Merge pull request 'working-installer' (#1) from working-installer into main
oginstaller/pipeline/head There was a failure building this commit Details

Reviewed-on: #1
ogrepo-keys
Nicolas Arenas 2025-01-09 15:34:01 +01:00
commit 625c464ff5
10 changed files with 956 additions and 1 deletions

View File

@ -82,7 +82,7 @@ OGBOOT_REPO="$OPENGNSYS_BASE_URL/ogboot.git"
OGCORE_REPO="$OPENGNSYS_BASE_URL/ogcore.git"
OGDHCP_REPO="$OPENGNSYS_BASE_URL/ogdhcp.git"
OGGUI_REPO="$OPENGNSYS_BASE_URL/oggui.git"
OGREPOSITORY_REPO="$OPENGNSYS_BASE_URL/ogrepo.git"
OGREPOSITORY_REPO="$OPENGNSYS_BASE_URL/ogrepository.git"
export GIT_SSL_NO_VERIFY=1
echo ======================================== > /etc/issue

View File

@ -0,0 +1,194 @@
#!/usr/bin/bash
set -x
# Paso 1: Seleccionar los componentes
# Los componentes a instalar se encuentran en el directorio /tmp/opengnsys-installer-configs
# Set configuration
COMPONENTS="ogCore ogGui ogDhcp ogBoot ogRepository"
CONFIGS_DIR=/tmp/oginstall
# PAT_FILE=/opengnsys-installer/pat.txt
# PAT=$(cat $PAT_FILE | tr -d '\n\r\t')
# OPENGNSYS_BASE_URL="https://$PAT@ognproject.evlt.uma.es/gitea/opengnsys"ls
OPENGNSYS_BASE_URL="https://ognproject.evlt.uma.es/gitea/opengnsys"
OGBOOT_REPO="$OPENGNSYS_BASE_URL/ogboot.git"
OGCORE_REPO="$OPENGNSYS_BASE_URL/ogcore.git"
OGDHCP_REPO="$OPENGNSYS_BASE_URL/ogdhcp.git"
OGGUI_REPO="$OPENGNSYS_BASE_URL/oggui.git"
OGREPOSITORY_REPO="$OPENGNSYS_BASE_URL/ogrepository.git"
export GIT_SSL_NO_VERIFY=1
## Functions
function install_docker() {
apt-get -y update
apt-get -y install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get -y update
apt-get -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable docker
}
function install_ogcore_docker() {
cat <<EOF > /etc/systemd/system/ogcore.service
[Unit]
Description=Servicio para ejecutar Docker Compose de ogCore
After=docker.service
Requires=docker.service
[Service]
WorkingDirectory=/opt/opengnsys/ogCore/repo/
ExecStart=/usr/bin/docker compose -f /opt/opengnsys/ogCore/etc/docker-compose-deploy.yml up
ExecStartPost=/opt/opengnsys/ogCore/bin/provision_ogcore.sh
ExecStop=/usr/bin/docker compose -f /opt/opengnsys/ogCore/etc/docker-compose-deploy.yml stop
Restart=always
TimeoutStartSec=600
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now ogcore
}
function install_oggui_docker() {
# Sacar la IP del ogCore de la configuración
oggui_version=$(jq -r '.release' /opt/opengnsys/ogGui/installer/config.json)
# Exportar los valores como variables de entorno
ENV_DIR=/opt/opengnsys/ogGui/etc/
ENV_FILE=$ENV_DIR/.env
cat <<EOF > /etc/systemd/system/oggui-app.service
[Unit]
Description=Servicio para contenedor Docker de OgGui
After=docker.service
Requires=docker.service
[Service]
Restart=always
ExecStartPre=/opt/opengnsys/ogGui/bin/provision_oggui.sh
ExecStart=/usr/bin/docker run --rm --name ogGui-app -p 4200:4200 -v $ENV_FILE:/app/.env opengnsys/oggui:$oggui_version
ExecStop=/usr/bin/docker stop ogGui-app
TimeoutStartSec=600
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now oggui-app
}
function git_checkout_release() {
git clone --no-checkout "$1" "$2"
cd "$2" || exit
git checkout tags/"$3"
cd - || exit
}
echo ======================================== > /etc/issue
echo "OpenGnSys Installer" >> /etc/issue
echo "Componentes instalados:" >> /etc/issue
for component in $COMPONENTS
do
config_file="config_${component}.json"
if [ -f $CONFIGS_DIR/$config_file ]; then
echo "Componente $component seleccionado, instalando configuración..."
component_dir=/opt/opengnsys/$component
mkdir -p $component_dir/installer
mkdir -p $component_dir/repo
cp $CONFIGS_DIR/$config_file /opt/opengnsys/$component/installer/config.json
case $component in
ogCore)
echo "Instalando ogCore..."
OGCORE_BRANCH=$(jq -r '.release' /opt/opengnsys/ogCore/installer/config.json)
container_version=$(jq -r '.release' /opt/opengnsys/ogCore/installer/config.json)
git_checkout_release "$OGCORE_REPO" "$component_dir/repo" "$OGCORE_BRANCH"
mkdir -p $component_dir/etc
cp $component_dir/repo/.env $component_dir/etc/
cp $component_dir/repo/env.json $component_dir/etc/
mkdir -p $component_dir/etc/
mkdir -p $component_dir/bin/
cp $CONFIGS_DIR/provision_ogcore.sh $component_dir/bin/
chmod 755 $component_dir/bin/provision_ogcore.sh
cp $component_dir/repo/docker-compose-deploy.yml $component_dir/etc/
sed -i "s/static/$container_version/g" $component_dir/etc/docker-compose-deploy.yml
cat $component_dir/etc/docker-compose-deploy.yml
echo - ogCore >> /etc/issue
install_docker
install_ogcore_docker
;;
ogGui)
echo "Instalando ogGui..."
OGGUI_BRANCH=$(jq -r '.container_version' /opt/opengnsys/ogGui/installer/config.json)
mkdir -p $component_dir/bin
cp $CONFIGS_DIR/provision_oggui.sh $component_dir/bin/
chmod 755 $component_dir/bin/provision_oggui.sh
git_checkout_release "$OGGUI_REPO" "$component_dir/repo" "$OGGUI_BRANCH"
echo - ogGui >> /etc/issue
install_docker
install_oggui_docker
;;
ogDhcp)
echo "Instalando ogDhcp..."
OGCORE_BRANCH=$(jq -r '.release' /opt/opengnsys/ogDhcp/installer/config.json)
git_checkout_release "$OGDHCP_REPO" "$component_dir/repo" "$OGCORE_BRANCH"
cp $CONFIGS_DIR/$config_file $component_dir/repo/installer/config_ogdhcp.json
cd $component_dir/repo/installer || exit
chmod 755 ogdhcp_installer.sh
./ogdhcp_installer.sh
cd - || exit
echo - ogDhcp >> /etc/issue
;;
ogBoot)
OGCORE_BRANCH=$(jq -r '.release' /opt/opengnsys/ogBoot/installer/config.json)
echo "Instalando ogBoot..."
git_checkout_release "$OGBOOT_REPO" "$component_dir/repo" "$OGCORE_BRANCH"
cp $CONFIGS_DIR/$config_file $component_dir/repo/installer/config.json
apt install -y python3 git vim
cd $component_dir/repo/installer || exit
python3 ogboot_installer.py
cd - || exit
echo - ogBoot >> /etc/issue
;;
ogRepository)
echo "Instalando ogRepository..."
OGCORE_BRANCH=$(jq -r '.release' /opt/opengnsys/ogRepository/installer/config.json)
git_checkout_release "$OGREPOSITORY_REPO" "$component_dir/repo" "$OGCORE_BRANCH"
cp $CONFIGS_DIR/$config_file $component_dir/installer/config.json
REPO_IP=$(jq -r '.ogrepository_ip' $component_dir/installer/config.json)
CORE_IP=$(jq -r '.ogcore_server_ip' $component_dir/installer/config.json)
OGUSER=$(jq -r '.ogrepository_samba_user' $component_dir/installer/config.json)
OGPASS=$(jq -r '.ogrepository_samba_pass' $component_dir/installer/config.json)
mkdir -p $component_dir/bin
cp $CONFIGS_DIR/provision_ogrepository.sh $component_dir/bin/
chmod 755 $component_dir/bin/provision_ogrepository.sh
$component_dir/bin/provision_ogrepository.sh $REPO_IP $CORE_IP $OGUSER $OGPASS $component_dir/repo
echo - ogRepository >> /etc/issue
;;
*)
echo "Componente $component no reconocido"
;;
esac
continue
fi
done
echo ======================================== >> /etc/issue
# rm -f $PAT_FILE

