ogboot_symfony #3

Merged
lgromero merged 36 commits from ogboot_symfony into main 2024-07-15 11:24:43 +02:00
23 changed files with 4025 additions and 0 deletions

40
.env 100644
View File

@ -0,0 +1,40 @@
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
# https://symfony.com/doc/current/configuration/secrets.html
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=d423d1302b974417d415b10bcde25767
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8&charset=utf8mb4"
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=15&charset=utf8"
###< doctrine/doctrine-bundle ###
###> symfony/messenger ###
# Choose one of the transports below
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
###< symfony/messenger ###
###> symfony/mailer ###
# MAILER_DSN=null://null
###< symfony/mailer ###

20
.gitignore vendored 100644
View File

@ -0,0 +1,20 @@
###> symfony/framework-bundle ###
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/var/
/vendor/
###< symfony/framework-bundle ###
###> phpunit/phpunit ###
/phpunit.xml
.phpunit.result.cache
###< phpunit/phpunit ###
###> symfony/phpunit-bridge ###
.phpunit.result.cache
/phpunit.xml
###< symfony/phpunit-bridge ###

589
README.md
View File

@ -1,3 +1,592 @@
## Ogboot
Ogboot es una implementación independiente que facilita la funcionalidad de arranque remoto (PXE) en entornos gestionados por Opengnsys. Este componente permite la carga remota de sistemas operativos y otros archivos esenciales durante el proceso de arranque de las estaciones de trabajo.
## API de Ogboot
La API de Ogboot proporciona una interfaz para facilitar el proceso de inicialización remota de sistemas operativos en entornos administrados por OpenGnsys. Ogboot permite la gestión eficiente de los archivos de arranque tanto de particiones locales como de sistemas operativos remotos.
El presente documento detalla los endpoints del API con sus respectivos parámetros de entrada así como las acciones que llevan a cabo
### Tabla de Contenido
1. [Obtener configuración de ogboot](#obtener-configuración-de-ogboot) - `GET /ogboot/v1/config`
2. [Obtener datos de rendimiento](#obtener-datos-de-rendimiento) - `GET /ogboot/v1/status`
3. [Mostrar información de todos los clientes ogLive instalados](#mostrar-información-de-todos-los-clientes-oglive-instalados) - `GET /ogboot/v1/oglives`
4. [Mostrar información de un cliente ogLive instalado](#mostrar-información-de-todos-los-clientes-oglive-instalados) - `GET /ogboot/v1/oglives/{Index|Dir}`
5. [Mostrar información del cliente ogLive predeterminado](#mostrar-información-del-cliente-oglive-predeterminado) - `GET /ogboot/v1/oglives/default`
6. [Cambiar ogLive predeterminado](#cambiar-oglive-predeterminado) - `POST /ogboot/v1/oglives/default/{Index}`
7. [Instalar nuevo cliente ogLive desde imagen descargada](#instalar-nuevo-cliente-oglive-desde-imagen-descargada) - `POST /ogboot/v1/oglive/{iso}`
8. [Desinstalar cliente ogLive y eliminar imagen](#desinstalar-cliente-oglive-y-eliminar-imagen) - `DELETE /ogboot/v1/oglives/{iso}`
9. [Regenerar archivo de información de los ogLive](#regenerar-archivo-de-información-de-los-oglive) - `PUT /ogboot/v1/oglives`
10. [Mostrar menú de descarga de imagen de ogLive](#mostrar-menú-de-descarga-de-imagen-de-oglive) - `GET /ogboot/v1/images/download`
11. [Obtener todos los archivos de arranque](#obtener-todos-los-archivos-de-arranque) - `GET /ogboot/v1/pxes`
12. [Obtener archivo de arranque](#obtener-archivo-de-arranque) - `GET /ogboot/v1/pxes/{mac}`
13. [Crear archivo de arranque](#crear-archivo-de-arranque) - `POST /ogboot/v1/pxes`
14. [Eliminar archivo de arranque](#eliminar-archivo-de-arranque) - `DELETE /ogboot/v1/pxes`
15. [Obtener todas las plantillas](#obtener-todas-las-plantillas) - `GET /ogboot/v1/pxe-templates`
16. [Obtener contenido de la plantilla](#obtener-contenido-de-la-plantilla) - `GET /ogboot/v1/pxe-templates/{nombre}`
17. [Crear plantilla](#crear-plantilla) - `POST /ogboot/v1/pxe-templates`
18. [Regenerar plantilla](#regenerar-plantilla) - `PUT /ogboot/v1/pxe-templates`
### Obtener Configuración de ogboot
Devuelve la configuración actual del ogboot.
**URL:** `/ogboot/v1/config`
**Método HTTP:** GET
**Ejemplo de Solicitud:**
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/config
```
**Respuestas:**
- **Código 200 OK:** La configuración del ogboot se obtuvo exitosamente.
- **Contenido:** Configuración del ogboot en formato JSON.
```json
{
"config-file": "/opt/opengnsys/etc/ogliveinfo.json",
"download-url": "https://opengnsys.es/trac/downloads",
"download-dir": "/opt/opengnsys/lib",
"install-dir": "/opt/opengnsys/tftpboot",
"default-name": "ogLive",
"min-release": "r20190601"
}
```
- **config-file**: Ruta del archivo de configuración que usa oglivecli para guardar los oglives instalados.
- **download-url**: URL base desde la cual se descargan las imágenes de oglive.
- **download-dir**: Ruta del directorio en el cual se almacenan las imágenes de oglive descargadas
- **install-dir**: La ruta del directorio donde se instalan las imágenes de oglive
- **default-name**: Nombre predeterminado utilizado para los clientes ogLive.
- **min-release**: La versión mínima recomendada para la instalación de imágenes oglives.
- **Código 400 Bad Request:** La solicitud es incorrecta. La configuración del ogboot no se ha obtenido correctamente.
### Obtener estado de ogboot
Devuelve la consistencia, errores de incompatibilidad y de configuración
**URL:** `/ogboot/v1/status`
**Método HTTP:** GET
**Ejemplo de Solicitud:**
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/status
```
**Respuestas:**
- **Código 200 OK:** El status de ogboot se obtuvo exitosamente.
- **Contenido:**
```
Some installed ogLive aren't fully compatible: , , ogLive-3.19.0-i386-r4795
Problems detected:
```
- **Código 400 Bad Request:** La solicitud es incorrecta. La status de ogboot no se ha obtenido correctamente.
### Mostrar Información de Todos los Clientes ogLive Instalados
Muestra información en formato JSON sobre todos los clientes ogLive instalados.
**URL:** `/ogboot/v1/oglives`
**Método HTTP:** GET
**Ejemplo de Solicitud:**
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/clients/oglives/
[
{
"distribution": "focal",
"kernel": "5.11.0-22-generic",
"architecture": "amd64",
"revision": "r20210413",
"directory": "ogLive-5.11.0-r20210413",
"iso": "ogLive-focal-5.11.0-22-generic-amd64-r20210413.992ebb9.iso"
},
{
"distribution": "focal",
"kernel": "5.13.0-27-beta",
"architecture": "amd64",
"revision": "r20210706",
"directory": "ogLive-5.13.0-r20210706",
"iso": "ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f.iso"
}
]
```
- **distribution**: Distribución del sistema operativo de la imagen ogLive
- **kernel**: Versión del kernel del sistema operativo utilizado por la imagen ogLive
- **architecture**: Arquitectura del hardware de la imagen ogLive
- **revision**: Versión de la imagen ogLive
- **directory**: Directorio donde se encuentra instalado el cliente ogLive en el sistema.
- **iso**: Nombre del archivo ISO utilizado para instalar el cliente ogLive.
**Respuestas:**
- **Código 200 OK:** La información sobre todos los clientes ogLive instalados se obtuvo exitosamente.
- **Contenido:** Información sobre todos los clientes ogLive instalados en formato JSON.
### Mostrar Información de un Cliente ogLive Instalado
Muestra información en formato JSON sobre un cliente ogLive instalado específico.
**URL:** `/ogboot/v1/oglives/{Index}`
**Método HTTP:** GET
**Parámetros de la URL:**
- `{Index}`: El índice o directorio del cliente ogLive instalado.
**Ejemplo de Solicitud:**
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/clients/oglives/1
{
"distribution": "focal",
"kernel": "5.11.0-22-generic",
"architecture": "amd64",
"revision": "r20210413",
"directory": "ogLive-5.11.0-r20210413",
"iso": "ogLive-focal-5.11.0-22-generic-amd64-r20210413.992ebb9.iso"
}
```
**Respuestas:**
- **Código 200 OK:** La información sobre el cliente ogLive instalado se obtuvo exitosamente.
- **Contenido:** Información sobre el cliente ogLive instalado en formato JSON.
- **Código 404 Not Found:** No se encontró ningún cliente ogLive instalado con el índice o directorio proporcionado.
### Mostrar Información del Cliente ogLive Predeterminado
Muestra información en formato JSON sobre el cliente ogLive predeterminado.
**URL:** `/ogboot/v1/oglives/default`
**Método HTTP:** GET
**Ejemplo de Solicitud:**
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/clients/oglives/default
{
"distribution": "focal",
"kernel": "5.11.0-22-generic",
"architecture": "amd64",
"revision": "r20210413",
"directory": "ogLive-5.11.0-r20210413",
"iso": "ogLive-focal-5.11.0-22-generic-amd64-r20210413.992ebb9.iso"
}
```
**Respuestas:**
- **Código 200 OK:** La información sobre el cliente ogLive predeterminado se obtuvo exitosamente.
- **Contenido:** Información sobre el cliente ogLive predeterminado en formato JSON.
### Cambiar ogLive Predeterminado
Establece un nuevo cliente ogLive como predeterminado utilizando su índice.
**URL:** `/ogboot/v1/oglives/default`
**Método HTTP:** POST
**Parámetros de la URL:**
- `{Index}`: El índice del cliente ogLive que se establecerá como predeterminado.
**Ejemplo de Solicitud:**
```bash
curl -X POST -H "Authorization: $API_KEY" http://example.com/ogboot/v1/clients/oglives/default/1
```
**Respuestas:**
- **Código 200 OK:** El cliente ogLive se estableció como predeterminado exitosamente.
- **Código 404 Not Found:** No se encontró ningún cliente ogLive con el índice proporcionado.
### Descargar e Instalar Nuevo Cliente ogLive desde Imagen Descargada
Descarga y luego instala un nuevo cliente ogLive utilizando la imagen descargada, especificada por su nombre de archivo ISO en el parámetro de entrada.
**URL:** `/ogboot/v1/oglive`
**Método HTTP:** POST
**Parámetros de Entrada:**
- `ISO: Nombre de la ISO que se desea descargar e instalar
**Ejemplo de Solicitud:**
```bash
curl -X POST -H "Authorization: $API_KEY" -d "ISO=ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f.iso" http://example.com/ogboot/v1/oglive
```
**Respuestas:**
- **Código 200 OK:** La descarga e instalación del nuevo cliente ogLive desde la imagen descargada fue exitosa.
- **Código 404 Not Found:** No se encontró ninguna imagen ogLive con el índice o nombre de archivo ISO proporcionado.
### Desinstalar Cliente ogLive
Desinstala un cliente ogLive específico y elimina su imagen asociada.
**URL:** `/ogboot/v1/oglives/{Index}`
**Método HTTP:** DELETE
**Parámetros de la URL:**
- `{Index}`: El índice deL archivo ISO del cliente ogLive que se desinstalará y eliminará.
**Ejemplo de Solicitud:**
```bash
curl -X DELETE -H "Authorization: $API_KEY" http://example.com/ogboot/v1/oglives/1
```
**Respuestas:**
- **Código 200 OK:** El cliente ogLive se desinstaló y su imagen asociada se eliminó correctamente.
- **Código 404 Not Found:** No se encontró ningún cliente ogLive con el índice o nombre de archivo ISO proporcionado.
### Regenerar Archivo de Información de los ogLive
Regenera el archivo de información de los clientes ogLive instalados.
**URL:** `/ogboot/v1/oglives`
**Método HTTP:** PUT
**Ejemplo de Solicitud:**
```bash
curl -X PUT -H "Authorization: $API_KEY" http://example.com/ogboot/v1/oglives
```
**Respuestas:**
- **Código 200 OK:** El archivo de información de los clientes ogLive se regeneró correctamente.
- **Código 500 Internal Server Error:** Ocurrió un error al intentar regenerar el archivo de información de los clientes ogLive.
### Mostrar Menú de Descarga de Imagen de ogLive
Muestra un menú con opciones para descargar imágenes de ogLive disponibles.
**URL:** `/ogboot/v1/images/download`
**Método HTTP:** GET
**Ejemplo de Solicitud:**
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/images/download
```
**Respuestas:**
- **Código 200 OK:** El menú de descarga de imágenes de ogLive se obtuvo exitosamente.
- **Contenido:** Menú de descarga de imágenes de ogLive en formato JSON.
### Obtener Todos los Archivos de Arranque
Obtiene una lista de todos los archivos de arranque disponibles.
**URL:** `/ogboot/v1/pxes`
**Método HTTP:** GET
**Ejemplo de Solicitud:**
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/pxes
{
"boot_files": [
"01-00:50:56:22:11:11",
"01-00:50:56:22:11:12"
]
}
```
**Respuestas:**
- **Código 200 OK:** La lista de todos los archivos de arranque se obtuvo exitosamente.
- **Contenido:** Lista de archivos de arranque en formato JSON.
- **Código 500 Internal Server Error:** Ocurrió un error al intentar obtener la lista de todos los archivos de arranque disponibles.
### Obtener Configuración de Arranque
Obtiene el contenido del archivo de configuración de arranque específico para un cliente utilizando su dirección MAC.
**URL:** `/ogboot/v1/pxes/{mac}`
**Método HTTP:** GET
**Parámetros de la URL:**
- `{mac}`: La dirección MAC del cliente cuyo archivo de configuración de arranque se desea obtener.
**Ejemplo de Solicitud:**
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/clients/pxes/00:11:22:33:44:55
#!ipxe
set timeout 0
set timeout-style hidden
set ISODIR ogLive
set default 0
set kernelargs ro boot=oginit quiet splash irqpoll acpi=on og2nd=sqfs ogprotocol=smb ogactiveadmin=true ogdebug=true ogtmpfs=15 oglivedir=${ISODIR} LANG=es_ES.UTF-8 ip=192.168.2.11:192.168.2.1:192.168.2.1:255.255.255.0:pc11:eth0:none group=Aula_virtual ogrepo=192.168.2.1 oglive=192.168.2.1 oglog=192.168.2.1 ogshare=192.168.2.1 ogprof=false vga=788
set kernelargs ro boot=oginit quiet splash irqpoll acpi=on og2nd=sqfs ogprotocol=smb ogactiveadmin=true ogdebug=true ogtmpfs=15 oglivedir=$ISODIR LANG=es_ES.UTF-8 ip=192.168.2.11:192.168.2.1:192.168.2.1:255.255.255.0:pc11:eth0:none group=Aula_virtual ogrepo=192.168.2.1 oglive=192.168.2.1 oglog=192.168.2.1 ogshare=192.168.2.1 ogprof=false vga=788
kernel tftp://172.17.8.71/ogLive/ogvmlinuz ${kernelargs}
initrd tftp://172.17.8.71/ogLive/oginitrd.img
boot
```
**Respuestas:**
- **Código 200 OK:** El archivo de arranque para la dirección MAC especificada se encontró y se devuelve correctamente.
- **Contenido:** El archivo de arranque en formato adecuado para su uso en el cliente correspondiente.
- **Código 404 Not Found:** No se encontró ningún archivo de arranque para la dirección MAC especificada.
### Crear Archivo de Arranque
Crea un nuevo archivo de arranque utilizando los parámetros proporcionados.
**URL:** `/ogboot/v1/pxes`
**Método HTTP:** POST
**Cuerpo de la Solicitud:**
- Datos necesarios para la creación del archivo de arranque, como el nombre, la configuración, etc.
**Ejemplo de Solicitud:**
```bash
curl -X POST -H "Authorization: $API_KEY" -d '{"mac": "00:50:56:22:11:12", "config": "#!ipxe\nset timeout 0\nset timeout-style hidden\n\nset ISODIR ogLive\nset default 0\nset kernelargs ro boot=oginit quiet splash irqpoll acpi=on og2nd=sqfs ogprotocol=smb ogactiveadmin=true ogdebug=true ogtmpfs=15 oglivedir=${ISODIR} LANG=es_ES.UTF-8 ip=192.168.2.11:192.168.2.1:192.168.2.1:255.255.255.0:pc11:eth0:none group=Aula_virtual ogrepo=192.168.2.1 oglive=192.168.2.1 oglog=192.168.2.1 ogshare=192.168.2.1 ogprof=false vga=788\n\nset kernelargs ro boot=oginit quiet splash irqpoll acpi=on og2nd=sqfs ogprotocol=smb ogactiveadmin=true ogdebug=true ogtmpfs=15 oglivedir=$ISODIR LANG=es_ES.UTF-8 ip=192.168.2.11:192.168.2.1:192.168.2.1:255.255.255.0:pc11:eth0:none group=Aula_virtual ogrepo=192.168.2.1 oglive=192.168.2.1 oglog=192.168.2.1 ogshare=192.168.2.1 ogprof=false vga=788\nkernel tftp://172.17.8.71/ogLive/ogvmlinuz ${kernelargs}\ninitrd tftp://172.17.8.71/ogLive/oginitrd.img\nboot"}' http://example.com/ogboot/v1/pxes
```
**Respuestas:**
- **Código 200 OK:** El archivo de arranque se creó exitosamente.
- **Código 400 Bad Request:** La solicitud no pudo ser procesada debido a un error en los datos proporcionados en el cuerpo de la solicitud.
- **Código 500 Internal Server Error:** Ocurrió un error al subir el archivo de arranque.
### Eliminar Archivo de Arranque
Elimina un archivo de arranque específico utilizando su identificador único.
**URL:** `/ogboot/v1/pxes/{MAC}`
**Método HTTP:** DELETE
**Parámetros de la URL:**
- `{mac}`: La dirección MAC del cliente cuyo archivo de arranque se desea obtener.
**Ejemplo de Solicitud:**
```bash
curl -X DELETE -H "Authorization: $API_KEY" http://example.com/ogboot/v1/clients/pxes/00:11:22:33:44:55
```
**Respuestas:**
- **Código 200 OK:** El archivo de arranque se eliminó correctamente.
- **Código 404 Not Found:** No se encontró ningún archivo de arranque con el identificador único especificado.
- **Código 500 Internal Server Error:** Ocurrió un error al eliminar el archivo de arranque.
### Actualizar Repositorio de Arranque
Actualiza el repositorio de archivos de arranque con los archivos modificados.
**URL:** `/ogboot/v1/pxes`
**Método HTTP:** PUT
**Cuerpo de la Solicitud:**
- Fichero en json con la configuración de arranque de la máquina
**Ejemplo de Solicitud:**
```bash
curl -X PUT -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"mac": "00:50:56:22:11:12", "config": "#!ipxe\nset timeout 0\nset timeout-style hidden\n\nset ISODIR ogLive\nset default 0\nset kernelargs ro boot=oginit quiet splash irqpoll acpi=on og2nd=sqfs ogprotocol=smb ogactiveadmin=true ogdebug=true ogtmpfs=15 oglivedir=${ISODIR} LANG=es_ES.UTF-8 ip=192.168.2.11:192.168.2.1:192.168.2.1:255.255.255.0:pc11:eth0:none group=Aula_virtual ogrepo=192.168.2.1 oglive=192.168.2.1 oglog=192.168.2.1 ogshare=192.168.2.1 ogprof=false vga=788\n\nset kernelargs ro boot=oginit quiet splash irqpoll acpi=on og2nd=sqfs ogprotocol=smb ogactiveadmin=true ogdebug=true ogtmpfs=15 oglivedir=$ISODIR LANG=es_ES.UTF-8 ip=192.168.2.11:192.168.2.1:192.168.2.1:255.255.255.0:pc11:eth0:none group=Aula_virtual ogrepo=192.168.2.1 oglive=192.168.2.1 oglog=192.168.2.1 ogshare=192.168.2.1 ogprof=false vga=788\nkernel tftp://172.17.8.71/ogLive/ogvmlinuz ${kernelargs}\ninitrd tftp://172.17.8.71/ogLive/oginitrd.img\nboot"}' http://example.com/ogboot/v1/pxes
```
**Respuestas:**
- **Código 200 OK:** El repositorio de arranque se actualizó exitosamente con los archivos modificados.
- **Código 400 Bad Request:** La solicitud no pudo ser procesada debido a un error en los datos proporcionados en el cuerpo de la solicitud.
- **Código 500 Internal Server Error:** Ocurrió un error al actualizar el archivo de arranque.
### Obtener Todas las Plantillas
Obtiene una lista de todas las plantillas de arranque disponibles.
**URL:** `/ogboot/v1/pxe-templates`
**Método HTTP:** GET
**Ejemplo de Solicitud:**
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/pxe-templates
```
**Respuestas:**
- **Código 200 OK:** La lista de todas las plantillas de arranque se obtuvo exitosamente.
- **Contenido:** Lista de plantillas de arranque en formato JSON.
- **Código 500 Internal Server Error:** Ocurrió un error al obtener las plantillas de arranque.
### Obtener Contenido de la Plantilla
Obtiene el contenido de una plantilla de arranque específica utilizando su nombre.
**URL:** `/ogboot/v1/pxe-templates/{nombre}`
**Método HTTP:** GET
**Parámetros de la URL:**
- `{nombre}`: El nombre de la plantilla de arranque cuyo contenido se desea obtener.
**Ejemplo de Solicitud:**
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/pxe-templates/template1
#!ipxe
set timeout 0
set timeout-style hidden
set ISODIR ogLive
set default 0
set kernelargs ro boot=oginit quiet splash irqpoll acpi=on og2nd=sqfs ogprotocol=smb ogactiveadmin=true ogdebug=true ogtmpfs=15 oglivedir=${ISODIR} LANG=es_ES.UTF-8 ip=192.168.1.100:192.168.1.1:192.168.1.1:255.255.255.0:pc01:eth0:none group=Aula_virtual ogrepo=192.168.1.10 oglive=192.168.1.10 oglog=192.168.1.10 ogshare=192.168.1.10 ogprof=false vga=788
time kernel tftp://172.17.8.71/ogLive/ogvmlinuz ${kernelargs}
time initrd tftp://172.17.8.71/ogLive/oginitrd.img
boot
```
**Respuestas:**
- **Código 200 OK:** El contenido de la plantilla de arranque se obtuvo exitosamente.
- **Contenido:** Contenido de la plantilla de arranque en formato adecuado para su uso.
- **Código 400 Bad Request:** La solicitud no pudo ser procesada debido a un error en los datos proporcionados en el cuerpo de la solicitud.
- **Código 500 Internal Server Error:** Ocurrió un error al obtener la plantilla de arranque.
---
### Crear Plantilla
Crea una nueva plantilla de arranque utilizando los datos proporcionados.
**URL:** `/ogboot/v1/pxe-templates`
**Método HTTP:** POST
**Cuerpo de la Solicitud:**
- {name_template}: Nombre de la plantilla
- {ip}: Dirección IP del cliente.
- {gateway}: Puerta de enlace predeterminada.
- {netmask}: Máscara de red.
- {hostname}: Nombre del host del cliente.
- {interface}: Interfaz de red utilizada por el cliente.
- {group}: Grupo al que pertenece el cliente.
- {ogrepo}: Dirección IP del repositorio de ogLive.
- {oglive}: Dirección IP del servidor ogLive.
- {oglog}: Dirección IP del servidor de logs.
- {ogshare}: Dirección IP del servidor de archivos compartidos.
- {ogprof}: Valor booleano que indica si el perfil del cliente está habilitado o deshabilitado.
- {vga}: Modo VGA utilizado para la interfaz de usuario.
- {tftp_server_ip}: Dirección IP del servidor TFTP desde el cual se descargarán los archivos necesarios para el arranque del sistema
**Ejemplo de Solicitud:**
```bash
curl -X POST -H "Authorization: $API_KEY" -H "Content-Type: application/json" -d '{"name_template":"template1","ip": "192.168.1.100", "gateway": "192.168.1.1", "netmask": "255.255.255.0", "hostname": "pc01", "interface": "eth0", "group": "Aula_virtual", "ogrepo": "192.168.1.10", "oglive": "192.168.1.10", "oglog": "192.168.1.10", "ogshare": "192.168.1.10", "ogprof": false, "vga": 788, "tftp_server_ip": "172.17.8.71"}' http://example.com/ogboot/v1/pxe-templates
#!ipxe
set timeout 0
set timeout-style hidden
set ISODIR ogLive
set default 0
set kernelargs ro boot=oginit quiet splash irqpoll acpi=on og2nd=sqfs ogprotocol=smb ogactiveadmin=true ogdebug=true ogtmpfs=15 oglivedir=${ISODIR} LANG=es_ES.UTF-8 ip=192.168.1.100:192.168.1.1:192.168.1.1:255.255.255.0:pc01:eth0:none group=Aula_virtual ogrepo=192.168.1.10 oglive=192.168.1.10 oglog=192.168.1.10 ogshare=192.168.1.10 ogprof=false vga=788
time kernel tftp://172.17.8.71/ogLive/ogvmlinuz ${kernelargs}
time initrd tftp://172.17.8.71/ogLive/oginitrd.img
boot
```
**Respuestas:**
- **Código 200 OK:** La plantilla de arranque se creó exitosamente.
- **Contenido:** Plantilla generada a partir de los parámetros pasados en la petición.
- **Código 400 Bad Request:** La solicitud no pudo ser procesada debido a un error en los datos proporcionados en el cuerpo de la solicitud.
- **Código 500 Internal Server Error:** Ocurrió un error al crear la plantilla de arranque.
### Regenerar Plantilla
Regenera el contenido de una plantilla de arranque específica utilizando su nombre.
**URL:** `/ogboot/v1/pxe-templates/{nombre}`
**Método HTTP:** PUT
**Parámetros de la URL:**
- `{nombre}`: El nombre de la plantilla de arranque que se desea regenerar.
**Ejemplo de Solicitud:**
```bash
curl -X PUT -H "Authorization: $API_KEY" http://example.com/ogboot/v1/pxe-templates/template1
```
**Respuestas:**
- **Código 200 OK:** El contenido de la plantilla de arranque se regeneró exitosamente.
- **Código 404 Not Found:** No se encontró ninguna plantilla de arranque con el nombre especificado.
- **Código 500 Internal Server Error:** Ocurrió un error al regenerar la plantilla de arranque.
---
### Eliminar Plantilla
Elimina una plantilla de arranque específica utilizando su nombre.
**URL:** `/ogboot/v1/pxe-templates/{nombre}`
**Método HTTP:** DELETE
**Parámetros de la URL:**
- `{nombre}`: El nombre de la plantilla de arranque que se desea eliminar.
**Ejemplo de Solicitud:**
```bash
curl -X DELETE -H "Authorization: $API_KEY" http://example.com/ogboot/v1/pxe-templates/template1
```
**Respuestas:**
- **Código 200 OK:** La plantilla de arranque se eliminó correctamente.
- **Código 404 Not Found:** No se encontró ninguna plantilla de arranque con el nombre especificado.
- **Código 500 Internal Server Error:** Ocurrió un error al eliminar la plantilla de arranque.

BIN
bin/composer.phar 100755

Binary file not shown.

17
bin/console 100755
View File

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

View File

@ -0,0 +1,85 @@
import os
import socket
import json
import subprocess
import logging
import stat
# Configuración de logging
logging.basicConfig(level=logging.INFO, filename='/var/log/oglive_daemon.log', filemode='a', format='%(asctime)s - %(levelname)s - %(message)s')
def handle_command(command):
action = command.get('action')
args = command.get('args', [])
cleaned_args = [arg.strip('\'"') for arg in args]
logging.info(f'Handling command: {action} with args: {cleaned_args}')
try:
if action in ['config', 'install', 'download', 'show', 'check', 'uninstall', 'disk_usage','list_installed_oglives','get_info','get_default','set_default','check_services_status']:
command_to_run = ['sudo', '/opt/ogboot/bin/oglivecli', action] + cleaned_args
logging.info(f'Running command: {" ".join(command_to_run)}')
process = subprocess.Popen(command_to_run, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
stdout, stderr = process.communicate()
logging.info(f'Command stdout: {stdout}')
logging.error(f'Command stderr: {stderr}')
# Asumimos que `stdout` contendrá el JSON válido
try:
json_output = json.loads(stdout)
return {"success": True, "output": json_output}
except json.JSONDecodeError as e:
logging.error(f'Error parsing JSON: {e} - Raw output: {stdout}')
return {"success": False, "error": f'Error parsing JSON: {str(e)} - Raw output: {stdout}'}
else:
return {"success": False, "error": "Unknown command"}
except Exception as e:
logging.error(f'Error handling command {action}: {e}')
return {"success": False, "error": str(e)}
def main():
# Crea el directorio si no existe
if not os.path.exists('/var/run/oglive'):
os.makedirs('/var/run/oglive', exist_ok=True)
socket_path = '/var/run/oglive/oglive_daemon.sock'
# Elimina el socket si existe
if os.path.exists(socket_path):
os.remove(socket_path)
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.bind(socket_path)
# Establece los permisos del socket
os.chmod(socket_path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # Permisos para todos los usuarios
server.listen()
try:
while True:
logging.info('Daemon ready to accept connections')
conn, _ = server.accept()
with conn:
logging.info('Accepted connection')
data = conn.recv(1024)
if not data:
continue
try:
command = json.loads(data.decode('utf-8'))
logging.info(f'Received command: {command}')
except json.JSONDecodeError:
logging.error('Failed to decode JSON')
conn.sendall(json.dumps({"success": False, "error": "Invalid JSON"}).encode('utf-8'))
continue
response = handle_command(command)
conn.sendall(json.dumps(response).encode('utf-8'))
finally:
server.close()
if os.path.exists(socket_path):
os.remove(socket_path)
if __name__ == '__main__':
main()

734
bin/oglivecli 100755
View File

@ -0,0 +1,734 @@
#!/bin/bash
#/**
#@file oglivecli
#@brief Command line tool to manage ogLive clients.
#@usage oglivecli Command [Options ...]
#@param Command:
#@param help show this help
#@param version show script version
#@param config [Parameter] show configuration parameters
#@param check check system consistency
#@param convert convert old ogclient to new default ogLive client
#@param list list installed ogLive clients
#@param show all show JSON information about all installed ogLive clients
#@param show default show JSON information about ogLive client marked as default
#@param show Index|Dir show JSON information about an installed ogLive client
#@param search Index|Dir show corresponding index or directory
#@param download show a menu to download an ogLive ISO image from the OpenGnsys website
#@param download Iso download an specific ogLive ISO image from the OpenGnsys website
#@param install Iso install a new ogLive client from a downloaded ISO image
#@param uninstall Iso remove ISO image and uninstall its ogLive client
#@param uninstall Index|Dir uninstall an ogLive client
#@param get-default get index value for default ogLive client
#@param set-default Index set default ogLive client
#@param rebuild rebuild a lost configuration file
#@param assign Iso Index assign an ISO file to a JSON entry
#@param Options:
#@param Index a number, starting by 0
#@param Dir directory (relative to installation directory)
#@param Iso ISO file name (relative to download URL or download directory)
#@warning This script needs "jq" command.
#@version 1.1.0 - Initial version.
#@author Ramón M. Gómez - ETSII Univ. Sevilla
#@date 2016-12-05
#@version 1.1.1b - Use reduced directory names.
#@author Ramón M. Gómez - ETSII Univ. Sevilla
#@date 2020-01-17
#*/ ##
# Global constants definition.
PROG=$(basename "$(realpath "$0")") # Program name.
OPENGNSYS=/opt/ogboot # OpenGnsys main directory.
DOWNLOADDIR=$OPENGNSYS/lib # Directory to store ogLive images.
DOWNLOADURL="https://ognproject.evlt.uma.es/trac/downloads" # Download URL.
TFTPDIR=$OPENGNSYS/tftpboot # TFTP directory.
DEFOGLIVE="ogLive" # Default ogLive directory.
MINREL=20190601 # Mininum ogLive compatibility release.
INFOFILE=$OPENGNSYS/etc/ogliveinfo.json # Configuration file.
# Global and secondary functions.
source $OPENGNSYS/lib/ogfunctions.sh || exit 1
# Create/edit JSON file about installed ogLive clients.
function addToJson() {
local i DATA OGLIVEDIST="$1" OGLIVEKRNL="$2" OGLIVEARCH="$3" OGLIVEREV="$4"
local OGLIVEDIR=$(basename $5 2>/dev/null) OGLIVEISO=$(basename $6 2>/dev/null)
# JSON data for installed ogLive.
DATA=$(cat << EOT | jq .
{"distribution":"$OGLIVEDIST","kernel":"$OGLIVEKRNL","architecture":"$OGLIVEARCH","revision":"$OGLIVEREV","directory":"$OGLIVEDIR","iso":"$OGLIVEISO"}
EOT
)
# Check JSON file consistency.
if [ "$(jq -c keys $INFOFILE 2>/dev/null)" == '["default","oglive"]' ]; then
# Check if ogLive is defined into JSON file.
n=$(jq ".oglive | length" $INFOFILE)
for ((i=0; i<n; i++)); do
[ "$(jq ".check=$DATA | .check==.oglive[$i]" $INFOFILE)" == "true" ] && INDEX=$i
done
# Check if it needs to insert data.
if [ -z "$INDEX" ]; then
INDEX=$n
jq ".oglive |= (. + [$DATA])" $INFOFILE | sponge $INFOFILE
fi
# Show JSON entry.
jq ".oglive[$INDEX]" $INFOFILE
else
# Create new JSON file.
cat << EOT | jq . | tee $INFOFILE
{"oglive":[$DATA],"default":0}
EOT
fi
}
# Command functions.
# Convert default ogclient to a new ogLive format.
function convert() {
local OGCLIENT=ogclient OLDINFOFILE=$OPENGNSYS/doc/veroglive.txt
local OGLIVEKRNL OGLIVEDIR OGLIVEISO
[ $# -ne 0 ] && raiseError usage
[ ! -w $(dirname $INFOFILE) ] && raiseError access "Configuration file."
[ -n "$(stat -c "%N" $TFTPDIR/ogclient | awk '$3~/'$DEFOGLIVE'/ {print}')" ] && raiseError access "ogLive is already converted."
pushd $TFTPDIR >/dev/null || raiseError access "Installation directory."
[ ! -f $OGCLIENT/ogvmlinuz ] && raiseError notfound "\"ogclient\"."
# Add entry to JSON file using ogclient kernel version.
OGLIVEKRNL=$(file -bkr $OGCLIENT/ogvmlinuz | awk '/Linux/ {for(i=1;i<=NF;i++) if($i~/version/) {v=$(i+1);sub(/-.*/,"",v);print v}}')
OGLIVEDIR=$DEFOGLIVE-$OGLIVEKRNL
[ -r $OLDINFOFILE ] && OGLIVEISO="$(head -1 $OLDINFOFILE)"
addToJson "$(echo $OGLIVEISO|cut -f2 -d-)" "$OGLIVEKRNL" "i386" "${OGLIVEISO##*-}" "$OGLIVEDIR" "$OGLIVEISO.iso"
# Rename directory, link to default and clean old files.
mv -v $OGCLIENT $OGLIVEDIR
ln -vfs $OGLIVEDIR $DEFOGLIVE
rm -f $OGCLIENT
ln -vfs $DEFOGLIVE $OGCLIENT
mv -v $OGCLIENT.old $OGLIVEDIR.old 2>/dev/null
rm -fv {ogvmlinuz,oginitrd.img}{,.sum} $OLDINFOFILE
popd >/dev/null
# Delete old config file.
rm -f $OLDINFOFILE
}
# Show script configuration parameters.
function config() {
local DATA
DATA=$(cat << EOT
[
{ "param": "config-file", "description": "Configuration file", "value": "$INFOFILE" },
{ "param": "download-url", "description": "ogLive download URL", "value": "$DOWNLOADURL" },
{ "param": "download-dir", "description": "ogLive download directory", "value": "$DOWNLOADDIR" },
{ "param": "install-dir", "description": "ogLive installation directory", "value": "$TFTPDIR" },
{ "param": "default-name", "description": "Default ogLive name", "value": "$DEFOGLIVE" },
{ "param": "min-release", "description": "Minimum compatibility release", "value": "r$MINREL" }
]
EOT
)
case $# in
0) # Show all parameters.
echo "$DATA" | jq -r '.[] | .description + " (" + .param + ")," + .value' | column -ts,
;;
1) # Show specified parameter.
DATA=$(echo "$DATA" | jq -r ".[] | select(.param==\"$1\").value")
[ "$DATA" ] || raiseError notfound "\"$1\"."
echo "$DATA"
;;
*) # Usage error.
raiseError usage
;;
esac
}
# Check consistency, showing configuration problems.
function check() {
local ERR=0 AUX INST DEF
[ $# -ne 0 ] && raiseError usage
# Check for old system that needs conversion.
if [ -z "$(stat -c "%N" $TFTPDIR/ogclient | awk '$3~/'$DEFOGLIVE'/ {print}')" ]; then
echo "This server uses old ogclient, please run \"$PROG convert\" to update."
let ERR++
[ ! -f $INFOFILE ] && return $ERR
fi
# Check for other problems.
[ ! -f $INFOFILE ] && echo "Configuration file does not exists: $INFOFILE" && let ERR++
[ -f $INFOFILE -a "$(jq -c keys $INFOFILE 2>/dev/null)" != "[\"default\",\"oglive\"]" ] && echo "Format error in configuration file: $INFOFILE" && let ERR++
[ ! -e $TFTPDIR ] && echo "TFTP directory does not exist: $TFTPDIR." && let ERR++
# Check for installed ogLive clients.
INST=( $(find $TFTPDIR/ -type d -name "$DEFOGLIVE-*" -a ! -name "*.old" -printf "%f\n" | sort) )
[[ ${#INST[@]} -eq 0 ]] && echo "No ogLive clients are installed." && let ERR++
DEF=( $(jq -r .oglive[].directory $INFOFILE 2>/dev/null | sort) )
# Compare installed and defined ogLive clients.
AUX=$(comm -23 <(printf "%s\n" ${INST[*]}) <(printf "%s\n" ${DEF[*]}))
[ -n "$AUX" ] && echo "Some ogLive are installed but not defined: ${AUX//$'\n'/, }" && let ERR++
AUX=$(comm -13 <(printf "%s\n" ${INST[*]}) <(printf "%s\n" ${DEF[*]}))
[ -n "$AUX" ] && echo "Some ogLive are defined but not installed: ${AUX//$'\n'/, }" && let ERR++
# Compare downloaded and defined ISO images.
INST=( $(find $DOWNLOADDIR/ -type f -name "$DEFOGLIVE-*.iso" -printf "%f\n" | sort) )
DEF=( $(jq -r .oglive[].iso $INFOFILE 2>/dev/null | sort) )
AUX=$(comm -23 <(printf "%s\n" ${INST[*]}) <(printf "%s\n" ${DEF[*]}))
[ -n "$AUX" ] && echo "Some ISOs are downloaded but not defined: ${AUX//$'\n'/, }" && let ERR++
AUX=$(comm -13 <(printf "%s\n" ${INST[*]}) <(printf "%s\n" ${DEF[*]}))
[ -n "$AUX" ] && echo "Some ISOs are defined but not downloaded: ${AUX//$'\n'/, }" && let ERR++
# Check for new ISO files downloaded after installation.
AUX=$(jq -r '.oglive[] as $og | $og.iso + ":" + $og.directory' $INFOFILE 2>/dev/null | \
while IFS=":" read -r DEF INST; do
[ $DOWNLOADDIR/$DEF -nt $TFTPDIR/$INST ] && echo "$DEF"
done)
[ -n "$AUX" ] && echo "Some ISOs are downloaded after installation: ${AUX//$'\n'/, }" && let ERR++
AUX=$(jq -r '.oglive[] as $og | if ($og.revision[1:9] | tonumber) < '$MINREL' then $og.directory else "" end' $INFOFILE 2>/dev/null)
[ -n "$AUX" ] && echo "Some installed ogLive aren't fully compatible: ${AUX//$'\n'/, }" && let ERR++
DEF=$(jq -r ".oglive[$(getdefault)].directory" $INFOFILE 2>/dev/null)
INST=$(stat -c "%N" $TFTPDIR/$DEFOGLIVE | cut -f4 -d\')
[ "$DEF" != "$INST" ] && echo "Default ogLive is not linked to right directory: $DEF <> $INST" && let ERR++
# Print result.
[ $ERR -eq 0 ] && echo "OK!" || echo "Problems detected: $ERR"
return $ERR
}
# List installed ogLive clients.
function list() {
[ $# -ne 0 ] && raiseError usage
[ ! -r $INFOFILE ] && raiseError access "Configuration file."
# List all defined indexes, directories and check if missing.
jq -r .oglive[].directory $INFOFILE | nl -v 0 | \
awk '{system("echo -n "$0"; test -d '$TFTPDIR'/"$2" || echo -n \" (missing)\"; echo")}' | column -t
}
# Show information about an installed ogLive client.
function show() {
local INDEX
[ $# -ne 1 ] && raiseError usage
[ ! -r $INFOFILE ] && raiseError access "Configuration file."
# Show JSON entries.
case "$1" in
default) # Default index.
INDEX="[$(jq -r .default $INFOFILE)]" ;;
all) # All intries.
;;
[0-9]*) # Index.
INDEX="[$1]" ;;
*) # Directory.
INDEX="[$(search "$1" 2>/dev/null)]" || raiseError notfound "Directory \"$1\"."
;;
esac
jq ".oglive$INDEX" $INFOFILE || raiseError notfound "Index \"$1\"."
}
# Show index or directory corresponding to searching parameter.
function search() {
[ $# -ne 1 ] && raiseError usage
[ ! -r $INFOFILE ] && raiseError access "Configuration file."
# Show corresponding index or directory.
list | awk -v d="$1" '{if ($2==d) print $1; if ($1==d) print $2}' | grep . || raiseError notfound "Index/Directory \"$1\"."
}
function download() {
local OGLIVE NISOS i HTTPCODE ISOREL
# Verificar si el directorio de descarga existe y tiene permisos de escritura.
[ ! -d "$DOWNLOADDIR" ] && raiseError notfound "Directorio de descarga."
[ ! -w "$DOWNLOADDIR" ] && raiseError access "Directorio de descarga."
# Si no se proporciona ningún parámetro, mostrar el menú de descargas.
if [ -z "$1" ]; then
downloadMenu
else
local selected_name="$1"
# Obtener la lista de archivos disponibles.
OGLIVE=( $(curl -k --silent $DOWNLOADURL | grep "$DEFOGLIVE.*iso") )
# Buscar el archivo seleccionado por nombre.
OGLIVEFILE=""
for iso in "${OGLIVE[@]}"; do
if [[ "$iso" == *"$selected_name"* ]]; then
OGLIVEFILE=$iso
break
fi
done
[ -n "$OGLIVEFILE" ] || raiseError download "Nombre \"$selected_name\" inválido."
# Obtener el tamaño de descarga.
local SOURCELENGTH=$(curl -k --head --retry 5 --retry-delay 5 --max-time 30 "$DOWNLOADURL/$OGLIVEFILE" | awk -F: '/Content-Length:/ {print $2}')
[ -n "$SOURCELENGTH" ] || raiseError download "$OGLIVEFILE"
# Descargar ogLive.
local TARGETFILE="$DOWNLOADDIR/$OGLIVEFILE"
trap "rm -f $TARGETFILE" 1 2 3 6 9 15
curl -k --retry 5 --retry-delay 5 "$DOWNLOADURL/$OGLIVEFILE" -o "$TARGETFILE" || raiseError download "\"$OGLIVEFILE\"."
install "$OGLIVEFILE"
fi
}
# Muestra un menú para seleccionar y descargar un archivo ogLive ISO del sitio web de OpenGnsys.
function downloadMenu() {
local OGLIVE NISOS i HTTPCODE ISOREL
OGLIVE=( $(curl -k --silent $DOWNLOADURL | grep "$DEFOGLIVE.*iso") )
NISOS=${#OGLIVE[@]}
local downloads=()
for i in $(seq 1 $NISOS); do
local installed=false
local compatible=false
[ -e $DOWNLOADDIR/${OGLIVE[i-1]} ] && installed=true
ISOREL=${OGLIVE[i-1]##*-r}; ISOREL=${ISOREL%%.*}
[ $ISOREL -ge $MINREL ] && compatible=true
local DATA=$(jq -n \
--arg id "$i" \
--arg filename "${OGLIVE[i-1]}" \
--argjson installed "$installed" \
--argjson compatible "$compatible" \
'{id: $id, filename: $filename, installed: $installed, compatible: $compatible}')
downloads+=("$DATA")
done
jq -n --argjson downloads "$(printf '%s\n' "${downloads[@]}" | jq -s .)" \
'{downloads: $downloads}'
}
# Show a menu to select and download an ogLive ISO image from the OpenGnsys website.
function download_old() {
local OGLIVE NISOS i HTTPCODE TARGETFILE
local ISOREL
[ $# -gt 1 ] && raiseError usage
[ ! -d $DOWNLOADDIR ] && raiseError notfound "Download directory."
[ ! -w $DOWNLOADDIR ] && raiseError access "Download directory."
# Check parameter.
if [ -n "$1" ]; then
# ogLive to download.
OGLIVEFILE="$1"
else
# Show download menu.
OGLIVE=( $(curl -k --silent $DOWNLOADURL | grep "$DEFOGLIVE.*iso") )
NISOS=${#OGLIVE[@]}
echo "Available downloads (+ = installed, * = full compatibility):"
for i in $(seq 1 $NISOS); do
[ -e $DOWNLOADDIR/${OGLIVE[i-1]} ] && OGLIVE[i-1]="(+) ${OGLIVE[i-1]}"
ISOREL=${OGLIVE[i-1]##*-r}; ISOREL=${ISOREL%%.*}
[ $ISOREL -ge $MINREL ] && OGLIVE[i-1]="(*) ${OGLIVE[i-1]}"
done
select opt in "${OGLIVE[@]}"; do
[ -n "$opt" ] && OGLIVEFILE=${opt##* } && break
done
fi
# Get download size.
SOURCELENGTH=$(curl -k --head --retry 5 --retry-delay 5 --max-time 30 $DOWNLOADURL/$OGLIVEFILE | awk -F: '/Content-Length:/ {print $2}')
[ -n "$SOURCELENGTH" ] || raiseError download "$OGLIVEFILE"
# Download ogLive.
TARGETFILE=$DOWNLOADDIR/$OGLIVEFILE
trap "rm -f $TARGETFILE" 1 2 3 6 9 15
curl -k --retry 5 --retry-delay 5 --max-time 30 $DOWNLOADURL/$OGLIVEFILE -o $TARGETFILE || raiseError download "\"$OGLIVEFILE\"."
}
update_json() {
local key=$1
local value=$2
result_json=$(jq --arg key "$key" --arg value "$value" '.[$key] = $value' <<< "$result_json")
}
add_message() {
local message=$1
result_json=$(jq --arg message "$message" '.messages += [$message]' <<< "$result_json")
}
# Install an ogLive client from a previously downloaded ISO image.
function install() {
local OGLIVEFILE OGLIVEDIST OGLIVEREV OGLIVEKRNL OGLIVEDIR OGINITRD OGSQFS OGCLIENT=ogclient
local COMPRESS SAMBAPASS TMPDIR RSYNCSERV RSYNCCLNT JSON_OUTPUT
[ $# -ne 1 ] && { echo "{\"status\": \"error\", \"error\": \"usage\"}"; exit 1; }
OGLIVEFILE=$(realpath $DOWNLOADDIR/$1)
[ $(echo $OGLIVEFILE | wc -w) -gt 1 ] && { echo "{\"status\": \"error\", \"error\": \"usage\"}"; exit 1; }
[ ! -f $OGLIVEFILE ] && { echo "{\"status\": \"error\", \"error\": \"not found $1.\"}"; exit 1; }
[ ! -r $OGLIVEFILE ] && { echo "{\"status\": \"error\", \"error\": \"access $1.\"}"; exit 1; }
[ ! -w $(dirname $INFOFILE) ] && { echo "{\"status\": \"error\", \"error\": \"access configuration directory.\"}"; exit 1; }
[ ! -w $TFTPDIR ] && { echo "{\"status\": \"error\", \"error\": \"access installation directory.\"}"; exit 1; }
[ -z "$(file -b $OGLIVEFILE | grep "ISO.*ogClient")" ] && { echo "{\"status\": \"error\", \"error\": \"File is not an ogLive ISO image.\"}"; exit 1; }
OGLIVEDIST="$(echo $OGLIVEFILE|cut -f2 -d-)"
OGLIVEREV="${OGLIVEFILE##*-}"; OGLIVEREV="${OGLIVEREV%%.*}"
OGLIVEKRNL="$(echo $OGLIVEFILE|cut -f3- -d-)"; OGLIVEKRNL="${OGLIVEKRNL%-$OGLIVEREV.*}"
OGLIVEARCH="$(echo $OGLIVEFILE|awk -F- '{print $(NF-1)}')"
case "$OGLIVEARCH" in
i386|amd64)
OGLIVEKRNL="${OGLIVEKRNL%-$OGLIVEARCH}" ;;
*)
OGLIVEARCH="i386" ;;
esac
OGLIVEDIR="$TFTPDIR/$DEFOGLIVE-${OGLIVEKRNL%%-*}-$OGLIVEARCH-$OGLIVEREV"
OGLIVEDIR="${OGLIVEDIR/amd64-/}"
OGINITRD=$OGLIVEDIR/oginitrd.img
[ ! -r $OGINITRD ] && OGINITRD=$TFTPDIR/$DEFOGLIVE/oginitrd.img
if [ -r $OGINITRD ]; then
COMPRESS=$(file -b "$OGINITRD" | awk '{print tolower($1);}')
SAMBAPASS=$($COMPRESS -dc $OGINITRD | \
cpio -i --to-stdout scripts/ogfunctions 2>/dev/null | \
sed -n '/^[ \t].*OPTIONS=/s/.*pass=\(\w*\).*/\1/p')
fi
rm -fr ${OGLIVEDIR}.old
mv -f $OGLIVEDIR ${OGLIVEDIR}.old 2>/dev/null
TMPDIR=/tmp/${OGLIVEFILE%.iso}
mkdir -p $OGLIVEDIR $TMPDIR
trap "umount $TMPDIR; rm -fr $TMPDIR" 1 2 3 6 9 15
mount -o loop,ro $OGLIVEFILE $TMPDIR >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"mount failed.\"}"; exit 1; }
cp -va $TMPDIR/ogclient/* $OGLIVEDIR >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"Cannot copy files to ogLive directory.\"}"; exit 1; }
umount $TMPDIR >/dev/null 2>&1
if [ ! -f $INFOFILE ]; then
rm -f $TFTPDIR/$DEFOGLIVE $TFTPDIR/$OGCLIENT
ln -vfs $(basename $OGLIVEDIR) $TFTPDIR/$DEFOGLIVE >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"Linking to $TFTPDIR/$DEFOGLIVE failed.\"}"; exit 1; }
ln -vfs $DEFOGLIVE $TFTPDIR/$OGCLIENT >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"Linking to $TFTPDIR/$OGCLIENT failed.\"}"; exit 1; }
fi
if [ -n "$SAMBAPASS" ]; then
echo -ne "$SAMBAPASS\n$SAMBAPASS\n" | $OPENGNSYS/bin/setsmbpass "$(basename $OGLIVEDIR)" >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"setsmbpass failed.\"}"; exit 1; }
else
$OPENGNSYS/bin/setsmbpass "$(basename $OGLIVEDIR)" >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"setsmbpass failed.\"}"; exit 1; }
fi
find -L $OGLIVEDIR -type d -exec chmod 755 {} \; >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"chmod directories failed.\"}"; exit 1; }
find -L $OGLIVEDIR -type f -exec chmod 644 {} \; >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"chmod files failed.\"}"; exit 1; }
chown -R :opengnsys $OGLIVEDIR >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"chown failed.\"}"; exit 1; }
OGSQFS=$OGLIVEDIR/ogclient.sqfs
if mount -o loop,ro $OGSQFS $TMPDIR >/dev/null 2>&1; then
RSYNCSERV=$(rsync --version 2>/dev/null | awk '/protocol/ {print $6}')
RSYNCCLNT=$(chroot $TMPDIR /usr/bin/rsync --version 2>/dev/null | awk '/protocol/ {print $6}')
if [ -z "$RSYNCSERV" ] || [ "$RSYNCSERV" -gt "${RSYNCCLNT:-1}" ]; then
if [ -e "$OPENGNSYS/client/bin/rsync-$RSYNCSERV" ]; then
mv -f "$OPENGNSYS/client/bin/rsync-$RSYNCSERV" "$OPENGNSYS/client/bin/rsync" 2>/dev/null
fi
else
if [ -e "$OPENGNSYS/client/bin/rsync" ]; then
mv -f "$OPENGNSYS/client/bin/rsync" "$OPENGNSYS/client/bin/rsync-$($OPENGNSYS/client/bin/rsync --version 2>/dev/null | awk '/protocol/ {print $6}')"
fi
fi
umount $TMPDIR >/dev/null 2>&1
rmdir $TMPDIR >/dev/null 2>&1 || rm -rf $TMPDIR >/dev/null 2>&1
fi
# Crear JSON output
JSON_OUTPUT=$(jq -n \
--arg dist "$OGLIVEDIST" \
--arg krnl "$OGLIVEKRNL" \
--arg arch "$OGLIVEARCH" \
--arg rev "$OGLIVEREV" \
--arg dir "$OGLIVEDIR" \
--arg iso "$(basename "$OGLIVEFILE")" \
'{status: "success", messages: [], result: {distribution: $dist, kernel: $krnl, architecture: $arch, revision: $rev, directory: $dir, iso: $iso}}')
echo "$JSON_OUTPUT"
}
# Uninstall an ogLive client.
function uninstall() {
local CHECKSUM DIR
# Validar que se proporcionó exactamente un argumento (el checksum)
[ $# -ne 1 ] && { echo "{\"error\": \"usage: uninstall {checksum}\"}"; exit 1; }
CHECKSUM=$1
# Verificar acceso a los directorios necesarios
[ ! -w $TFTPDIR ] && { echo "{\"error\": \"access installation directory.\"}"; exit 1; }
# Buscar el directorio correspondiente al checksum
DIR=$(find $TFTPDIR -type f -name 'ogclient.sqfs.sum' -exec grep -l "$CHECKSUM" {} \; | xargs -I{} dirname {})
# Si no se encuentra el directorio, devolver error
if [ -z "$DIR" ]; then
echo "{\"error\": \"ogLive client with checksum $CHECKSUM not found.\"}"
exit 1
fi
# Eliminar archivos y directorio, redirigiendo la salida a /dev/null
rm -vfr $DIR > /dev/null 2>&1
# Comprobar si la eliminación tuvo éxito
if [ -d "$DIR" ]; then
echo "{\"error\": \"Failed to uninstall ogLive client in $DIR.\"}"
exit 1
fi
# Devolver mensaje de éxito
echo "{\"message\": \"ogLive client uninstalled successfully.\", \"details\": \"Removed directory: $DIR\"}"
}
# Get information about the default ogLive client.
function get_default() {
local DEFAULT_LINK="$TFTPDIR/$DEFOGLIVE"
local DIR OGLIVEDIST OGLIVEKRNL OGLIVEARCH OGLIVEREV OGLIVEISO OGLIVEDIR
# Verificar que el enlace simbólico del ogLive por defecto existe.
if [ ! -L "$DEFAULT_LINK" ]; then
echo "{\"error\": \"Default ogLive client link not found.\"}"
exit 1
fi
# Obtener el directorio real al que apunta el enlace simbólico.
DIR=$(readlink -f "$DEFAULT_LINK")
# Si no se encuentra el directorio, devolver error.
if [ -z "$DIR" ]; then
echo "{\"error\": \"Default ogLive client directory not found.\"}"
exit 1
fi
# Obtener la información del ogLive a partir del nombre del directorio.
OGLIVEDIR=$(basename "$DIR")
OGLIVEDIST="$(echo $OGLIVEDIR | cut -d- -f2)"
OGLIVEKRNL="$(echo $OGLIVEDIR | cut -d- -f3)"
OGLIVEARCH="amd64" # Suponiendo que siempre es amd64
OGLIVEREV="$(echo $OGLIVEDIR | cut -d- -f4)"
OGLIVEISO="" # No tenemos la información del ISO aquí, podría necesitarse un ajuste si se requiere
# Construir el JSON con la información.
local INFO=$(cat << EOT
{
"distribution": "$OGLIVEDIST",
"kernel": "$OGLIVEKRNL",
"architecture": "$OGLIVEARCH",
"revision": "$OGLIVEREV",
"directory": "$DIR",
"iso": "$OGLIVEISO"
}
EOT
)
# Devolver la información en formato JSON.
echo "$INFO"
}
# Set default ogLive client by checksum.
function set_default() {
local CHECKSUM=$1
local DIR
# Validar que se proporcionó exactamente un argumento (el checksum)
[ $# -ne 1 ] && { echo "{\"error\": \"usage: set-default {checksum}\"}"; exit 1; }
# Verificar acceso a los directorios necesarios
[ ! -w $TFTPDIR ] && { echo "{\"error\": \"access installation directory.\"}"; exit 1; }
# Buscar el directorio correspondiente al checksum
DIR=$(find $TFTPDIR -type f -name 'ogclient.sqfs.sum' -exec grep -l "$CHECKSUM" {} \; | xargs -I{} dirname {} | grep -v ".old")
# Si no se encuentra el directorio, devolver error
if [ -z "$DIR" ]; then
echo "{\"error\": \"ogLive client with checksum $CHECKSUM not found.\"}"
exit 1
fi
# Eliminar el enlace simbólico existente y crear uno nuevo
rm -f $TFTPDIR/$DEFOGLIVE > /dev/null 2>&1
ln -vfs $(basename $DIR) $TFTPDIR/$DEFOGLIVE > /dev/null 2>&1
# Comprobar si el enlace simbólico se creó correctamente
if [ "$(readlink -f $TFTPDIR/$DEFOGLIVE)" == "$(readlink -f $DIR)" ]; then
echo "{\"message\": \"ogLive client set as default successfully.\", \"details\": \"$DIR\"}"
else
echo "{\"error\": \"Failed to set default ogLive client.\"}"
exit 1
fi
}
# Rebuild a lost configuration file.
function rebuild() {
local i INST NF DEF
[ $# -ne 0 ] && raiseError usage
[ -f $INFOFILE ] && raiseError access "Configuration file exists."
INST=$(find $TFTPDIR/ -type d -name "$DEFOGLIVE-*" -a ! -name "*.old" -printf "%f\n" | sort)
for i in $INST; do
NF=$(echo $i | awk -F- '{print NF-1}')
case $NF in
1) addToJson "" "$(echo $i|cut -f2 -d-)" "i386" "" "$i" "" ;;
2) eval addToJson $(echo $i | awk -F- '{printf "\"\" %s amd64 %s %s \"\"",$2,$3,$0}') ;;
3) eval addToJson $(echo $i | awk -F- '{if ($3=="i386") printf "\"\" %s %s %s %s \"\"",$2,$3,$4,$0; else printf "%s %s i386 %s %s \"\"",$2,$3,$4,$0}') ;;
4) eval addToJson $(echo $i | awk -F- '{printf "%s %s %s %s %s \"\"",$2,$3,$4,$5,$0}') ;;
esac
# Check for is default oglive.
[ -n "$(stat -c "%N" $TFTPDIR/$DEFOGLIVE | awk '$3~/'$i'/ {print}')" ] && DEF="$i"
done
# Set default ogLive.
[ -n "$DEF" ] && setdefault $(search $DEF)
}
# Assign an ISO file to a JSON entry.
function assign() {
local ISOFILE DIR
[ $# -ne 2 ] && raiseError usage
[ ! -w $INFOFILE ] && raiseError access "Configuration file."
# Check if ISO file and index directory exist.
ISOFILE=$DOWNLOADFILE/$1
[ ! -f $DOWNLOADDIR/$ISOFILE ] && raiseError notfound "ISO file \"$1\"."
DIR=$(search $2 2>/dev/null)
[ ! -d $TFTPDIR/$DIR ] && raiseError notfound "Directory for index \"$2\"."
# Assign ISO file to JSON entry.
jq ".oglive[$2].iso=\"$1\"" $INFOFILE | sponge $INFOFILE && jq ".oglive[$2]" $INFOFILE
}
# Get disk usage information
function disk_usage() {
DISK_INFO=$(df -h / | awk 'NR==2{print "{\"total\":\""$2"\", \"used\":\""$3"\", \"available\":\""$4"\", \"percentage\":\""$5"\"}"}')
echo $DISK_INFO
}
# Function to list installed ogLive clients and the default ogLive client
function list_installed_oglives() {
local INST NF DEF
INST=$(find $TFTPDIR/ -type d -name "$DEFOGLIVE-*" -a ! -name "*.old" -printf "%f\n" | sort)
local installed_ogLives=()
for i in $INST; do
NF=$(echo $i | awk -F- '{print NF-1}')
local OGLIVEDIST=""
local OGLIVEKRNL=""
local OGLIVEARCH=""
local OGLIVEREV=""
local CHECKSUM=""
local CHECKSUM_FILE="$TFTPDIR/$i/ogclient.sqfs.sum"
if [ -f "$CHECKSUM_FILE" ]; then
CHECKSUM=$(cat "$CHECKSUM_FILE" | cut -d ' ' -f 1)
fi
case $NF in
1) OGLIVEDIST="" OGLIVEKRNL=$(echo $i|cut -f2 -d-) OGLIVEARCH="i386" OGLIVEREV="" ;;
2) eval $(echo $i | awk -F- '{printf "OGLIVEDIST=\"\" OGLIVEKRNL=%s OGLIVEARCH=amd64 OGLIVEREV=%s OGLIVEDIR=%s",$2,$3,$0}') ;;
3) eval $(echo $i | awk -F- '{if ($3=="i386") printf "OGLIVEDIST=\"\" OGLIVEKRNL=%s OGLIVEARCH=%s OGLIVEREV=%s OGLIVEDIR=%s",$2,$3,$4,$0; else printf "OGLIVEDIST=%s OGLIVEKRNL=%s OGLIVEARCH=i386 OGLIVEREV=%s OGLIVEDIR=%s",$2,$3,$4,$0}') ;;
4) eval $(echo $i | awk -F- '{printf "OGLIVEDIST=%s OGLIVEKRNL=%s OGLIVEARCH=%s OGLIVEREV=%s OGLIVEDIR=%s",$2,$3,$4,$5,$0}') ;;
esac
local DATA=$(jq -n \
--arg id "$CHECKSUM" \
--arg dist "$OGLIVEDIST" \
--arg krnl "$OGLIVEKRNL" \
--arg arch "$OGLIVEARCH" \
--arg rev "$OGLIVEREV" \
--arg dir "$TFTPDIR/$OGLIVEDIR" \
--arg iso "" \
'{id: $id, distribution: $dist, kernel: $krnl, architecture: $arch, revision: $rev, directory: $dir, iso: $iso}')
installed_ogLives+=("$DATA")
[ -n "$(stat -c "%N" $TFTPDIR/$DEFOGLIVE | awk '$3~/'$i'/ {print}')" ] && DEF="$i"
done
local default_oglive=$(basename $(readlink -f $TFTPDIR/$DEFOGLIVE))
jq -n \
--arg default_oglive "$default_oglive" \
--argjson installed_ogLives "$(printf '%s\n' "${installed_ogLives[@]}" | jq -s .)" \
'{
default_oglive: $default_oglive,
installed_ogLives: $installed_ogLives
}'
}
# Get information about an installed ogLive client.
function get_info() {
local CHECKSUM="$1"
local DIR OGLIVEDIST OGLIVEKRNL OGLIVEARCH OGLIVEREV OGLIVEISO OGLIVEDIR
# Verificar que se proporcionó un checksum.
[ -z "$CHECKSUM" ] && { echo "{\"error\": \"usage: get_info {checksum}\"}"; exit 1; }
# Verificar acceso al directorio de instalación.
[ ! -w $TFTPDIR ] && { echo "{\"error\": \"access installation directory.\"}"; exit 1; }
# Buscar el directorio correspondiente al checksum, excluyendo los que terminan en .old.
DIR=$(find $TFTPDIR -type f -name 'ogclient.sqfs.sum' -exec grep -l "$CHECKSUM" {} \; | grep -v '.old' | xargs -I{} dirname {})
# Si no se encuentra el directorio, devolver error.
if [ -z "$DIR" ]; then
echo "{\"error\": \"ogLive client with checksum $CHECKSUM not found.\"}"
exit 1
fi
# Obtener la información del ogLive a partir del nombre del directorio.
OGLIVEDIR=$(basename "$DIR")
OGLIVEDIST="$(echo $OGLIVEDIR | cut -d- -f2)"
OGLIVEKRNL="$(echo $OGLIVEDIR | cut -d- -f3)"
OGLIVEARCH="amd64" # Suponiendo que siempre es amd64
OGLIVEREV="$(echo $OGLIVEDIR | cut -d- -f4)"
OGLIVEISO="" # No tenemos la información del ISO aquí, podría necesitarse un ajuste si se requiere
# Construir el JSON con la información.
local INFO=$(cat << EOT
{
"distribution": "$OGLIVEDIST",
"kernel": "$OGLIVEKRNL",
"architecture": "$OGLIVEARCH",
"revision": "$OGLIVEREV",
"directory": "$DIR",
"iso": "$OGLIVEISO"
}
EOT
)
# Devolver la información en formato JSON.
echo "$INFO"
}
# Function to check the status of services
function check_services_status() {
local SERVICES=("oglive_daemon.service" "tftpd-hpa.service" "nginx.service")
declare -A STATUS_MAP
for service in "${SERVICES[@]}"; do
if systemctl list-units --type=service --all | grep -q "$service"; then
STATUS=$(systemctl is-active "$service")
STATUS_MAP[$service]=$STATUS
else
STATUS_MAP[$service]="not installed"
fi
done
local json_output=$(jq -n \
--arg oglive_daemon "${STATUS_MAP['oglive_daemon.service']}" \
--arg tftpboot "${STATUS_MAP['tftpd-hpa.service']}" \
--arg nginx "${STATUS_MAP['nginx.service']}" \
'{
oglive_daemon: $oglive_daemon,
tftpboot: $tftpboot,
nginx: $nginx
}')
echo "$json_output"
}
# Main progrram.
# Access control.
[ -r $OPENGNSYS/www/controlacceso.php ] && ACCESS="web"
[ "$USER" = "root" ] && ACCESS="root"
[ -z "$ACCESS" ] && raiseError access "Need to be root."
# Check dependencies.
which sponge &>/dev/null || raiseError notfound "Need to install \"moreutils\"."
# Commands control.
shopt -s extglob
case "$ACCESS" in
root) CMDS='+(help|version|convert|config|check|list|show|search|download|install|uninstall|get-default|set-default|rebuild|assign|disk_usage|list_installed_oglives|get_info|get_default|set_default|check_services_status)' ;;
web) CMDS='+(list|show|search|get-default)' ;;
esac
case "$1" in
$CMDS) COMMAND="${1/-/}"; shift; $COMMAND "$@" ;;
*) raiseError usage ;;
esac
exit $?

23
bin/phpunit 100755
View File

@ -0,0 +1,23 @@
#!/usr/bin/env php
<?php
if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}
if (is_file(dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit')) {
if (PHP_VERSION_ID >= 80000) {
require dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit';
} else {
define('PHPUNIT_COMPOSER_INSTALL', dirname(__DIR__).'/vendor/autoload.php');
require PHPUNIT_COMPOSER_INSTALL;
PHPUnit\TextUI\Command::main();
}
} else {
if (!is_file(dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) {
echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n";
exit(1);
}
require dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php';
}

142
bin/setsmbpass 100755
View File

@ -0,0 +1,142 @@
#!/bin/bash
#/**
# setsmbpass
#@file setsmbpass [ogLive]
#@brief Cambia la contraseña del usuario del cliente para acceder a los servicios Samba.
#@warning Se modifica el Initrd del cliente y se cambia la clave en el servidor.
#@warning No se modifica el usuario de acceso (usuario "opengnsys").
#@version 1.0.2 - Versión inicial.
#@author Ramón M. Gómez - ETSII Univ. Sevilla
#@date 2011-07-28
#@version 1.1.0 - Soporte para varios clientes ogLive.
#@author Ramón M. Gómez - ETSII Univ. Sevilla
#@date 2017-06-20
#*/ ##
# Variables.
PROG=$(basename "$0")
PATH=$PATH:$(dirname "$(realpath "$0")")
OPENGNSYS=${OPENGNSYS:-"/opt/opengnsys"}
OGCFGFILE=$OPENGNSYS/etc/opengnsys.json
SAMBAUSER="opengnsys" # Usuario por defecto.
TFTPDIR=$OPENGNSYS/tftpboot
INITRD=oginitrd.img
TMPDIR=/tmp/oglive$$
let CHANGES=0
# Control básico de errores.
if [ "$USER" != "root" ]; then
echo "$PROG: Error: solo ejecutable por root" >&2
exit 1
fi
case $# in
0) # Cambios en todos los clientes ogLive instalados.
if which oglivecli &>/dev/null; then
LIST=$(oglivecli list | awk '{print $2}')
else
LIST="ogclient"
fi ;;
1) # Cambios en único ogLive (AVISO: puede crear inconsistencias con otros ogLive).
LIST="$1" ;;
*) # Error de formato.
echo "$PROG: Error de ejecución" >&2
echo "Formato: $PROG ogLive"
exit 1 ;;
esac
# Recuperar eco de consola si se corta el proceso.
trap "stty echo 2>/dev/null" KILL
# Buscar todos los clients ogLive instalados.
for OGLIVE in $LIST; do
# Crear clave para usuario de acceso a los recursos.
CLIENTINITRD="$TFTPDIR/$OGLIVE/$INITRD"
if [ -r "$CLIENTINITRD" ]; then
if [ -z "$SAMBAPASS" ]; then
# Obtener clave del teclado sin eco en pantalla.
stty -echo 2>/dev/null
echo -n "Clave del usuario Samba: "
read -r SAMBAPASS
# Solo se deben aceptar números y letras para la clave de acceso.
if [[ "$SAMBAPASS" =~ [^a-zA-Z0-9] ]]; then
echo
echo "$PROG: Error: la clave solo debe contener caracteres alfanuméricos" >&2
stty echo 2>/dev/null
exit 2
fi
echo
# Obtener confirmación clave sin eco en pantalla.
echo -n "Confirmar clave: "
read -r SAMBAPASS2
echo
stty echo 2>/dev/null
if [ "$SAMBAPASS" != "$SAMBAPASS2" ]; then
echo "$PROG: Error: las claves no coinciden" >&2
exit 2
fi
fi
# Editar la parte de acceso del cliente:
# descomprimir Initrd, sustituir clave y recomprimir Initrd).
echo "Configurando cliente \"$OGLIVE\" ..."
mkdir -p $TMPDIR
cd $TMPDIR || { echo "Error: no se pudo cambiar al directorio temporal."; exit 3; }
# Verificar si el archivo es gzip o lz4 antes de descomprimir.
if file "$CLIENTINITRD" | grep -q "gzip compressed data"; then
if ! gzip -dc "$CLIENTINITRD" | cpio -im; then
echo "Error: No se pudo descomprimir y extraer $CLIENTINITRD con gzip."
exit 4
fi
COMPRESS_CMD="gzip -9c"
elif file "$CLIENTINITRD" | grep -q "LZ4 compressed data"; then
if ! lz4 -d "$CLIENTINITRD" | cpio -im; then
echo "Error: No se pudo descomprimir y extraer $CLIENTINITRD con lz4."
exit 4
fi
COMPRESS_CMD="lz4 -c"
else
echo "Error: $CLIENTINITRD no está en formato gzip o lz4."
exit 4
fi
if [ -f scripts/ogfunctions ]; then
sed -i "s/OPTIONS=\(.*\)user=\w*\(.*\)pass=\w*\(.*\)/OPTIONS=\1user=$SAMBAUSER\2pass=$SAMBAPASS\3/" scripts/ogfunctions
# TEMPORAL: solución ticket 554, actualizar cliente en caché (ogLive r3257).
sed -i "s/busybox reboot/reboot/" scripts/ogfunctions
# FIN CÓDIGO TEMPORAL.
# Ticket 565, preparar acceso Rsync cliente.
echo "$SAMBAPASS" > scripts/passrsync
# Guardar tokens de seguridad.
cat << EOT > scripts/client.cfg
CLIENTID=$(jq -r .client.id $OGCFGFILE)
CLIENTSECRET=$(jq -r .client.secret $OGCFGFILE)
EOT
chown root.root scripts/passrsync scripts/client.cfg
chmod 400 scripts/passrsync scripts/client.cfg
# Generar Initrd del cliente.
if ! find . | cpio -H newc -oa | $COMPRESS_CMD > "$CLIENTINITRD"; then
echo "Error: No se pudo recomprimir $CLIENTINITRD."
exit 5
fi
else
echo "$PROG: Aviso: no se ha modificado la clave del cliente \"$OGLIVE\"."
fi
rm -fr $TMPDIR
# Calcular suma de comprobación.
md5sum "$CLIENTINITRD" | cut -f1 -d" " > "$CLIENTINITRD.sum"
let CHANGES++
else
echo "$PROG: Cliente \"$OGLIVE\" no accesible."
fi
done
if [[ $CHANGES != 0 ]]; then
# Ticket 565, preparar acceso Rsync servidor.
echo "$SAMBAUSER:$SAMBAPASS" > /etc/rsyncd.secrets
chown root.root /etc/rsyncd.secrets
chmod 600 /etc/rsyncd.secrets
# Cambiar clave Samba.
echo -ne "$SAMBAPASS\n$SAMBAPASS\n" | smbpasswd -a -s $SAMBAUSER
else
echo "$PROG: Aviso: no se ha modificado la clave de ningún cliente."
fi

107
composer.json 100644
View File

@ -0,0 +1,107 @@
{
"type": "project",
"license": "proprietary",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=7.2.0",
"ext-ctype": "*",
"ext-iconv": "*",
"doctrine/annotations": "^1.6",
"doctrine/doctrine-bundle": "^2.0",
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^2.7",
"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.*",
"symfony/dotenv": "5.*",
"symfony/expression-language": "5.*",
"symfony/flex": "^1.17",
"symfony/form": "5.*",
"symfony/framework-bundle": "5.*",
"symfony/http-client": "5.*",
"symfony/intl": "5.*",
"symfony/mailer": "5.*",
"symfony/mime": "5.*",
"symfony/monolog-bundle": "^3.0",
"symfony/notifier": "5.*",
"symfony/process": "5.*",
"symfony/property-access": "5.*",
"symfony/property-info": "5.*",
"symfony/security-bundle": "5.*",
"symfony/serializer": "5.*",
"symfony/string": "5.*",
"symfony/translation": "5.*",
"symfony/twig-bundle": "5.*",
"symfony/validator": "5.*",
"symfony/web-link": "5.*",
"symfony/yaml": "5.*",
"twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0"
},
"require-dev": {
"phpunit/phpunit": "^8.5",
"symfony/browser-kit": "5.*",
"symfony/css-selector": "5.*",
"symfony/debug-bundle": "5.*",
"symfony/maker-bundle": "^1.0",
"symfony/phpunit-bridge": "^5.0",
"symfony/stopwatch": "5.*",
"symfony/web-profiler-bundle": "5.*"
},
"config": {
"platform": {
"php": "7.2.24"
},
"allow-plugins": {
"composer/package-versions-deprecated": true,
"symfony/flex": true,
"symfony/runtime": true
},
"optimize-autoloader": true,
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "5.*"
}
}
}

15
config/bundles.php 100644
View File

@ -0,0 +1,15 @@
<?php
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
App\OgBootBundle\OgBootBundle::class => ['all' => true],
];

View File

@ -0,0 +1,6 @@
controllers:
resource: ../../src/OgBootBundle/Controller/
type: annotation
kernel:
resource: ../../src/Kernel.php
type: annotation

View File

@ -0,0 +1,27 @@
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
App\OgBootBundle\Controller\:
resource: '../src/OgBootBundle/Controller'
tags: ['controller.service_arguments']

View File

@ -0,0 +1,795 @@
## Diseño de la Lógica y Comunicación entre los Endpoints del Componente `ogboot` y el Servidor `ogCore`
### Introducción
El componente `ogboot` se encarga de la gestión y configuración de archivos de arranque (iPXE) y plantillas en un entorno de despliegue de imágenes. El servidor `ogCore` es el núcleo que interactúa con `ogboot` para realizar operaciones de administración y configuración. Este documento describe la lógica y la comunicación entre los endpoints del componente `ogboot` y el servidor `ogCore`.
### Endpoints del Componente `ogboot`
#### Endpoints del Recurso `oglive`
1. **Ver todos los ogLives instalados**
- **URL**: `/ogboot/v1/oglives`
- **Método HTTP**: GET
- **Descripción**: Obtiene información sobre todos los ogLives instalados.
- **Respuesta**:
```json
[
"ogLive-5.0.0-r20190605",
"ogLive-5.11.0-r20210413",
"ogLive-5.13.0-27-r20210706"
]
```
2. **Obtener Información de un ogLive**
- **URL**: `/ogboot/v1/oglives/{uuid}`
- **Método HTTP**: GET
- **Descripción**: Obtiene información sobre un cliente ogLive instalado utilizando su nombre.
- **Parámetros**:
- `uuid` (string): uuid del ogLive.
- **Respuesta**:
```json
{
"distribution": "uuid",
"distribution": "focal",
"kernel": "5.13.0-27",
"architecture": "amd64",
"revision": "r20210706.5b4bf5f",
"directory": "ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f",
"iso": "ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f.iso"
}
```
- **Respuestas**:
- **200 OK**: Información del ogLive obtenida exitosamente.
- **404 Not Found**: ogLive no encontrado.
3. **Obtener Información del ogLive Predeterminado**
- **URL**: `/ogboot/v1/oglives/default`
- **Método HTTP**: GET
- **Descripción**: Obtiene información sobre el cliente ogLive predeterminado.
- **Ejemplo de Solicitud**:
```bash
curl -X GET -H "Authorization: $API_KEY" http://example.com/ogboot/v1/oglives/default
```
- **Respuesta**:
```json
{
"distribution": "focal",
"kernel": "5.13.0-27",
"architecture": "amd64",
"revision": "r20210706.5b4bf5f",
"directory": "ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f",
"iso": "ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f.iso"
}
```
- **Respuestas**:
- **200 OK**: Información del ogLive predeterminado obtenida exitosamente.
- **500 Internal Server Error**: Error al obtener la información del ogLive predeterminado.
4. **Establecer ogLive Predeterminado**
- **URL**: `/ogboot/v1/oglives/default/{uuid}`
- **Método HTTP**: POST
- **Descripción**: Establece un cliente ogLive como predeterminado utilizando su nombre.
- **Parámetros**:
- `uuid` (string): uuid del ogLive a establecer como predeterminado.
- **Respuestas**:
- **200 OK**: ogLive establecido como predeterminado exitosamente.
- **404 Not Found**: ogLive no encontrado.
- **500 Internal Server Error**: Error al establecer el ogLive como predeterminado.
5. **Ver la lista de ogLives disponibles para descargar**
- **URL**: `/ogboot/v1/oglives/isos`
- **Método HTTP**: GET
- **Respuesta**:
```json
[
{
"id": "1",
"filename": "ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f.iso",
"installed": false,
"compatible": true
},
{
"id": "2",
"filename": "ogLive-focal-5.11.0-22-generic-amd64-r20210413.992ebb9.iso",
"installed": false,
"compatible": true
},
{
"id": "3",
"filename": "ogLive-focal-5.8.0-50-generic-amd64-r20210413.992ebb9.iso",
"installed": false,
"compatible": true
},
{
"id": "4",
"filename": "ogLive-bionic-5.4.0-40-generic-amd64-r20200629.85eceaf.iso",
"installed": false,
"compatible": true
},
]
```
- **500 Internal Server Error**: Error en la conexión.
6. **Crear un ogLive**
- **URL**: `/ogboot/v1/oglives`
- **Método HTTP**: POST
- **Descripción**: Crea un nuevo ogLive utilizando el nombre del ISO proporcionado.
- **Cuerpo de la Solicitud**:
```json
{
"isoName": "ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f.iso"
}
```
- **Ejemplo de Solicitud**:
```bash
curl -X POST -H "Authorization: $API_KEY" -d '{"isoName": "ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f.iso"}' http://example.com/ogboot/v1/oglives
```
- **Respuestas**:
- **200 OK**: ogLive creado exitosamente.
- **400 Bad Request**: Error en los datos proporcionados.
- **500 Internal Server Error**: Error al crear el ogLive.
7. **Eliminar un ogLive**
- **URL**: `/ogboot/v1/oglives/{uuid}`
- **Método HTTP**: DELETE
- **Descripción**: Elimina un ogLive específico utilizando su nombre.
- **Parámetros**:
- `name` (string): Nombre del ogLive.
- **Respuestas**:
- **200 OK**: ogLive eliminado exitosamente.
- **404 Not Found**: ogLive no encontrado.
- **500 Internal Server Error**: Error al eliminar el ogLive.
#### Endpoints del Recurso `pxe` y `pxe-template`
1. **Obtener Todos los Archivos de Arranque**
- **URL**: `/ogboot/v1/pxes`
- **Método HTTP**: GET
- **Descripción**: Obtiene una lista de todos los archivos de arranque disponibles.
- **Respuesta**: Lista de archivos de arranque en formato JSON.
2. **Obtener Configuración de Arranque**
- **URL**: `/ogboot/v1/pxes/{mac}`
- **Método HTTP**: GET
- **Descripción**: Obtiene el contenido del archivo de configuración de arranque específico para un cliente utilizando su dirección MAC.
- **Respuesta**: Archivo de arranque en formato adecuado.
```json
{
"template_name": "pxe",
"mac": "00:50:56:22:11:12",
"lang": "es_ES.UTF-8",
"ip": "192.168.2.11",
"server_ip": "192.168.2.1",
"router": "192.168.2.1",
"netmask": "255.255.255.0",
"computer_name": "pc11",
"netiface": "eth0",
"group": "Aula_virtual",
"ogrepo": "192.168.2.1",
"oglive": "192.168.2.1",
"oglog": "192.168.2.1",
"ogshare": "192.168.2.1",
"oglivedir": "ogLive",
"ogprof": "false",
"hardprofile": "",
"ogntp": "",
"ogdns": "",
"ogproxy": "",
"ogunit": "",
"resolution": "788"
}
```
3. **Crear Archivo de Arranque**
- **URL**: `/ogboot/v1/pxes`
- **Método HTTP**: POST
- **Descripción**: Crea un nuevo archivo de arranque utilizando los parámetros proporcionados.
- **Cuerpo de la Solicitud**:
```json
{
"template_name": "pxe",
"mac": "00:50:56:22:11:12",
"lang": "es_ES.UTF-8",
"ip": "192.168.2.11",
"server_ip": "192.168.2.1",
"router": "192.168.2.1",
"netmask": "255.255.255.0",
"computer_name": "pc11",
"netiface": "eth0",
"group": "Aula_virtual",
"ogrepo": "192.168.2.1",
"oglive": "192.168.2.1",
"oglog": "192.168.2.1",
"ogshare": "192.168.2.1",
"oglivedir": "ogLive",
"ogprof": "false",
"hardprofile": "",
"ogntp": "",
"ogdns": "",
"ogproxy": "",
"ogunit": "",
"resolution": "788"
}
```
- **Respuesta**: Mensaje de éxito o error.
4. **Eliminar Archivo de Arranque**
- **URL**: `/ogboot/v1/pxes/{name}`
- **Método HTTP**: DELETE
- **Descripción**: Elimina un archivo de arranque específico utilizando su dirección MAC.
- **Respuesta**: Mensaje de éxito o error.
5. **Obtener Todas las Plantillas de Arranque**
- **URL**: `/ogboot/v1/pxe-templates`
- **Método HTTP**: GET
- **Descripción**: Obtiene una lista de todas las plantillas de arranque disponibles.
- **Respuesta**: Lista de plantillas en formato JSON.
```json
{
"templates": [
"pxe",
"pxe2",
"pxe_default"
]
}
```
6. **Obtener Contenido de una Plantilla**
- **URL**: `/ogboot/v1/pxe-templates/{name}`
- **Método HTTP**: GET
- **Descripción**: Obtiene el contenido de una plantilla de arranque específica utilizando su nombre.
- **Respuesta**: Contenido de la plantilla en formato adecuado.
7. **Crear Plantilla de Arranque**
- **URL**: `/ogboot/v1/pxe-templates`
- **Método HTTP**: POST
- **Descripción**: Crea una nueva plantilla de arranque utilizando los datos proporcionados.
- **Cuerpo de la Solicitud**:
```json
{
"name_template": "pxe",
"content_template": "contenido_de_la_plantilla"
}
```
- **Respuesta**: Mensaje de éxito o error.
8. **Eliminar Plantilla de Arranque**
- **URL**: `/ogboot/v1/pxe-templates/{name}`
- **Método HTTP**: DELETE
- **Descripción**: Elimina una plantilla de arranque específica utilizando su nombre.
- **Respuesta**: Mensaje de éxito o error.
## Flujos de Trabajo
Para los nuevos flujos de trabajo, asumimos que habrá al menos una nueva tabla en ogCore para almacenar la información de los ogLives y su estado. Esta tabla permitirá a ogCore gestionar y sincronizar la información con ogBoot.
### Propuesta de definición de la tabla `ogLive`
| Atributo | Tipo de Dato | Descripción |
|----------------|----------------|-----------------------------------------------------------------|
| `id` | `SERIAL` | Identificador del ogLive que corresponde a su suma de comprobación |
| `distribution` | `VARCHAR(50)` | Nombre de la distribución del ogLive (por ejemplo, "focal"). |
| `kernel` | `VARCHAR(100)` | Versión del kernel del ogLive. |
| `architecture` | `VARCHAR(10)` | Arquitectura del ogLive (por ejemplo, "amd64"). |
| `revision` | `VARCHAR(50)` | Revisión del ogLive (por ejemplo, "r20210706"). |
| `directory` | `VARCHAR(100)` | Nombre del directorio del ogLive en el sistema de archivos. |
| `iso` | `VARCHAR(255)` | Nombre del archivo ISO del ogLive. |
| `is_default` | `BOOLEAN` | Indica si el ogLive es el predeterminado (`true` o `false`). |
### Ejemplo de Registro
| `id` | `distribution` | `kernel` | `architecture` | `revision` | `directory` | `iso` | `is_default` |
|------|----------------|---------------------|----------------|-------------|--------------------------|-------------------------------------------------------|--------------|
| 1 | focal | 5.13.0-27-beta | amd64 | r20210706 | ogLive-5.13.0-r20210706 | ogLive-focal-5.13.0-27-beta-amd64-r20210706.5b4bf5f.iso | true |
### Flujo de trabajo para instalar un `ogLive`
#### 1. Consultar los `ogLives` Instalados
- **Descripción**: Obtener la lista de `ogLives` que están actualmente instalados en el sistema.
- **Interacción en la Web**:
- El usuario navega a la sección de `ogLives` en el panel de administración.
- Hace clic en "Ver `ogLives` instalados".
- El sistema realiza una llamada a la API para obtener la lista de `ogLives` instalados.
**Realización**: Puede realizarse directamente desde **`ogCore`** mediante una consulta a la base de datos `oglives`.
**Consulta SQL**:
```sql
SELECT * FROM oglives;
```
**Endpoint**:
- **`ogBoot`**: `/ogboot/v1/oglives`
- **Método**: `GET`
#### 2. Consultar los `ogLives` disponibles para descargar
- **Descripción**: Obtener una lista de `ogLives` disponibles para descargar desde el servidor.
- **Interacción en la Web**:
- El usuario selecciona "Descargar nuevos `ogLives`" en la interfaz.
- Aparece una lista de `ogLives` disponibles, obtenida mediante una consulta al servidor.
**Realización**: Necesita comunicación con **`ogBoot`**. Nota: Este proceso requiere de una consulta a Trac (o web) que se podría llevar a cabo desde el ogCore.
**Endpoint**:
- **`ogBoot`**: `/ogboot/v1/isos`
- **Método**: `GET`
#### 3. Instalar un `ogLive`
- **Descripción**: Instalar un `ogLive` seleccionado en el sistema.
- **Interacción en la Web**:
- El usuario selecciona un `ogLive` de la lista de disponibles y hace clic en "Instalar".
- El sistema muestra un cuadro de confirmación, y al confirmar, se inicia el proceso de instalación.
**Realización**: Requiere comunicación con **`ogBoot`** para iniciar la instalación. Primero, se construye el JSON con los parámetros necesarios. La inserción en la base de datos `ogCore` solo se realiza después de que la instalación en `ogBoot` sea confirmada como exitosa.
- **Proceso de Instalación**:
1. **Generación de JSON**: `ogCore` genera un JSON con los detalles del `ogLive`, incluyendo un UUID temporal.
2. **Solicitud de Instalación**:
- **Endpoint**: `/ogboot/v1/oglives`
- **Método**: `POST`
- **Cuerpo de la Solicitud**:
```json
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"directory": "ogLive-5.11.0-r20210413",
"distribution": "focal",
"kernel": "5.11.0-22-generic",
"architecture": "amd64",
"revision": "r20210413",
"iso": "ogLive-focal-5.11.0-22-generic-amd64-r20210413.992ebb9.iso"
}
```
3. **Validación de Instalación**: `ogBoot` intenta instalar el `ogLive` y devuelve un estado de éxito o fallo.
4. **Actualización de Base de Datos**:
- **Instalación Exitosa**: Si `ogBoot` confirma el éxito, `ogCore` inserta el nuevo `ogLive` en la base de datos:
```sql
INSERT INTO oglives (uuid, distribution, kernel, architecture, revision, directory, iso, is_default)
VALUES ('550e8400-e29b-41d4-a716-446655440000', 'focal', '5.11.0-22-generic', 'amd64', 'r20210413', 'ogLive-5.11.0-r20210413', 'ogLive-focal-5.11.0-22-generic-amd64-r20210413.992ebb9.iso', false);
```
- **Instalación Fallida**: Si `ogBoot` reporta un fallo, no se realiza ninguna inserción y se maneja el error adecuadamente en la interfaz de usuario.
#### 4. Revisar un `ogLive` Instalado
- **Descripción**: Obtener detalles sobre un `ogLive` específico que está instalado.
- **Interacción en la Web**:
- El usuario selecciona un `ogLive` de la lista de instalados para ver detalles.
- Se muestra la información detallada del `ogLive` seleccionado.
**Realización**: Puede realizarse desde **`ogCore`** mediante una consulta a la base de datos `oglives`.
**Consulta SQL**:
```sql
SELECT * FROM oglives WHERE directory = 'ogLive-5.13.0-r20210706';
```
### Flujo de trabajo para cambiar el `oglive` por defecto
#### 1. Consultar los `ogLives` Instalados
- **Descripción**: Obtener la lista de `ogLives` que están actualmente instalados en el sistema.
- **Interacción en la Web**:
- El usuario navega a la sección de `ogLives` en el panel de administración.
- Hace clic en "Ver `ogLives` instalados".
- El sistema realiza una llamada a la API para obtener la lista de `ogLives` instalados.
**Realización**: Puede realizarse directamente desde **`ogCore`** mediante una consulta a la base de datos `oglives`. Lo ideal sería hacerlo hacia **`ogBoot`** ya que tiene la fuente de información fidedigna del estado de los `ogLives` en el componente.
**Consulta SQL**:
```sql
SELECT * FROM oglives;
```
**Endpoint**:
- **`ogBoot`**: `/ogboot/v1/oglives`
- **Método**: `GET`
#### 2. Ver el `ogLive` por Defecto
- **Descripción**: Obtener el `ogLive` que está configurado como predeterminado.
- **Interacción en la Web**:
- El usuario navega a la sección de configuración de `ogLives` en el panel de administración.
- Hace clic en en el `ogLive` que está marcado por defecto.
- El sistema realiza una consulta a la base de datos para obtener el `ogLive` predeterminado.
**Realización**: Puede realizarse desde **`ogCore`** mediante una consulta a la base de datos `oglives`.
**Consulta SQL**:
```sql
SELECT * FROM oglives WHERE directory = 'ogLive-5.13.0-r20210706';
```
#### 3. Asignar `ogLive` por Defecto
- **Descripción**: Configurar un `ogLive` instalado como el predeterminado.
- **Interacción en la Web**:
- El usuario selecciona un `ogLive` de la lista de instalados.
- Hace clic en "Configurar como `ogLive` por defecto".
- Tras la confirmación, el sistema envía una solicitud para actualizar el `ogLive` por defecto.
- El sistema actualiza la base de datos y comunica el cambio a `ogBoot`.
**Realización**: Requiere comunicación con **`ogBoot`** para modificar el `ogLive` por defecto en el TFTP boot del **`ogBoot`**.
**Consulta SQL**:
```sql
SELECT * FROM oglives WHERE directory = 'ogLive-5.13.0-r20210706';
```
**Endpoint**:
- **`ogBoot`**: `/ogboot/v1/oglives/default/550e8400-e29b-41d4-a716-446655440000`
- **Método**: `POST`
**Actualizar Base de Datos**:
- Tras la actualización en `ogBoot`, se debe actualizar la base de datos para reflejar el nuevo `ogLive` por defecto:
```sql
UPDATE oglives SET is_default = false WHERE is_default = true;
UPDATE oglives SET is_default = true WHERE uuid = '550e8400-e29b-41d4-a716-446655440000';
```
### Flujo de trabajo para desinstalar un `ogLive`
#### 1. Consultar los `ogLives` Instalados
- **Descripción**: Obtener la lista de `ogLives` que están actualmente instalados en el sistema.
- **Interacción en la Web**:
- El usuario navega a la sección de `ogLives` en el panel de administración.
- Hace clic en "Ver `ogLives` instalados".
- El sistema realiza una llamada a la API para obtener la lista de `ogLives` instalados.
**Realización**: Puede realizarse directamente desde **`ogCore`** mediante una consulta a la base de datos `oglives`.
**Consulta SQL**:
```sql
SELECT * FROM oglives;
```
**Endpoint**:
- **`ogBoot`**: `/ogboot/v1/oglives`
- **Método**: `GET`
#### 2. Desinstalar `ogLive`
- **Descripción**: Iniciar el proceso de desinstalación del `ogLive` seleccionado en `ogBoot`.
- **Interacción en la Web**:
- En la lista de `ogLives` instalados, el usuario elige el `ogLive` a desinstalar.
- Hace clic en el botón "Desinstalar" junto al `ogLive` seleccionado.
- El sistema muestra un cuadro de confirmación preguntando si el usuario está seguro de desinstalar el `ogLive`.
- El usuario hace clic en "Confirmar" para proceder.
- El sistema envía una solicitud a `ogBoot` para desinstalar el `ogLive`.
**Realización**:
- **Endpoint**: `/ogboot/v1/oglives/550e8400-e29b-41d4-a716-446655440000`
- **Método**: `DELETE`
- **Validación de Instalación**: `ogBoot` intenta desinstalar el `ogLive` y devuelve un estado de éxito o fallo.
- **Actualización de Base de Datos**:
- **Desinstalación Exitosa**: Si `ogBoot` confirma el éxito, `ogCore` elimina el `ogLive` en la base de datos:
```sql
DELETE FROM oglives WHERE uuid = '550e8400-e29b-41d4-a716-446655440000';
```
- **Instalación Fallida**: Si `ogBoot` reporta un fallo, no se realiza ningún borrado y se maneja el error adecuadamente en la interfaz de usuario.
### Flujo de trabajo para corregir las incongruencias entre `ogCore` y `ogBoot`
#### 8. Revisar estado de ogboot
- **Descripción**: Comparar el estado actual de `ogboot` con la base de datos de `ogCore`, generando un informe de discrepancias.
- **Realización**: Requiere comunicación con **`ogBoot`** para obtener el estado actual de los `ogLives` instalados, el `ogLive` por defecto, y las plantillas de arranque (`pxes`). Luego, `ogCore` compara estos datos con su base de datos y devuelve un informe de discrepancias.
**Endpoint**:
- **`ogBoot`**: `/ogboot/v1/oglive/status`
- **Método**: `GET`
- **Resultado de la Solicitud**:
```json
{
"installed_oglives": [
{
"name": "ogLive-5.13.0-r20210706",
"kernel": "5.13.0-27-beta",
"revision": "r20210706",
"default": true
},
{
"name": "ogLive-5.11.0-r20210413",
"kernel": "5.11.0-22-generic",
"revision": "r20210413",
"default": false
}
],
"installed_pxe_templates": [
"default.ipxe",
"template1.ipxe"
]
}
```
**Informe de Discrepancias** (Ejemplo):
```json
{
"discrepancies": {
"oglives": [
{
"expected": {
"name": "ogLive-5.13.0-r20210706",
"default": true
},
"actual": {
"name": "ogLive-5.11.0-r20210413",
"default": true
}
}
],
"pxe_templates": [
{
"expected": "default.ipxe",
"actual": "template1.ipxe"
}
]
}
}
```
#### 9. Sincronizar Datos de `ogboot` con `ogCore`
- **Descripción**: `ogCore` sincroniza su base de datos con el estado actual de `ogboot`. Este proceso solo actualiza las discrepancias detectadas.
- **Realización**: Requiere comunicación con **`ogBoot`** para obtener el estado actual. Luego, `ogCore` actualiza su base de datos con cualquier cambio detectado en los `ogLives` instalados, el `ogLive` por defecto, y las plantillas de arranque (`pxes`).
**Endpoint**:
- **`ogBoot`**: `/ogboot/v1/sync`
- **Método**: `GET`
- **Resultado de la Solicitud**:
```json
{
"installed_oglives": [
{
"name": "ogLive-5.13.0-r20210706",
"kernel": "5.13.0-27-beta",
"revision": "r20210706",
"default": true
},
{
"name": "ogLive-5.11.0-r20210413",
"kernel": "5.11.0-22-generic",
"revision": "r20210413",
"default": false
}
],
"installed_pxe_templates": [
"default.ipxe",
"template1.ipxe"
]
}
```
### Flujo de Trabajo: `pxe y pxe-template`
#### NOTA
En la implementación actual de OpenGnsys, se realiza una consulta SQL a la tabla `ordenadores`, haciendo joins con tablas como `aulas`, `centros`, `entidades`, etc. (consultar fichero `opengnsys/server/bin/setclientmode`) para obtener todos los parámetros necesarios para la creación de archivos PXE. Es necesario estudiar si existe la necesidad de crear una tabla `pxe` para almacenar estos parámetros. En caso de decidirse la creación de dicha tabla, podría tener los siguientes atributos:
- `template_name` (nombre de la plantilla)
- `mac` (dirección MAC)
- `lang` (idioma)
- `ip` (dirección IP)
- `server_ip` (dirección IP del servidor)
- `router` (router)
- `netmask` (máscara de red)
- `computer_name` (nombre del equipo)
- `netiface` (interfaz de red)
- `group` (grupo)
- `ogrepo` (IP del repositorio)
- `oglive` (IP del servidor en vivo)
- `oglog` (IP del servidor de logs)
- `ogshare` (IP del servidor compartido)
- `oglivedir` (directorio en vivo)
- `ogprof` (es profesor)
- `hardprofile` (perfil de hardware)
- `ogntp` (servidor NTP)
- `ogdns` (servidor DNS)
- `ogproxy` (servidor proxy)
- `ogunit` (directorio de unidad)
- `resolution` (resolución de pantalla)
---
#### NOTA 2
¿Tiene sentido hacer una tabla para las plantillas pxe-templates? Solo tendrian dos atributos: template-name y content. ¿No sería mejor que quedasen guardadas en el ogboot y se usen cuando se vaya a crear un fichero de arranque?
Para estos flujos asumiremos que NO se han creado tablas a mayores de pxe ni de pxe-templates. Este es el flujo original que se produce actualmente en ogboot.
1. **Obtener Todos los Archivos de Arranque**
- **URL**: `/ogboot/v1/pxes`
- **Método HTTP**: GET
- **Cuerpo de la Solicitud**:
```json
{
{
"boot_files": [
"01-00:50:56:20:69:11",
"01-00:50:56:20:69:12"
]
}
}
```
2. **Obtener Configuración de Arranque por MAC**
- **URL**: `/ogboot/v1/pxes/{mac}`
- **Método HTTP**: GET
- **Cuerpo de la Solicitud**:
- **Respuesta**:
```json
{
"template_name": "pxe",
"mac": "00:50:56:22:11:12",
"lang": "es_ES.UTF-8",
"ip": "192.168.2.11",
"server_ip": "192.168.2.1",
"router": "192.168.2.1",
"netmask": "255.255.255.0",
"computer_name": "pc11",
"netiface": "eth0",
"group": "Aula_virtual",
"ogrepo": "192.168.2.1",
"oglive": "192.168.2.1",
"oglog": "192.168.2.1",
"ogshare": "192.168.2.1",
"oglivedir": "ogLive",
"ogprof": "false",
"hardprofile": "",
"ogntp": "",
"ogdns": "",
"ogproxy": "",
"ogunit": "",
"resolution": "788"
}
```
3. **Obtener Todas las Plantillas de Arranque**
- **URL**: `/ogboot/v1/pxe-templates`
- **Método HTTP**: GET
- **Respuesta**:
```json
{
"templates": [
"pxe",
"pxe_default"
]
}
```
4. **Crear Plantilla de Arranque**
- **URL**: `/ogboot/v1/pxes-templates`
- **Método HTTP**: POST
- **Cuerpo de la Solicitud**:
```json
{
"name_template": "pxe2",
"content_template": "#!ipxe\\nset timeout 0\\nset timeout-style hidden\\n\\nset ISODIR ogLive\\nset default 0\\nset kernelargs INFOHOST\\nkernel tftp://SERVERIP/ogLive/ogvmlinuz ${kernelargs}\\ninitrd tftp://SERVERIP/ogLive/oginitrd.img\\nboot"
}
```
- **Respuesta**:
```json
{
"message": "Plantilla creada exitosamente.",
"template": "#!ipxe\\nset timeout 0\\nset timeout-style hidden\\n\\nset ISODIR ogLive\\nset default 0\\nset kernelargs INFOHOST\\nkernel tftp://SERVERIP/ogLive/ogvmlinuz ${kernelargs}\\ninitrd tftp://SERVERIP/ogLive/oginitrd.img\\nboot"
}
```
5. **Obtener Todas las Plantillas de Arranque**
- **URL**: `/ogboot/v1/pxe-templates`
- **Método HTTP**: GET
- **Respuesta**:
```json
{
"templates": [
"pxe",
"pxe2"
"pxe_default"
]
}
```
6. **Crear archivo de Arranque**
- **URL**: `/ogboot/v1/pxes`
- **Método HTTP**: POST
- **Respuesta**:
```json
{
"template_name": "pxe2",
"mac": "00:50:56:22:11:13",
"lang": "es_ES.UTF-8",
"ip": "192.168.2.11",
"server_ip": "192.168.2.1",
"router": "192.168.2.1",
"netmask": "255.255.255.0",
"computer_name": "pc13",
"netiface": "eth0",
"group": "Aula_virtual",
"ogrepo": "192.168.2.1",
"oglive": "192.168.2.1",
"oglog": "192.168.2.1",
"ogshare": "192.168.2.1",
"oglivedir": "ogLive",
"ogprof": "false",
"hardprofile": "",
"ogntp": "",
"ogdns": "",
"ogproxy": "",
"ogunit": "",
"resolution": "788"
}
```
7. **Obtener Todos los Archivos de Arranque**
- **URL**: `/ogboot/v1/pxes`
- **Método HTTP**: GET
- **Cuerpo de la Solicitud**:
```json
{
{
"boot_files": [
"01-00:50:56:20:69:11",
"01-00:50:56:20:69:12",
"01-00:50:56:20:69:13"
]
}
}
```
8. **Borrado de un fichero de arranque**
- **URL**: `/ogboot/v1/pxes/{mac}`
- **Método HTTP**: DELETE
- **Respuesta**:
```json
{
"message": "El archivo de arranque se eliminó correctamente"
}
```
9. **Borrado de una plantilla**
- **URL**: `/ogboot/v1/pxe-templates/{name}`
- **Método HTTP**: DELETE
- **Respuesta**:
```json
{
"message": "Plantilla eliminada correctamente."
}
```

65
lib/ogfunctions.sh 100755
View File

@ -0,0 +1,65 @@
#!/bin/bash
#/**
#@file ogfunctions.sh
#@brief Generic functions for OpenGnsys Server and OpenGnsys Repository.
#@version 1.1.1 - Initial version
#@author Ramón M. Gómez, ETSII Universidad de Sevilla
#@date 2017-10-08
#*/
# Showing an error message.
function raiseError() {
case "$1" in
usage)
echo "$PROG: Usage error: Type \"$PROG help\"" >&2
exit 1 ;;
notfound)
echo "$PROG: Resource not found: $2" >&2
exit 2 ;;
access)
echo "$PROG: Access error: $2" >&2
exit 3 ;;
download)
echo "$PROG: Download error: $2" >&2
exit 4 ;;
*)
echo "$PROG: Unknown error" >&2
exit 1 ;;
esac
}
# Showing help message.
function help() {
[ -n "$1" ] && DESCRIPTION="$1" || DESCRIPTION=$(grep "^#@brief" "$0" | cut -f2- -d" ")
shift
if [ -n "$1" ]; then
USAGE="$1"
shift
else
USAGE=$(grep "^#@usage" "$0" | cut -f2- -d" ")
[ -n "$USAGE" ] && PARAMS=$(awk '$1=="#@param" {sub($1,""); print "\t",$0}' "$0")
fi
# Showing help.
echo "$PROG: ${DESCRIPTION:-"no description"}"
echo "Usage: ${USAGE:-"no usage info"}"
[ -n "$PARAMS" ] && echo -e "$PARAMS"
if [ -n "$*" ]; then
echo "Examples:"
while (( "$#" )); do
echo -e "\t$1"
shift
done
fi
exit 0
}
# Metafunction to check if JSON result exists.
JQ=$(which jq 2>/dev/null) || raiseError notfound "Need to install \"jq\"."
function jq() {
local OUTPUT
OUTPUT=$($JQ "$@") || return $?
[[ "$OUTPUT" = "null" ]] && return 1
echo "$OUTPUT"
}

0
src/Controller/.gitignore vendored 100644
View File

0
src/Entity/.gitignore vendored 100644
View File

11
src/Kernel.php 100644
View File

@ -0,0 +1,11 @@
<?php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
}

View File

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
<?php
// src/OgBootBundle/OgBootBundle.php
namespace App\OgBootBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class OgBootBundle extends Bundle
{
}

View File

@ -0,0 +1,149 @@
<?php
// src/OgBootBundle/Service/CurlRequestService.php
namespace App\OgBootBundle\Service;
use Exception;
use Psr\Log\LoggerInterface;
class CurlRequestService
{
public function convertMaskToCIDR($mask)
{
$bits = 0;
$mask = explode(".", $mask);
foreach ($mask as $octect)
$bits += strlen(str_replace("0", "", decbin($octect)));
return $bits;
}
// src/Service/CurlRequestService.php
public function installOglive($isoname)
{
$socketPath = '/tmp/oglive_daemon.sock';
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
if ($socket === false) {
syslog(LOG_ERR, 'Error al crear el socket: ' . socket_strerror(socket_last_error()));
return ['success' => false, 'output' => 'Error al crear el socket'];
}
$result = socket_connect($socket, $socketPath);
if ($result === false) {
syslog(LOG_ERR, 'Error al conectar con el socket: ' . socket_strerror(socket_last_error($socket)));
socket_close($socket);
return ['success' => false, 'output' => 'Error al conectar con el socket'];
}
$command = [
'action' => 'download',
'args' => [$isoname]
];
socket_write($socket, json_encode($command), strlen(json_encode($command)));
$response = '';
$status = [];
while ($buffer = socket_read($socket, 2048)) {
$response .= $buffer;
$status[] = json_decode($buffer, true);
}
socket_close($socket);
// Analiza el último estado recibido
$lastStatus = end($status);
if ($lastStatus && $lastStatus['status'] === 'completed') {
return ['success' => true, 'output' => $lastStatus];
} else {
return ['success' => false, 'output' => $status];
}
}
public function callOgLive($parameter)
{
$socketPath = '/var/run/oglive/oglive_daemon.sock';
file_put_contents('/tmp/serviceOglive.log', 'callOgLive called with parameter: ' . $parameter . PHP_EOL, FILE_APPEND);
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
if ($socket === false) {
$error = 'Error al crear el socket: ' . socket_strerror(socket_last_error());
file_put_contents('/tmp/serviceOglive.log', 'Socket creation error: ' . $error . PHP_EOL, FILE_APPEND);
return [
'success' => false,
'error' => $error
];
}
$result = socket_connect($socket, $socketPath);
if ($result === false) {
$error = 'Error al conectar con el socket: ' . socket_strerror(socket_last_error($socket));
file_put_contents('/tmp/serviceOglive.log', 'Socket connection error: ' . $error . PHP_EOL, FILE_APPEND);
socket_close($socket);
return [
'success' => false,
'error' => $error
];
}
$args = array_map('trim', explode(' ', $parameter));
$action = array_shift($args);
$command = [
'action' => $action,
'args' => $args
];
socket_write($socket, json_encode($command), strlen(json_encode($command)));
$response = '';
while ($buffer = socket_read($socket, 2048)) {
$response .= $buffer;
}
socket_close($socket);
file_put_contents('/tmp/serviceOglive.log', 'Raw response: ' . $response . PHP_EOL, FILE_APPEND);
if (empty($response)) {
$error = 'Respuesta vacía del demonio';
file_put_contents('/tmp/serviceOglive.log', 'Empty response error: ' . $error . PHP_EOL, FILE_APPEND);
return [
'success' => false,
'error' => $error
];
}
$decodedResponse = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$error = 'Error al decodificar JSON: ' . json_last_error_msg();
file_put_contents('/tmp/serviceOglive.log', 'JSON decode error: ' . $error . PHP_EOL, FILE_APPEND);
return [
'success' => false,
'error' => $error
];
}
if (isset($decodedResponse['success']) && $decodedResponse['success']) {
file_put_contents('/tmp/serviceOglive.log', 'Decoded successful response: ' . json_encode($decodedResponse['output']) . PHP_EOL, FILE_APPEND);
return $decodedResponse['output'];
} else {
$error = $decodedResponse['error'] ?? 'Unknown error';
file_put_contents('/tmp/serviceOglive.log', 'Error in response: ' . $error . PHP_EOL, FILE_APPEND);
return [
'success' => false,
'error' => $error
];
}
}
}

0
src/Repository/.gitignore vendored 100644
View File