curlKeaService = $curlKeaService; $this->logger = $logger; } /** * @Route("/ogdhcp/v1/status", name="getDhcpStatus", methods={"GET"}) * @OA\Get( * path="/ogdhcp/v1/status", * summary="Get ogDHCP status", * @OA\Response( * response=200, * description="Status retrieved successfully", * @OA\JsonContent( * type="object", * @OA\Property(property="disk_usage", type="object", * @OA\Property(property="total", type="string"), * @OA\Property(property="used", type="string"), * @OA\Property(property="available", type="string"), * @OA\Property(property="percentage", type="string") * ), * @OA\Property(property="default_oglive", type="string"), * @OA\Property(property="installed_oglives", type="array", @OA\Items(type="string")), * @OA\Property(property="services_status", type="object", * @OA\Property(property="dhcp_daemon", type="string"), * @OA\Property(property="nginx", type="string"), * @OA\Property(property="tftpboot", type="string") * ) * ) * ) * ) */ public function getDhcpStatus(): Response { try { // Obtener el uso de disco $diskUsageResult = $this->getDiskUsage(); if (!$diskUsageResult) { throw new \Exception('Failed to retrieve disk usage'); } // Obtener el estado de los servicios de ogDHCP $servicesStatusResult = $this->getServicesStatus(); if (!$servicesStatusResult) { throw new \Exception('Failed to retrieve services status'); } // Intentar obtener las subredes, pero si falla devolver un array vacío $subnetsResult = []; try { $subnetsResult = $this->getSubnetsService(); } catch (\Exception $e) { // Si ocurre un error, simplemente dejar $subnetsResult vacío $subnetsResult = []; } // Componer la respuesta $response = [ 'disk_usage' => $diskUsageResult, 'subnets' => $subnetsResult, 'services_status' => $servicesStatusResult ]; return new JsonResponse(['success' => "Información obtenida con éxito", 'message' => $response], Response::HTTP_OK); } catch (\Exception $e) { // Capturar la excepción y devolver el mensaje de error return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR); } } private function getDiskUsage(): array { // Simular la salida del comando df para obtener el uso del disco $output = shell_exec("df -h /opt/ogdhcp | tail -1 | awk '{print $2, $3, $4, $5}'"); if (!$output) { $this->logger->error("Failed to execute disk usage command"); return null; } list($total, $used, $available, $percentage) = explode(' ', $output); return [ 'total' => trim($total), 'used' => trim($used), 'available' => trim($available), 'percentage' => trim($percentage), ]; } private function getServicesStatus(): array { $services = [ 'kea-dhcp4-server' => $this->getServiceStatus('kea-dhcp4-server.service'), 'kea-ctrl-agent' => $this->getServiceStatus('kea-ctrl-agent.service'), 'nginx' => $this->getServiceStatus('nginx.service') ]; return $services; } private function getServiceStatus(string $service): string { // Ejecutar el comando systemctl para verificar el estado del servicio $output = shell_exec("systemctl is-active " . escapeshellarg($service)); // Si el comando retorna "active", el servicio está corriendo if (trim($output) === 'active') { return 'active'; } else { return 'inactive'; } } private function getSubnetsService(): ?array { try { // Ejecutar el comando para obtener la configuración $response = $this->curlKeaService->executeCurlCommand('config-get'); // Verificar si la respuesta es nula if (!$response) { throw new \Exception('Error: No se pudo acceder a la configuración de Kea. Respuesta nula.'); } // Verificar el código de resultado $result_code = $response[0]["result"]; if ($result_code != 0) { throw new \Exception("Error en la configuración de Kea: " . $response[0]["text"]); } // Verificar si el campo 'subnet4' está presente en la respuesta if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) { throw new \Exception("El campo 'subnet4' no está inicializado. Respuesta: " . json_encode($response[0]['arguments'])); } // Subredes encontradas, devolver resultado return $response[0]['arguments']['Dhcp4']['subnet4']; } catch (\Exception $e) { // Escalar la excepción para que sea gestionada por la función que llama throw new \Exception("Error al obtener las subredes: " . $e->getMessage()); } } /** * @OA\Schema( * schema="Subnet", * type="object", * @OA\Property(property="id", type="integer", description="The ID of the subnet"), * @OA\Property(property="subnet", type="string", description="The name of the subnet"), * @OA\Property(property="next-server", type="string", description="The next server in the subnet"), * @OA\Property(property="boot-file-name", type="string", description="The boot file name for the subnet"), * @OA\Property( * property="reservations", * type="array", * @OA\Items(type="object", description="The reservations in the subnet") * ) * ) */ /** * @OA\Get( * path="/ogdhcp/v1/subnets", * @OA\Response( * response=200, * description="Devuelve todas las subredes", * @OA\JsonContent( * type="object", * @OA\Property(property="success", type="string", example="Subredes obtenidas correctamente"), * @OA\Property(property="message", type="array", * @OA\Items( * type="object", * @OA\Property(property="id", type="integer", example=1), * @OA\Property(property="subnet", type="string", example="192.168.1.0/24"), * @OA\Property(property="pools", type="array", * @OA\Items( * type="object", * @OA\Property(property="pool", type="string", example="192.168.1.10-192.168.1.100") * ) * ), * @OA\Property(property="reservations", type="array", * @OA\Items( * type="object", * @OA\Property(property="ip-address", type="string", example="192.168.1.20"), * @OA\Property(property="hw-address", type="string", example="00:0c:29:6b:5e:71") * ) * ) * ) * ) * ) * ), * @OA\Response( * response=400, * description="Error al obtener las subredes", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string", example="Error al obtener las subredes") * ) * ) * ) * @Route("/ogdhcp/v1/subnets", methods={"GET"}) */ public function getSubnets(): JsonResponse { try { $response = $this->curlKeaService->executeCurlCommand('config-get'); if (!$response) { return new JsonResponse(['error' => 'Error: No se pudo acceder al archivo de configuración de Kea'], 400); } $result_code = $response[0]["result"]; if ($result_code == 0) { if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) { return new JsonResponse(['error' => 'El campo "subnet4" no está inicializado'], 400); } else { $subnets = $response[0]['arguments']['Dhcp4']['subnet4']; return new JsonResponse([ 'success' => 'Subredes obtenidas correctamente', 'message' => $subnets ], 200); } } else { return new JsonResponse(['error' => "Error en la configuración de Kea: " . $response[0]["text"]], 400); } } catch (Exception $e) { return new JsonResponse(['error' => "Error al obtener la configuración de Kea DHCP: " . $e->getMessage()], 400); } } /** * @OA\Post( * path="/ogdhcp/v1/subnets", * summary="Add a new DHCP subnet", * @OA\RequestBody( * description="JSON payload to create a new subnet", * 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", example="Subnet added successfully"), * @OA\Property(property="message", type="object", * @OA\Property(property="subnetId", type="integer", example=2), * @OA\Property(property="subnet", type="string", example="192.168.1.0/24"), * @OA\Property(property="nextServer", type="string", example="192.168.1.1"), * @OA\Property(property="bootFileName", type="string", example="pxelinux.0"), * @OA\Property(property="reservations", type="array", @OA\Items(type="object")) * ) * ) * ), * @OA\Response( * response=400, * description="Error occurred while adding the subnet", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string", example="Error: La subred con el nombre 'subnetName' ya existe.") * ) * ) * ) * @Route("/ogdhcp/v1/subnets", methods={"POST"}) */ public function addDhcpSubnet(Request $request): JsonResponse { try { $input = json_decode($request->getContent()); $subnetId = (int) htmlspecialchars($input->subnetId); $mask = htmlspecialchars($input->mask); $address = htmlspecialchars($input->address); $nextServer = htmlspecialchars($input->nextServer); $bootFileName = htmlspecialchars($input->bootFileName); } catch (Exception $e) { $response["message"] = $e->getMessage(); return new JsonResponse(['error' => $response], 400); } try { $response = $this->curlKeaService->executeCurlCommand('config-get'); $subnetName = $address . '/' . $this->curlKeaService->convertMaskToCIDR($mask); $newSubnet = [ "id" => $subnetId, "subnet" => $subnetName, "next-server" => $nextServer, "boot-file-name" => $bootFileName, "reservations" => [] ]; if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) { $response[0]['arguments']['Dhcp4']['subnet4'] = []; } $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); /** * @OA\Post( * path="/ogdhcp/v1/subnets", * summary="Add a new DHCP subnet", * @OA\RequestBody( * description="JSON payload to create a new subnet", * 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", example="Subnet added successfully"), * @OA\Property(property="message", type="object", * @OA\Property(property="subnetId", type="integer", example=2), * @OA\Property(property="subnet", type="string", example="192.168.1.0/24"), * @OA\Property(property="nextServer", type="string", example="192.168.1.1"), * @OA\Property(property="bootFileName", type="string", example="pxelinux.0"), * @OA\Property(property="reservations", type="array", @OA\Items(type="object")) * ) * ) * ), * @OA\Response( * response=400, * description="Error occurred while adding the subnet", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string", example="Error: La subred con el nombre 'subnetName' ya existe.") * ) * ), * @OA\Response( * response=400, * description="Error occurred while adding the subnet", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string", example="Error: La subred con el ID 'subnetId' ya existe.") * ) * ) * ) * @Route("/ogdhcp/v1/subnets", methods={"POST"}) */ // Controlar las salidas para los diferentes casos if ($subnetNameExists) { $responseError = "Error: La subred con el nombre '$subnetName' ya existe."; return new JsonResponse(['error' => $responseError], 400); } elseif ($subnetIdExists) { $responseError = "Error: La subred con el ID '$subnetId' ya existe."; return new JsonResponse(['error' => $responseError], 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) { $responseError = "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { $responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration); if ($responseWrite == false || $responseWrite[0]["result"] != 0) { $responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { $responseSuccess = "Configuración cargada correctamente"; return new JsonResponse(['success' => $responseSuccess], 200); } } } else { $responseError = "Error kea configuration invalid: " . $responseTest[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } } } catch (Exception $e) { $responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage(); return new JsonResponse(['error' => $responseError], 400); } } /** * @OA\Delete( * path="/ogdhcp/v1/subnets/{subnetId}", * 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", example="Subred eliminada correctamente") * ) * ), * @OA\Response( * response=400, * description="Error occurred", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string", example="Error: No hay subredes definidas") * ) * ), * @OA\Response( * response=404, * description="Subnet not found", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string", example="Error: La subred con el id '2' no existe") * ) * ), * @OA\Response( * response=500, * description="Error saving configuration in Kea DHCP", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string", example="Error al guardar la configuración en Kea DHCP: Unable to save configuration") * ) * ) * ) * @Route("/ogdhcp/v1/subnets/{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]); // Eliminar el campo 'hash' si existe if (isset($response[0]['arguments']['hash'])) { unset($response[0]['arguments']['hash']); } $response[0]['arguments']['Dhcp4']['subnet4'] = array_values($response[0]['arguments']['Dhcp4']['subnet4']); $array_encoded = json_encode($response[0]['arguments']); $configurationParsed = str_replace('\\', '', $array_encoded); $configuration = json_decode($configurationParsed); $responseTest = $this->curlKeaService->executeCurlCommand('config-test', $configuration); if ($responseTest[0]["result"] == 0) { $responseSet = $this->curlKeaService->executeCurlCommand('config-set', $configuration); if ($responseSet == false || $responseSet[0]["result"] != 0) { $responseError = "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { $responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration); if ($responseWrite == false || $responseWrite[0]["result"] != 0) { $responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { $responseSuccess = "Subred eliminada correctamente"; return new JsonResponse(['success' => $responseSuccess], 200); } } } else { $responseError = "Error kea configuration invalid: " . $responseTest[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } } } catch (Exception $e) { $responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage(); return new JsonResponse(['error' => $responseError], 400); } } /** * @Route("/ogdhcp/v1/subnets/{subnetId}", methods={"PUT"}) * @OA\Put( * path="/ogdhcp/v1/subnets/{subnetId}", * summary="Modify a DHCP subnet", * @OA\Parameter( * name="subnetId", * in="path", * description="ID of the subnet to modify", * required=true, * @OA\Schema( * type="integer" * ) * ), * @OA\RequestBody( * description="Data to modify the subnet", * required=true, * @OA\JsonContent( * type="object", * @OA\Property(property="mask", type="string"), * @OA\Property(property="address", type="string"), * @OA\Property(property="nextServer", type="string"), * @OA\Property(property="bootFileName", type="string") * ) * ), * @OA\Response( * response=200, * description="Subnet modified successfully", * @OA\JsonContent( * type="object", * @OA\Property(property="success", type="string") * ) * ), * @OA\Response( * response=400, * description="Error occurred", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string") * ) * ) * ) */ public function modifyDhcpSubnet(Request $request): JsonResponse { $subnetId = (int) $request->get('subnetId'); try { $input = json_decode($request->getContent()); $mask = htmlspecialchars($input->mask); $address = htmlspecialchars($input->address); $nextServer = htmlspecialchars($input->nextServer); $bootFileName = htmlspecialchars($input->bootFileName); } catch (Exception $e) { $response["message"] = $e->getMessage(); return new JsonResponse(['error' => $response], 400); } try { $response = $this->curlKeaService->executeCurlCommand('config-get'); $subnetName = $address . '/' . $this->curlKeaService->convertMaskToCIDR($mask); if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) { $responseError = "Error: No hay subredes definidas"; return new JsonResponse(['error' => $responseError], 400); } $subnetIndex = array_search($subnetId, array_column($response[0]['arguments']['Dhcp4']['subnet4'], 'id')); if ($subnetIndex === false) { $responseError = "Error: La subred con el id '$subnetId' no existe"; return new JsonResponse(['error' => $responseError], 400); } else { $response[0]['arguments']['Dhcp4']['subnet4'][$subnetIndex] = [ "id" => $subnetId, "subnet" => $subnetName, "next-server" => $nextServer, "boot-file-name" => $bootFileName, "reservations" => [] ]; $array_encoded = json_encode($response[0]['arguments']); $configurationParsed = str_replace('\\', '', $array_encoded); $configuration = json_decode($configurationParsed); $responseTest = $this->curlKeaService->executeCurlCommand('config-test', $configuration); if ($responseTest[0]["result"] == 0) { $responseSet = $this->curlKeaService->executeCurlCommand('config-set', $configuration); if ($responseSet == false || $responseSet[0]["result"] != 0) { $responseError = "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { $responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration); if ($responseWrite == false || $responseWrite[0]["result"] != 0) { $responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { $responseSuccess = "Subred modificada correctamente"; return new JsonResponse(['success' => $responseSuccess], 200); } } } else { $responseError = "Error kea configuration invalid: " . $responseTest[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } } } catch (Exception $e) { $responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage(); return new JsonResponse(['error' => $responseError], 400); } } /** * @OA\Get( * path="/ogdhcp/v1/subnets/{subnetId}/hosts", * summary="Get all hosts in a subnet", * @OA\Parameter( * name="subnetId", * in="path", * description="The ID of the subnet", * required=true, * @OA\Schema(type="integer") * ), * @OA\Response( * response=200, * description="List of hosts in the subnet", * ), * @OA\Response( * response=400, * description="Error occurred", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string") * ) * ), * @OA\Response( * response=500, * description="Server error", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string") * ) * ) * ) * @Route("/ogdhcp/v1/subnets/{subnetId}/hosts", methods={"GET"}) */ public function getHosts($subnetId): JsonResponse { try { $response = $this->curlKeaService->executeCurlCommand('config-get'); if (!$response) { $responseError = 'Error: No se pudo acceder al archivo dhcpd.conf'; return new JsonResponse(['error' => $responseError], 400); } else { $result_code = $response[0]["result"]; if ($result_code == 0) { if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) { $responseError = 'El campo \'subnet4\' no está inicializado'; return new JsonResponse(['error' => $responseError], 400); } else { $subnets = $response[0]['arguments']['Dhcp4']['subnet4']; foreach ($subnets as $subnet) { if ($subnet['id'] == $subnetId) { return new JsonResponse($subnet['reservations'], 200); } } $responseError = 'Error: La subred con el id \'' . $subnetId . '\' no existe.'; return new JsonResponse(['error' => $responseError], 400); } } else { $responseError = "Error kea configuration invalid: " . $response[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } } } catch (Exception $e) { $responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage(); return new JsonResponse(['error' => $responseError], 400); } } /** * @OA\Post( * path="/ogdhcp/v1/subnets/{subnetId}/hosts", * summary="Add a DHCP host to a subnet", * @OA\Parameter( * name="subnetId", * in="path", * description="ID of the subnet to add the host to", * required=true, * @OA\Schema( * type="integer" * ) * ), * @OA\RequestBody( * description="Data for the new host", * required=true, * @OA\JsonContent( * type="object", * @OA\Property(property="host", type="string", example="pc11"), * @OA\Property(property="macAddress", type="string", example="56:6f:c7:4f:00:4f"), * @OA\Property(property="address", type="string", example="172.30.4.11") * ) * ), * @OA\Response( * response=200, * description="Host added successfully", * @OA\JsonContent( * type="object", * @OA\Property(property="success", type="string") * ) * ), * @OA\Response( * response=400, * description="Error occurred", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string") * ) * ) * ) * @Route("/ogdhcp/v1/subnets/{subnetId}/hosts", methods={"POST"}) */ public function addDhcpHost(Request $request): JsonResponse { $subnetId = (int) $request->get('subnetId'); try { $input = json_decode($request->getContent()); $host = htmlspecialchars($input->host); $macAddress = htmlspecialchars($input->macAddress); $address = htmlspecialchars($input->address); } catch (Exception $e) { $response["message"] = $e->getMessage(); return new JsonResponse(['error' => $response], 400); } try { $response = $this->curlKeaService->executeCurlCommand('config-get'); $newHost = [ "hostname" => $host, "hw-address" => $macAddress, "ip-address" => $address ]; $subnetFound = false; foreach ($response[0]['arguments']['Dhcp4']['subnet4'] as &$subnet) { if ($subnet['id'] == $subnetId) { $subnetFound = true; if (!isset($subnet['reservations'])) { $subnet['reservations'] = []; } $exists = array_reduce($subnet['reservations'], function ($exists, $reservation) use ($host) { return $exists || ($reservation['hostname'] === $host); }); if ($exists) { $responseError = "Error: El host con el hostname '$host' ya existe en las reservaciones."; return new JsonResponse(['error' => $responseError], 400); } else { $subnet['reservations'][] = $newHost; break; } } } if (!$subnetFound) { $responseError = "Error: No se encontró la subnet con id '$subnetId'."; return new JsonResponse(['error' => $responseError], 400); } $array_encoded = json_encode($response[0]['arguments']); $configurationParsed = str_replace('\\', '', $array_encoded); $configuration = json_decode($configurationParsed); $responseTest = $this->curlKeaService->executeCurlCommand('config-test', $configuration); if ($responseTest[0]["result"] == 0) { $responseSet = $this->curlKeaService->executeCurlCommand('config-set', $configuration); if ($responseSet == false || $responseSet[0]["result"] != 0) { $responseError = "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { $responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration); if ($responseWrite == false || $responseWrite[0]["result"] != 0) { $responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { $responseSuccess = "Configuración cargada correctamente"; return new JsonResponse(['success' => $responseSuccess], 200); } } } else { $responseError = "Error kea configuration invalid: " . $responseTest[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } } catch (Exception $e) { $responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage(); return new JsonResponse(['error' => $responseError], 400); } } /** * @OA\Delete( * path="/ogdhcp/v1/subnets/{subnetId}/hosts", * summary="Delete a DHCP host from a specific subnet", * @OA\Parameter( * name="subnetId", * in="path", * description="The ID of the subnet", * required=true, * @OA\Schema(type="integer") * ), * @OA\RequestBody( * description="Data for the host to delete", * required=true, * @OA\JsonContent( * type="object", * @OA\Property(property="macAddress", type="string", example="56:6f:c7:4f:00:4f") * ) * ), * @OA\Response( * response=200, * description="Host deleted successfully", * @OA\JsonContent( * type="object", * @OA\Property(property="success", type="string") * ) * ), * @OA\Response( * response=404, * description="Host or subnet not found", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string") * ) * ), * @OA\Response( * response=400, * description="Error occurred", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string") * ) * ) * ) * @Route("/ogdhcp/v1/subnets/{subnetId}/hosts", methods={"DELETE"}) */ public function deleteDhcpHost(Request $request, $subnetId): JsonResponse { try { $input = json_decode($request->getContent()); $macAddress = htmlspecialchars($input->macAddress); } catch (Exception $e) { return new JsonResponse(['error' => $e->getMessage()], 400); } try { $response = $this->curlKeaService->executeCurlCommand('config-get'); $subnetFound = false; $hostFound = 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 ($reservation['hw-address'] === $macAddress) { unset($subnet['reservations'][$key]); $subnet['reservations'] = array_values($subnet['reservations']); $hostFound = true; break; } } } } if (!$subnetFound) { return new JsonResponse(['error' => "Error: La subred con el id '$subnetId' no existe."], 404); } if (!$hostFound) { return new JsonResponse(['error' => "Error: El host con la MAC '$macAddress' no existe en las reservaciones."], 404); } // 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 { return new JsonResponse(['success' => "Host eliminado correctamente"], 200); } } } else { return new JsonResponse(['error' => "Error en la configuración de Kea: " . $responseTest[0]["text"]], 400); } } catch (Exception $e) { return new JsonResponse(['error' => $e->getMessage()], 400); } } /** * @OA\Put( * path="/ogdhcp/v1/subnets/{subnetId}/hosts", * summary="Update a DHCP host", * @OA\Parameter( * name="subnetId", * in="path", * description="The ID of the subnet", * required=true, * @OA\Schema(type="integer") * ), * @OA\RequestBody( * description="Data for the host to update", * required=true, * @OA\JsonContent( * type="object", * @OA\Property(property="oldMacAddress", type="string", example="56:6f:c7:4f:00:4f", description="Old MAC address of the host to update"), * @OA\Property(property="macAddress", type="string", example="56:6f:c7:4f:01:01", description="New MAC address"), * @OA\Property(property="address", type="string", example="192.168.1.11", description="New IP address"), * @OA\Property(property="hostname", type="string", example="PC11", description="New or existing hostname") * ) * ), * @OA\Response( * response=200, * description="Host updated successfully", * @OA\JsonContent( * type="object", * @OA\Property(property="success", type="string", example="Host updated successfully"), * @OA\Property(property="message", type="object", * @OA\Property(property="hostname", type="string", example="PC11"), * @OA\Property(property="macAddress", type="string", example="56:6f:c7:4f:01:01"), * @OA\Property(property="ipAddress", type="string", example="192.168.1.12") * ) * ) * ), * @OA\Response( * response=400, * description="Error occurred", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string", example="Invalid input data") * ) * ), * @OA\Response( * response=404, * description="Host not found", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string", example="Error: The host with MAC '56:6f:c7:4f:00:4f' was not found") * ) * ), * @OA\Response( * response=500, * description="Server error", * @OA\JsonContent( * type="object", * @OA\Property(property="error", type="string", example="Internal server error") * ) * ) * ) * @Route("/ogdhcp/v1/subnets/{subnetId}/hosts", methods={"PUT"}) */ public function updateDhcpHost(Request $request, $subnetId): JsonResponse { try { $input = json_decode($request->getContent()); $host = htmlspecialchars($input->host); $oldMacAddress = htmlspecialchars($input->oldMacAddress); $macAddress = htmlspecialchars($input->macAddress); $address = htmlspecialchars($input->address); } catch (Exception $e) { $response["message"] = $e->getMessage(); return new JsonResponse(['error' => $response], 400); } try { // Ejecutar el comando para obtener la configuración actual $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) { $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'); // Eliminar el campo 'hash' si existe if (isset($response[0]['arguments']['hash'])) { unset($response[0]['arguments']['hash']); } // Preparar la configuración modificada $array_encoded = json_encode($response[0]['arguments']); $configurationParsed = str_replace('\\', '', $array_encoded); $configuration = json_decode($configurationParsed); // Test de la configuración $responseTest = $this->curlKeaService->executeCurlCommand('config-test', $configuration); if ($responseTest[0]["result"] == 0) { // Guardar la configuración $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 { // Escribir la configuración en disco $responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration); if ($responseWrite == false || $responseWrite[0]["result"] != 0) { $responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { return new JsonResponse(['success' => "Host actualizado correctamente"], 200); } } } else { $responseError = "Error en la configuración de Kea: " . $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], 404); } elseif (!$hostFound) { $responseError = "Error: El host con la MAC " . $oldMacAddress . " no existe en las reservaciones."; return new JsonResponse(['error' => $responseError], 404); } } catch (Exception $e) { $responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage(); return new JsonResponse(['error' => $responseError], 400); } } public function restoreDhcpConfiguration(): JsonResponse { $backup_dir = '/opt/opengnsys/etc/kea/backup'; try { $backup_files = glob($backup_dir . '/*.conf'); if (empty($backup_files)) { $response = "No se encontraron archivos de backup"; return new JsonResponse(['error' => $response], 400); } else { usort($backup_files, function ($a, $b) { return filemtime($b) - filemtime($a); }); $backup_file = reset($backup_files); $config = file_get_contents($backup_file); $configuration = json_decode($config); $test_command = 'config-test'; $test_output = $this->curlKeaService->executeCurlCommand($test_command, $configuration); if ($test_output == false || $test_output[0]["result"] != 0) { $responseError = "Error al comprobar la configuración de Kea: " . $test_output[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { $set_command = 'config-set'; $set_output = $this->curlKeaService->executeCurlCommand($set_command, $configuration, false); if ($set_output == false || $set_output[0]["result"] != 0) { $responseError = "Error al guardar la última configuración de Kea: " . $set_output[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { unlink($backup_file); $responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration); if ($responseWrite == false || $responseWrite[0]["result"] != 0) { $responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"]; return new JsonResponse(['error' => $responseError], 400); } else { $responseSuccess = "Configuración cargada correctamente"; return new JsonResponse(['success' => $responseSuccess], 200); } } } } } catch (Exception $e) { $responseError = "Error al restaurar la configuración: " . $e->getMessage(); return new JsonResponse(['error' => $responseError], 400); } } }