View File

@ -0,0 +1,52 @@
#!/bin/bash
#
set -x
CONF_DIR=/opt/opengnsys/ogCore/etc/
cd /opt/opengnsys/ogCore/repo/
# Preparar el fichero .yaml
# CONF_DIR=/opt/opengnsys/ogCore/etc/
# mkdir -p $CONF_DIR
# Copiar el fichero de configuración a CONF_DIR
# cp docker-compose-deploy.yml $CONF_DIR/
if [ -f /opt/opengnsys/ogCore/installer/.deployed ]; then
echo "ogCore ya instalado"
exit 0
fi
while ! docker compose -f $CONF_DIR/docker-compose-deploy.yml ps --format json |jq -r '"\(.Name) \(.State)"' |grep -q 'ogcore-php running'; do
sleep 2
done
adminuser=$(jq -r '.username' /opt/opengnsys/ogCore/installer/config.json)
adminpass=$(jq -r '.password' /opt/opengnsys/ogCore/installer/config.json)
docker compose -f $CONF_DIR/docker-compose-deploy.yml exec php composer install
docker compose -f $CONF_DIR/docker-compose-deploy.yml exec php php bin/console lexik:jwt:generate-keypair --overwrite
docker compose -f $CONF_DIR/docker-compose-deploy.yml exec php php bin/console doctrine:migrations:migrate --no-interaction
## TODO we need to feed $adminuser and $adminpass to doctrine:fixtures:load somehow
docker compose -f $CONF_DIR/docker-compose-deploy.yml exec php php bin/console doctrine:fixtures:load --no-interaction
# Provision user admin
bearer=$(curl -k -X 'POST' 'https://localhost:8443/auth/login' -H 'accept: application/json' -H 'Content-Type: application/json' -d "{ \"username\": \"ogadmin\", \"password\": \"12345678\" }" | jq .token | sed 's/"//g' )
if [ $adminuser == "ogadmin" ]; then
echo "Cambiando password a ogadmin no puede ser el usuario administrador"
ogadmin_uuid=$(curl -q -k -L https://localhost:8443/users/?username=ogadmin -H 'accept: application/json' -H "Authorization: Bearer $bearer" | jq .[0].uuid | sed 's/"//g')
curl -k -L -X PUT "https://localhost:8443/users/$ogadmin_uuid/reset-password" -H 'accept: application/ld+json' -H 'Content-Type: application/ld+json' -d "{\"currentPassword\": \"12345678\", \"newPassword\": \"$adminpass\", \"repeatNewPassword\": \"$adminpass\"}" -H "Authorization: Bearer $bearer"
touch /opt/opengnsys/ogCore/installer/.deployed
exit 0
fi
curl -k -L --location 'https://localhost:8443/users' \
--header 'Content-Type: application/json' \
--header "Authorization: Bearer $bearer" \
--data "{ \"username\": \"$adminuser\", \"password\": \"$adminpass\", \"roles\": [\"ROLE_SUPER_ADMIN\"] }"
touch /opt/opengnsys/ogCore/installer/.deployed
exit 0

View File

@ -0,0 +1,42 @@
#!/bin/bash
#
set -x
# preparar el fichero .env
ENV_DIR=/opt/opengnsys/ogGui/etc/
ENV_FILE=$ENV_DIR/.env
mkdir -p $ENV_DIR
# Comprobar si ya se ha instalado ogCore
if [ -f /opt/opengnsys/ogGui/installer/.deployed ]; then
echo "ogCore ya instalado"
exit 0
fi
# Sacar la IP del ogCore de la configuración
ogcore_ip=$(jq -r '.ogcore_ip' /opt/opengnsys/ogGui/installer/config.json)
export OGCORE_IP="$ogcore_ip"
# Si no se ha configurado la IP del ogCore, se intenta obtener de la interfaz de red
if [ -z "$ogcore_ip" ]; then
# Obtiene el nombre del interfaz asociado a la ruta por defecto
interface=$(ip route | grep default | awk '{print $5}')
# Si se encuentra el interfaz, obtiene su dirección IP
if [ -n "$interface" ]; then
ip_address=$(ip -o -4 addr show "$interface" | awk '{print $4}' | cut -d'/' -f1)
ogcore_ip=$ip_address
# Si no se ha configurado la IP del ogCore, se escribe en el fichero .env
echo "NG_APP_BASE_API_URL=https://$ogcore_ip:8443" > $ENV_FILE
exit 0
else
echo "No se pudo determinar el interfaz asociado a la ruta por defecto."
exit 1
fi
fi
# Si se ha configurado la IP del ogCore, se escribe en el fichero .env
echo "NG_APP_BASE_API_URL=$OGCORE_IP" > $ENV_FILE
touch /opt/opengnsys/ogGui/installer/.deployed

View File

@ -0,0 +1,104 @@
#!/bin/bash
set -e
REPO_IP=${1:-"127.0.0.1"}
CORE_IP=${2:-"127.0.0.1"}
OGUSER=${3:-"opengnsys"}
OGPASS=${4:-"og"}
INSTALL_DIR=/opt/opengnsys/ogrepository
DOWNLOAD_DIR=${5:-"/tmp/ogrepository"}
DEBIAN_FRONTEND=noninteractive
export DEBIAN_FRONTEND
export GIT_SSL_NO_VERIFY
check_root() {
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
}
install_uftp() {
apt install uftp -y
systemctl stop uftp
systemctl disable uftp
}
install_updcast () {
apt install $DOWNLOAD_DIR/packets/udpcast_20230924_amd64.deb
}
add_user_ogrepository() {
if ! id "$OGUSER" &>/dev/null; then
echo "User ogrepository does not exist, creating it"
useradd -r -s /bin/bash $OGUSER
fi
if [ ! -f /etc/sudoers.d/$OGUSER ]; then
echo "User $OGUSER does not have sudo permissions, adding it"
echo "$OGUSER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/"$OGUSER"
fi
}
create_directories() {
mkdir -p $INSTALL_DIR
mkdir -p $INSTALL_DIR/images $INSTALL_DIR/images_trash/ $INSTALL_DIR/bin/ $INSTALL_DIR/etc/ $INSTALL_DIR/log/ $INSTALL_DIR/api/
chown -R $OGUSER:$OGUSER $INSTALL_DIR
}
install_dependencies() {
apt update -y
apt install -y git python3 python3-pip python3-flask python3-paramiko python3-psutil python3-flasgger debian-archive-keyring samba gunicorn wakeonlan
}
install_ext_repo() {
cp $DOWNLOAD_DIR/installer/files/ctorrent.sources /etc/apt/sources.list.d/ctorrent.sources
apt update -y
}
install_external_packages() {
apt install -y bittorrent bittornado ctorrent
}
install_ogrepo-api_service() {
cp -r $DOWNLOAD_DIR/installer/files/ogrepo-api.service /etc/systemd/system/ogrepo-api.service
sed -i "s/%%OGREPOSITORY_USER%%/$OGUSER/g" /etc/systemd/system/ogrepo-api.service
systemctl enable --now ogrepo-api
}
install_files() {
cp -pr $DOWNLOAD_DIR/bin/* $INSTALL_DIR/bin/
cp -pr $DOWNLOAD_DIR/etc/* $INSTALL_DIR/etc/
cp -pr $DOWNLOAD_DIR/api/* $INSTALL_DIR/api/
chown -R $OGUSER:$OGUSER $INSTALL_DIR
chmod 755 $INSTALL_DIR/bin/*
echo IPlocal="$REPO_IP" > $INSTALL_DIR/etc/ogAdmRepo.cfg
echo IPcore="$CORE_IP" >> $INSTALL_DIR/etc/ogAdmRepo.cfg
sudo chown $OGUSER:$OGUSER $INSTALL_DIR/etc/ogAdmRepo.cfg
}
configure_samba() {
echo "include = /etc/samba/smb.conf.ogrepository" >> /etc/samba/smb.conf
cp $DOWNLOAD_DIR/installer/files/ogrepo-smb.conf /etc/samba/smb.conf.ogrepository
sed -i "s/%%OGREPOSITORY_USER%%/$OGUSER/g" /etc/samba/smb.conf.ogrepository
systemctl restart smbd
# Create default user ogrepository
(echo $OGPASS; echo $OGPASS) | smbpasswd -s -a $OGUSER
}
## Main program
install_dependencies
add_user_ogrepository
install_ext_repo
install_external_packages
install_uftp
install_updcast
create_directories
install_files
install_ogrepo-api_service
configure_samba

View File

@ -0,0 +1,217 @@
import npyscreen
import json
import os
from git import Repo
CONFIGS_DIR = "/tmp/oginstall"
os.makedirs(CONFIGS_DIR, exist_ok=True)
REPO_URL = "https://ognproject.evlt.uma.es/gitea/opengnsys/ogcore.git"
def get_git_tags():
try:
repo_path = os.path.join(CONFIGS_DIR, "opengnsys_repo")
if not os.path.exists(repo_path):
print("Clonando el repositorio...")
Repo.clone_from(REPO_URL, repo_path)
else:
print("Usando repositorio existente en", repo_path)
repo = Repo(repo_path)
tags = [tag.name for tag in repo.tags if tag.name.startswith("opengnsys")]
return tags
except Exception as e:
print("Error al obtener los tags:", str(e))
return []
class ComponentSelectionForm(npyscreen.ActionForm):
def create(self):
self.components = self.add(npyscreen.TitleMultiSelect, max_height=6, name="Selecciona los componentes",
values=["ogCore", "ogGui", "ogDhcp", "ogBoot", "ogRepository"], scroll_exit=True)
self.tags = get_git_tags()
self.tag = self.add(npyscreen.TitleSelectOne, max_height=10, name="Selecciona el tag",
values=self.tags, scroll_exit=True)
def beforeEditing(self):
npyscreen.blank_terminal()
def on_ok(self):
npyscreen.blank_terminal()
selected_components = [self.components.values[i] for i in self.components.value]
if not selected_components or not self.tag.value:
npyscreen.notify_confirm("Debes seleccionar al menos un componente y un tag.", title="Error")
return
selected_tag = self.tags[self.tag.value[0]]
self.parentApp.selected_components = selected_components
self.parentApp.selected_tag = selected_tag
self.parentApp.current_component_index = 0
self.parentApp.switchForm(selected_components[0])
def on_cancel(self):
if npyscreen.notify_yes_no("¿Estás seguro de que deseas salir?", title="Confirmación"):
self.parentApp.setNextForm(None)
class ComponentForm(npyscreen.ActionForm):
component_name = None
def create(self):
self.fields = {}
def beforeEditing(self):
npyscreen.blank_terminal()
self.fields.clear()
self._recreate_form()
def _recreate_form(self):
"""Limpia y recrea los widgets del formulario."""
self._clear_widgets()
self.configure_fields()
def configure_fields(self):
"""Método para definir los campos de configuración para cada componente"""
pass
def _clear_widgets(self):
"""Limpia todos los widgets del formulario."""
self._widgets__ = []
self._widgets_by_id__ = {}
self._contained_widgets = []
def validate_fields(self):
"""Validaciones personalizadas para contraseñas."""
password_field = None
confirmation_field = None
# Identificar los campos de contraseña y confirmación
for key, field_data in self.fields.items():
if field_data.get("is_password_field"):
password_field = field_data["widget"]
if field_data.get("is_password_confirmation"):
confirmation_field = field_data["widget"]
# Validar contraseñas si ambos campos están definidos
if password_field and confirmation_field:
if password_field.value != confirmation_field.value:
npyscreen.notify_confirm("Las contraseñas no coinciden. Por favor, revísalas.", title="Error")
return False
return True
def add_password_field(self, key, name, is_confirmation=False, default_value=""):
"""Añade un campo de contraseña con metadatos."""
widget = self.add(npyscreen.TitlePassword, name=name, value=default_value)
self.fields[key] = {
"widget": widget,
"is_password_field": not is_confirmation,
"is_password_confirmation": is_confirmation,
}
def on_ok(self):
if not self.validate_fields():
return # Si las validaciones fallan, no proceder
npyscreen.blank_terminal()
config_data = {"release": self.parentApp.selected_tag}
for key, field_data in self.fields.items():
config_data[key] = field_data["widget"].value
config_file = os.path.join(CONFIGS_DIR, f"config_{self.component_name}.json")
with open(config_file, "w") as f:
json.dump(config_data, f)
npyscreen.notify_confirm(f"Configuración de {self.component_name} guardada en {config_file}", title="Confirmación")
self.parentApp.current_component_index += 1
if self.parentApp.current_component_index < len(self.parentApp.selected_components):
next_component = self.parentApp.selected_components[self.parentApp.current_component_index]
self.parentApp.switchForm(next_component)
else:
self.parentApp.setNextForm(None)
def on_cancel(self):
if npyscreen.notify_yes_no("¿Estás seguro de que deseas salir?", title="Confirmación"):
self.parentApp.setNextForm(None)
class OgCoreForm(ComponentForm):
component_name = "ogCore"
def configure_fields(self):
self.fields["username"] = {"widget": self.add(npyscreen.TitleText, name="Usuario administrador (ogadmin):", value="ogadmin")}
self.add_password_field("password", "Contraseña:" , default_value="12345678")
self.add_password_field("confirm_password", "Confirmar Contraseña:", is_confirmation=True, default_value="12345678")
class OgGuiForm(ComponentForm):
component_name = "ogGui"
def configure_fields(self):
self.fields["ogcore_ip"] = {"widget": self.add(npyscreen.TitleText, name="URL Api OgCore (https://127.0.0.1:8443):", value="https://127.0.0.1:8443")}
class OgDhcpForm(ComponentForm):
component_name = "ogDhcp"
def configure_fields(self):
self.fields["ogbootIP"] = {"widget": self.add(npyscreen.TitleText, name="IP servidor de Boot (127.0.0.1):", value="127.0.0.1")}
self.fields["ogDhcpIP"] = {"widget": self.add(npyscreen.TitleText, name="IP servidor de DHCP (127.0.0.1):", value="127.0.0.1")}
self.fields["ogDhcp_Dir"] = {"widget": self.add(npyscreen.TitleText, name="Directorio de ogdhcp (/opt/opengnsys/ogdhcp):", value="/opt/opengnsys/ogdhcp")}
self.fields["interfaces"] = {"widget": self.add(npyscreen.TitleText, name="Interfaces Boot (eth0,eth1):", value="eth0,eth1")}
def on_ok(self):
if not self.validate_fields():
return # Si las validaciones fallan, no proceder
npyscreen.blank_terminal()
config_data = {"release": self.parentApp.selected_tag}
for key, field_data in self.fields.items():
if key == "interfaces":
config_data[key] = [iface.strip() for iface in field_data["widget"].value.split(",")]
else:
config_data[key] = field_data["widget"].value
config_file = os.path.join(CONFIGS_DIR, f"config_{self.component_name}.json")
with open(config_file, "w") as f:
json.dump(config_data, f)
npyscreen.notify_confirm(f"Configuración de {self.component_name} guardada en {config_file}", title="Confirmación")
self.parentApp.current_component_index += 1
if self.parentApp.current_component_index < len(self.parentApp.selected_components):
next_component = self.parentApp.selected_components[self.parentApp.current_component_index]
self.parentApp.switchForm(next_component)
else:
self.parentApp.setNextForm(None)
class OgBootForm(ComponentForm):
component_name = "ogBoot"
def configure_fields(self):
self.fields["ogCore_ServerIP"] = {"widget": self.add(npyscreen.TitleText, name="ogCore IP:", value="")}
self.fields["ogBoot_ServerIP"] = {"widget": self.add(npyscreen.TitleText, name="ogBoot Server IP:", value="")}
self.fields["ogBoot_Dir"] = {"widget": self.add(npyscreen.TitleText, name="ogCore Dir (/opt/opengnsys/ogboot):", value="/opt/opengnsys/ogboot")}
self.fields["ogLive_Default"] = {"widget": self.add(npyscreen.TitleText, name="ogLive por defecto:", value="https://ognproject.evlt.uma.es/oglive/ogLive-noble-6.8.0-31-generic-amd64-r20241128.62778c9_20241129.iso")}
self.fields["ogBootSambaUser"] = {"widget": self.add(npyscreen.TitleText, name="ogBoot Samba User (opengnsys):", value="opengnsys")}
self.add_password_field("ogBootSambaPass", "ogBoot Samba Pass (og):", default_value="og")
self.add_password_field("confirm_ogBootSambaPass", "Confirmar ogBoot Samba Pass (og):", is_confirmation=True, default_value="og")
class OgRepositoryForm(ComponentForm):
component_name = "ogRepository"
def configure_fields(self):
self.fields["ogrepository_ip"] = {"widget": self.add(npyscreen.TitleText, name="ogRepository IP:", value="127.0.0.1")}
self.fields["ogcore_server_ip"] = {"widget": self.add(npyscreen.TitleText, name="ogCoreserver IP(127.0.0.1):", value="127.0.0.1")}
self.fields["ogrepository_samba_user"] = {"widget": self.add(npyscreen.TitleText, name="Samba User:", value="opengnsys")}
self.add_password_field("ogrepository_samba_pass", "Samba Password:", default_value="og")
self.add_password_field("confirm_repository_password", "Confirmar Samba Password:", is_confirmation=True, default_value="og")
class ConfigApp(npyscreen.NPSAppManaged):
def onStart(self):
self.addForm("MAIN", ComponentSelectionForm, name="Selección de Componentes")
self.addForm("ogCore", OgCoreForm, name="Configuración de ogCore")
self.addForm("ogGui", OgGuiForm, name="Configuración de ogGui")
self.addForm("ogDhcp", OgDhcpForm, name="Configuración de ogDhcp")
self.addForm("ogBoot", OgBootForm, name="Configuración de ogBoot")
self.addForm("ogRepository", OgRepositoryForm, name="Configuración de ogRepository")
self.selected_components = []
self.selected_tag = ""
self.current_component_index = 0
if __name__ == "__main__":
app = ConfigApp()
app.run()

View File

@ -0,0 +1,220 @@
import curses
import json
import os
from git import Repo
CONFIGS_DIR = "/tmp/oginstall"
os.makedirs(CONFIGS_DIR, exist_ok=True)
REPO_URL = "https://ognproject.evlt.uma.es/gitea/opengnsys/ogcore.git"
def get_git_tags():
try:
repo_path = os.path.join(CONFIGS_DIR, "opengnsys_repo")
if not os.path.exists(repo_path):
print("Clonando el repositorio...")
Repo.clone_from(REPO_URL, repo_path)
else:
print("Usando repositorio existente en", repo_path)
repo = Repo(repo_path)
tags = [tag.name for tag in repo.tags]
if tags:
print("Tags encontrados:", tags)
else:
print("No se encontraron tags con el patrón especificado.")
return tags
except Exception as e:
print("Error al obtener los tags:", str(e))
return []
def get_password(stdscr, y, x, prompt, default=""):
stdscr.addstr(y, x, prompt, curses.color_pair(1))
password = ""
masked_password = ""
stdscr.move(y, x + len(prompt)) # Coloca el cursor después del prompt
while True:
key = stdscr.getch()
if key in (curses.KEY_BACKSPACE, 127): # Maneja el retroceso
if len(password) > 0:
password = password[:-1]
masked_password = "*" * len(password)
stdscr.move(y, x + len(prompt)) # Mueve el cursor después del prompt
stdscr.addstr(y, x + len(prompt), " " * (len(masked_password) + 1)) # Borra la línea
stdscr.addstr(y, x + len(prompt), masked_password) # Vuelve a mostrar los asteriscos actualizados
elif key == ord("\n"): # Confirmar con Enter
if not password and default: # Si el usuario no ingresó nada, usa el valor predeterminado
password = default
break
elif 32 <= key <= 126: # Rango de caracteres imprimibles
password += chr(key)
masked_password = "*" * len(password)
stdscr.addstr(y, x + len(prompt), masked_password) # Muestra asteriscos
return password
def get_input(stdscr, y, x, prompt, default=""):
max_y, max_x = stdscr.getmaxyx()
if x + len(prompt) >= max_x:
raise ValueError("El prompt es demasiado largo para caber en la pantalla.")
stdscr.addstr(y, x, prompt, curses.color_pair(1))
input_text = ""
prompt_end_x = x + len(prompt) # Calcula la posición final del prompt
stdscr.move(y, prompt_end_x) # Coloca el cursor después del prompt
while True:
key = stdscr.getch()
if key in (curses.KEY_BACKSPACE, 127): # Maneja el retroceso
if len(input_text) > 0:
input_text = input_text[:-1]
stdscr.move(y, prompt_end_x) # Mueve el cursor después del prompt
stdscr.clrtoeol() # Limpia la línea desde la posición actual hacia el final
stdscr.addstr(y, prompt_end_x, input_text) # Vuelve a mostrar el texto actualizado
stdscr.move(y, prompt_end_x + len(input_text))
elif key == ord("\n"): # Confirmar con Enter
if not input_text and default: # Usa el valor predeterminado si está vacío
input_text = default
break
elif 32 <= key <= 126: # Rango de caracteres imprimibles
if prompt_end_x + len(input_text) < max_x - 1:
input_text += chr(key)
stdscr.addstr(y, prompt_end_x, input_text) # Muestra el texto actualizado
stdscr.move(y, prompt_end_x + len(input_text)) # Mueve el cursor al final del texto
return input_text
def main(stdscr):
# Inicializar colores
curses.start_color()
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
stdscr.bkgd(' ', curses.color_pair(1))
curses.curs_set(0)
stdscr.clear()
# Paso 1: Seleccionar componentes
components = ["ogCore", "ogGui", "ogDhcp", "ogBoot", "ogRepository"]
selected_components = []
current_index = 0
# Mostrar instrucciones y opciones de componentes
stdscr.addstr(1, 2, "Selecciona los componentes (usa Flechas para navegar, Espacio para seleccionar, Enter para continuar):", curses.color_pair(1) | curses.A_BOLD)
while True:
for idx, comp in enumerate(components):
if comp in selected_components:
stdscr.addstr(idx + 3, 4, f"[X] {comp}", curses.color_pair(1))
else:
stdscr.addstr(idx + 3, 4, f"[ ] {comp}", curses.color_pair(1))
stdscr.addstr(current_index + 3, 4, f"> {components[current_index]}", curses.color_pair(1))
key = stdscr.getch()
if key == curses.KEY_UP and current_index > 0:
current_index -= 1
elif key == curses.KEY_DOWN and current_index < len(components) - 1:
current_index += 1
elif key == ord(" "):
component = components[current_index]
if component in selected_components:
selected_components.remove(component)
else:
selected_components.append(component)
elif key == ord("\n"):
break
stdscr.refresh()
# Menu de selección de releases
tags = get_git_tags()
tag_index = 0
stdscr.clear()
while True:
for idx, tag in enumerate(tags):
if idx == tag_index:
stdscr.addstr(idx + 3, 4, f"> {tag}", curses.color_pair(1))
else:
stdscr.addstr(idx + 3, 4, f" {tag}", curses.color_pair(1))
key = stdscr.getch()
if key == curses.KEY_UP and tag_index > 0:
tag_index -= 1
elif key == curses.KEY_DOWN and tag_index < len(tags) - 1:
tag_index += 1
elif key == ord("\n"):
break
stdscr.refresh()
# Configuración específica de cada componente seleccionado
curses.echo()
for component in selected_components:
stdscr.clear()
stdscr.addstr(1, 2, f"Configuración para {component}:", curses.color_pair(1) | curses.A_BOLD)
curses.curs_set(1)
config_data = {}
if component == "ogCore":
user = get_input(stdscr, 3, 0, "Usuario administrador (ogadmin): ", "ogadmin")
password = get_password(stdscr, 4, 0, "Contraseña (por defecto '12345678'): ", "12345678")
config_data = {"username": user, "password": password, "container_version": tags[tag_index]}
elif component == "ogGui":
ogcore_ip = get_input(stdscr, 3, 0, "URL Api OgCore (https://127.0.0.1:8443): " , "https://127.0.0.1:8443")
config_data = {"ogcore_ip": ogcore_ip, "container_version": tags[tag_index]}
elif component == "ogDhcp":
ogbootIP = get_input(stdscr, 3, 0, "IP servidor de Boot (127.0.0.1): ", "127.0.0.1")
ogdhcpIP = get_input(stdscr, 4, 0, "IP servidor de DHCP (127.0.0.1): ", "127.0.0.1")
ogdhcpDir = get_input(stdscr, 5, 0, "Directorio de ogdhcp (/opt/opengnsys/ogdhcp): ", "/opt/opengnsys/ogdhcp")
interfaces = get_input(stdscr, 6, 0, "Interfaces Boot (eth0,eth1): ", "eth0,eth1")
json_array_interfaces = interfaces.split(",")
config_data = {"ogbootIP": ogbootIP, "ogDhcpIP": ogdhcpIP , "ogDhcp_Dir" : ogdhcpDir , "interfaces": json_array_interfaces, "release": tags[tag_index]}
elif component == "ogBoot":
ogcore_ip = get_input(stdscr, 3, 0, "ogCore Ip Server: ", "")
ogboot_server_ip = get_input(stdscr, 4, 0, "ogBoot Server IP: ", "")
ogcore_dir = get_input(stdscr, 5, 0, "ogCore Dir (/opt/opengnsys/ogboot): ", "/opt/opengnsys/ogboot")
ogLive_default = get_input(stdscr, 6, 0, "ogLive por defecto (ogLive-noble-6.8.0-31-generic-amd64-r20241128.62778c9_20241129): ", "ogLive-noble-6.8.0-31-generic-amd64-r20241128.62778c9_20241129")
ogboot_samba_user = get_input(stdscr, 7, 0, "ogBoot Samba User (opengnsys): ", "opengnsys")
ogboot_samba_pass = get_password(stdscr, 8, 0, "ogBoot Samba Pass (og): ", "og")
config_data = {
"ogCore_ServerIP": ogcore_ip,
"ogBoot_ServerIP": ogboot_server_ip,
"ogBoot_Dir": ogcore_dir,
"ogLive_Default": "https://ognproject.evlt.uma.es/oglive/" + ogLive_default + ".iso",
"ogBootSambaUser": ogboot_samba_user,
"ogBootSambaPass": ogboot_samba_pass,
"release": tags[tag_index]
}
elif component == "ogRepository":
ogrepository_ip = get_input(stdscr, 3, 0, "ogRepository IP Server (127.0.0.1): ", "")
ogrepository_samba_user = get_input(stdscr, 4, 0, "ogRepository Sambauser (opengnsys): ", "opengnsys")
ogrepository_samba_pass = get_password(stdscr, 5, 0, "ogRepository Sambapass (og): ", "og")
config_data = {
"ogrepository_ip": ogrepository_ip,
"ogrepository_samba_user": ogrepository_samba_user,
"ogrepository_samba_pass": ogrepository_samba_pass,
"release": tags[tag_index]
}
# Guardar en archivo JSON
config_file = os.path.join(CONFIGS_DIR, f"config_{component}.json")
with open(config_file, "w") as f:
json.dump(config_data, f)
stdscr.clear()
stdscr.addstr(2, 2, f"Configuración de {component} guardada en {config_file}", curses.color_pair(1))
stdscr.refresh()
stdscr.getch()
curses.noecho() # Desactivar el eco después de la entrada
curses.wrapper(main)

View File

@ -0,0 +1,54 @@
#!/bin/bash
# Setup installer environment
BRANCH=${BRANCH:-main}
GIT_SSL_NO_VERIFY=1
GIT_REPO="https://ognproject.evlt.uma.es/gitea/api/v1/repos/opengnsys/oginstaller/archive/$BRANCH.zip"
export GIT_SSL_NO_VERIFY
install_packages() {
apt-get update
apt-get install -y curl jq unzip python3 python3-git
}
download_installer() {
rm -f /tmp/oginstaller.zip
rm -rf /tmp/oginstaller-$BRANCH
rm -rf /tmp/oginstaller
curl -q -k $GIT_REPO -H 'accept: application/json' -o /tmp/oginstaller.zip
unzip /tmp/oginstaller.zip -d /tmp
mv /tmp/oginstaller /tmp/oginstaller-$BRANCH
}
extract_installer() {
rm -rf /tmp/oginstall
mkdir -p /tmp/oginstall
cp -r /tmp/oginstaller-$BRANCH/python-installer/* /tmp/oginstall/
cp -r /tmp/oginstaller-$BRANCH/component-installer/* /tmp/oginstall/
chmod 755 /tmp/oginstall/*.sh
chmod 755 /tmp/oginstall/*.py
}
create_questions() {
echo "Creating questions..."
python3 /tmp/oginstall/oginstaller.py
}
launch_component_installer() {
echo "Launching component installer..."
/tmp/oginstall/component-installer.sh
}
install_packages
download_installer
extract_installer
create_questions
launch_component_installer

View File

@ -0,0 +1,70 @@
#!/bin/bash
# Setup installer environment
BRANCH=${BRANCH:-main}
GIT_SSL_NO_VERIFY=1
GIT_REPO="https://ognproject.evlt.uma.es/gitea/api/v1/repos/opengnsys/oginstaller/archive/$BRANCH.zip"
export GIT_SSL_NO_VERIFY
install_packages() {
apt-get update
apt-get install -y curl jq unzip python3 python3-git
}
create_python_venv() {
apt-get install -y python3-venv
python3 -m venv /tmp/oginstall/venv
source /tmp/oginstall/venv/bin/activate
pip install -r /tmp/oginstall/requirements.txt
}
download_installer() {
rm -f /tmp/oginstaller.zip
rm -rf /tmp/oginstaller-$BRANCH
rm -rf /tmp/oginstaller
curl -q -k $GIT_REPO -H 'accept: application/json' -o /tmp/oginstaller.zip
unzip /tmp/oginstaller.zip -d /tmp
mv /tmp/oginstaller /tmp/oginstaller-$BRANCH
}
extract_installer() {
rm -rf /tmp/oginstall
mkdir -p /tmp/oginstall
cp -r /tmp/oginstaller-$BRANCH/python-installer/* /tmp/oginstall/
cp -r /tmp/oginstaller-$BRANCH/component-installer/* /tmp/oginstall/
chmod 755 /tmp/oginstall/*.sh
chmod 755 /tmp/oginstall/*.py
}
create_questions() {
echo "Creating questions..."
python3 /tmp/oginstall/oginstaller-v2.py
deactivate
}
launch_component_installer() {
echo "Launching component installer..."
/tmp/oginstall/component-installer.sh
}
clean_tmp() {
rm -rf /tmp/oginstall
rm -rf /tmp/oginstaller-$BRANCH
rm -f /tmp/oginstaller.zip
}
install_packages
download_installer
extract_installer
create_python_venv
create_questions
launch_component_installer
clean_tmp

View File

@ -0,0 +1,2 @@
GitPython
npyscreen