diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ecdadc --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +venv +app/frontend/node_modules +app/venv \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..784958e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +# Usa Debian como base +FROM debian:bookworm-slim + +# Definir el directorio de trabajo +WORKDIR /app + +# Instalar dependencias necesarias +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + bash \ + curl \ + gnupg \ + apt-transport-https \ + ca-certificates && \ + rm -rf /var/lib/apt/lists/* + + + + +# Descargar e instalar code-server +RUN curl -sSL https://code-server.dev/install.sh | sh || echo "Error al instalar code-server" && \ + which code-server || echo "code-server no encontrado" && \ + code-server --version || echo "Error al obtener la versión de code-server" + + +# Exponer el puerto por defecto de code-server +EXPOSE 8080 + +# Definir el usuario y grupo de trabajo +USER root + +# Comando para iniciar code-server como root +ENTRYPOINT ["/bin/bash", "-c", "code-server /app --bind-addr 0.0.0.0:8080 --auth none -vvv"] + + diff --git a/app/utils/conocer_id_docker.sh b/app/utils/conocer_id_docker.sh new file mode 100644 index 0000000..8777244 --- /dev/null +++ b/app/utils/conocer_id_docker.sh @@ -0,0 +1,3 @@ +#!/bin/bash +# Obtener el ID del contenedor actual +cat /proc/self/cgroup | grep ":cpu:" | sed 's/.*\///' | head -n 1 | cut -c1-12 diff --git a/app/utils/extensiones_vscode.sh b/app/utils/extensiones_vscode.sh new file mode 100644 index 0000000..b2be473 --- /dev/null +++ b/app/utils/extensiones_vscode.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Lista de extensiones a instalar +EXTENSIONES=( + "ms-python.python" + "ms-python.vscode-pylance" + "ms-toolsai.jupyter" + "ms-toolsai.jupyter-keymap" + "ms-toolsai.jupyter-renderers" + "ms-toolsai.vscode-jupyter-cell-tags" + "ms-toolsai.vscode-jupyter-slideshow" +) + +# Función para instalar extensiones +instalar_extensiones() { + for EXT in "${EXTENSIONES[@]}"; do + echo "Instalando $EXT..." + code --install-extension "$EXT" + if [ $? -eq 0 ]; then + echo "✅ $EXT instalado correctamente." + else + echo "❌ Error al instalar $EXT." + fi + done +} + +# Ejecutar la instalación +instalar_extensiones +echo "🚀 ¡Instalación completada!" diff --git a/app/utils/jupyter_sistema.sh b/app/utils/jupyter_sistema.sh new file mode 100644 index 0000000..b103cb2 --- /dev/null +++ b/app/utils/jupyter_sistema.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# Actualizar repositorios +echo "Actualizando repositorios..." +apt-get update + +# Instalar compiladores y herramientas necesarias +echo "Instalando gcc, make y otras dependencias..." +apt-get install -y gcc make build-essential linux-headers-$(uname -r) python3-dev + +# Instalar Python 3, pip y virtualenv +echo "Instalando Python 3, pip y virtualenv..." +apt-get install -y python3 python3-pip python3-venv + +# Crear alias para 'python' si no existe +if ! command -v python &> /dev/null; then + echo "Creando alias para 'python'..." + ln -s /usr/bin/python3 /usr/bin/python +fi + +# Actualizar pip a la última versión globalmente +echo "Actualizando pip globalmente..." +python3 -m pip install --upgrade pip + +# Instalar wheel para facilitar la instalación de paquetes compilados +echo "Instalando wheel globalmente..." +python3 -m pip install wheel + +# Instalar Jupyter y psutil globalmente +echo "Instalando Jupyter Notebook y psutil globalmente..." +python3 -m pip install jupyter psutil + +# Crear un perfil de configuración por defecto para Jupyter +echo "Creando configuración por defecto para Jupyter..." +jupyter notebook --generate-config + +# Añadir configuración para ejecutar Jupyter sin token en localhost +CONFIG_FILE=$(jupyter --config-dir)/jupyter_notebook_config.py +echo "c.NotebookApp.ip = '0.0.0.0'" >> $CONFIG_FILE +echo "c.NotebookApp.open_browser = False" >> $CONFIG_FILE +echo "c.NotebookApp.token = ''" >> $CONFIG_FILE +echo "Configuración creada en $CONFIG_FILE" + +# Verificar la instalación +echo "Verificando la instalación..." +jupyter --version + +echo "Instalación completada exitosamente." +echo "Para iniciar Jupyter, ejecuta: jupyter notebook --allow-root" diff --git a/app/utils/node-manager.sh b/app/utils/node-manager.sh new file mode 100644 index 0000000..5570757 --- /dev/null +++ b/app/utils/node-manager.sh @@ -0,0 +1,81 @@ +#!/bin/bash +set -eu + +# 🛠 Actualizar repositorios +echo "Actualizando repositorios..." +apt-get update + +# 🛠 Instalar Node.js, NPM, y dependencias necesarias si no están instalados +echo "Instalando Node.js, NPM y dependencias necesarias..." +apt-get install -y curl python3 make g++ git libc-dev bash + +# 🛠 Instalar n (gestor de versiones de Node.js) globalmente +echo "Instalando el gestor de versiones 'n' para Node.js..." +curl -L https://raw.githubusercontent.com/tj/n/master/bin/n -o /usr/local/bin/n +chmod +x /usr/local/bin/n + +# 🛠 Eliminar versiones conflictivas de Node.js y NPM +echo "Eliminando binarios conflictivos..." +rm -f /usr/local/bin/node || true +rm -f /usr/local/bin/npm || true +rm -f /usr/local/bin/npx || true + +# 🛠 Crear directorio para versiones globales de Node.js si no existe +mkdir -p /usr/local/n +chown -R $(whoami) /usr/local/n +export N_PREFIX=/usr/local/n + +# 🛠 Agregar N_PREFIX al PATH si no está +if ! grep -q "/usr/local/n/bin" <<< "$PATH"; then + export PATH="/usr/local/n/bin:$PATH" + echo 'export PATH="/usr/local/n/bin:$PATH"' >> ~/.bashrc + source ~/.bashrc +fi + +# 🛠 Función para configurar la versión de Node.js +setup_node_version() { + local VERSION=$1 + echo "Instalando Node.js v$VERSION..." + n $VERSION + + # 🛠 Crear enlaces simbólicos globales + ln -sf /usr/local/n/bin/node /usr/local/bin/node + ln -sf /usr/local/n/bin/npm /usr/local/bin/npm + ln -sf /usr/local/n/bin/npx /usr/local/bin/npx + + # 🛠 Actualizar el PATH y limpiar caché de comandos + export PATH="/usr/local/n/bin:$PATH" + hash -r + + # 🛠 Mostrar la versión instalada + echo "Node.js actualizado a:" + node -v + npm -v +} + +# 🛠 Preguntar al usuario qué versión quiere instalar +echo "¿Qué versión de Node.js deseas instalar? (Ejemplo: 20)" +read -r NODE_VERSION + +# 🛠 Ejecutar la instalación de la versión solicitada +setup_node_version $NODE_VERSION + +# 🛠 Instrucciones para cambiar de versión rápidamente +cat << EOF + +¡Node.js v$NODE_VERSION instalado correctamente! 🎉 + +Para cambiar de versión en el futuro, usa: + n # Ejemplo: n 18 + +Para listar versiones disponibles: + n ls-remote + +Para listar versiones instaladas localmente: + n ls + +Para borrar una versión específica: + n rm # Ejemplo: n rm 18 + +¡Disfruta usando Node.js con n! 🚀 +EOF \ No newline at end of file diff --git a/app/utils/python-manager.sh b/app/utils/python-manager.sh new file mode 100644 index 0000000..ff2a39d --- /dev/null +++ b/app/utils/python-manager.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# Preguntar la versión de Python que se desea instalar +read -p "Ingresa la versión de Python que deseas establecer como global (por ejemplo, 3.11.2 o 3.8.9): " PYTHON_VERSION + +# Validar el formato de la versión ingresada (más permisivo) +if [[ ! $PYTHON_VERSION =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?([a-zA-Z0-9]+)?$ ]]; then + echo "❌ Formato inválido. Asegúrate de ingresar una versión válida (por ejemplo, 3.11.2, 3.8.9, 3.8.9b1)." + exit 1 +fi + +# Comprobar si pyenv está instalado +if ! command -v pyenv &> /dev/null; then + echo "pyenv no está instalado. Procediendo a instalarlo..." + + # Instalar dependencias para pyenv + apt-get update + apt-get install -y curl git build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libffi-dev liblzma-dev + + # Instalar pyenv + curl https://pyenv.run | bash + + # Configurar pyenv en el shell actual + export PATH="$HOME/.pyenv/bin:$PATH" + eval "$(pyenv init --path)" + eval "$(pyenv init -)" + eval "$(pyenv virtualenv-init -)" + + # Agregar pyenv al bashrc para futuros shells + echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bashrc + echo 'eval "$(pyenv init --path)"' >> ~/.bashrc + echo 'eval "$(pyenv init -)"' >> ~/.bashrc + echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc +fi + +# Verificar si la versión de Python ya está instalada con pyenv +if pyenv versions --bare | grep -q "^$PYTHON_VERSION$"; then + echo "✅ Python $PYTHON_VERSION ya está instalado." +else + # Instalar la versión solicitada de Python + echo "Instalando Python $PYTHON_VERSION con pyenv..." + pyenv install $PYTHON_VERSION + + # Comprobar si la instalación fue exitosa + if [[ $? -ne 0 ]]; then + echo "❌ Error durante la instalación de Python $PYTHON_VERSION." + exit 1 + fi +fi + + +# Establecer la versión global de Python con pyenv +echo "Configurando Python $PYTHON_VERSION como versión global..." +pyenv global $PYTHON_VERSION + +# Actualizar pip a la última versión +echo "Actualizando pip..." +pip install --upgrade pip + +# Verificar la instalación +echo "Verificando la instalación..." +python --version +pip --version + +# Recargar .bashrc para aplicar los cambios +echo "Recargando .bashrc para aplicar los cambios de pyenv..." +source ~/.bashrc + +echo "✅ Python $PYTHON_VERSION configurado como versión global exitosamente." diff --git a/app/utils/python.sh b/app/utils/python.sh new file mode 100644 index 0000000..baae0f6 --- /dev/null +++ b/app/utils/python.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Actualizar repositorios +echo "Actualizando repositorios..." +apt-get update + +# Instalar Python 3 y pip +echo "Instalando Python 3 y pip..." +apt-get install -y python3 python3-pip + +# Crear alias para 'python' si no existe +if ! command -v python &> /dev/null +then + echo "Creando alias para 'python'..." + ln -s /usr/bin/python3 /usr/bin/python +fi + +# Actualizar pip a la última versión +echo "Actualizando pip..." +python3 -m pip install --upgrade pip --break-system-packages + +# Verificar la instalación +echo "Verificando la instalación..." +python --version +pip --version + +echo "Instalación completada exitosamente." diff --git a/app/utils/react.sh b/app/utils/react.sh new file mode 100644 index 0000000..a3a026e --- /dev/null +++ b/app/utils/react.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Actualiza los repositorios y asegura que curl esté instalado +apt-get update +apt-get install -y curl + +# Verifica las versiones instaladas +echo "Node.js version:" +node -v +echo "npm version:" +npm -v + +# Crea un directorio para el proyecto +mkdir "frontend" +cd "frontend" + +# Inicializa un nuevo proyecto React +npx create-react-app . + +# Instala Material-UI y sus dependencias +npm install @mui/material @emotion/react @emotion/styled + +# Inicia el servidor de desarrollo +npm start diff --git a/app/utils/venv_python.sh b/app/utils/venv_python.sh new file mode 100644 index 0000000..f53a5ae --- /dev/null +++ b/app/utils/venv_python.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Actualizar repositorios +echo "Actualizando repositorios..." +apt-get update + +# Instalar venv si no está disponible +if ! python3 -m venv --help &> /dev/null; then + echo "Instalando venv..." + apt-get install -y python3-venv +fi + +# Crear un entorno virtual llamado 'venv' +echo "Creando entorno virtual 'venv'..." +python3 -m venv /app/venv + +echo "Entorno virtual 'venv' creado exitosamente." diff --git a/app/utils/vscode.sh b/app/utils/vscode.sh new file mode 100644 index 0000000..f7d923b --- /dev/null +++ b/app/utils/vscode.sh @@ -0,0 +1,618 @@ +#!/bin/sh +set -eu + +# code-server's automatic install script. +# See https://coder.com/docs/code-server/latest/install + +usage() { + arg0="$0" + if [ "$0" = sh ]; then + arg0="curl -fsSL https://code-server.dev/install.sh | sh -s --" + else + not_curl_usage="The latest script is available at https://code-server.dev/install.sh +" + fi + + cath << EOF +Installs code-server. +It tries to use the system package manager if possible. +After successful installation it explains how to start using code-server. + +Pass in user@host to install code-server on user@host over ssh. +The remote host must have internet access. +${not_curl_usage-} +Usage: + + $arg0 [--dry-run] [--version X.X.X] [--edge] [--method detect] \ + [--prefix ~/.local] [--rsh ssh] [user@host] + + --dry-run + Echo the commands for the install process without running them. + + --version X.X.X + Install a specific version instead of the latest. + + --edge + Install the latest edge version instead of the latest stable version. + + --method [detect | standalone] + Choose the installation method. Defaults to detect. + - detect detects the system package manager and tries to use it. + Full reference on the process is further below. + - standalone installs a standalone release archive into ~/.local + Add ~/.local/bin to your \$PATH to use it. + + --prefix + Sets the prefix used by standalone release archives. Defaults to ~/.local + The release is unarchived into ~/.local/lib/code-server-X.X.X + and the binary symlinked into ~/.local/bin/code-server + To install system wide pass --prefix=/usr/local + + --rsh + Specifies the remote shell for remote installation. Defaults to ssh. + +The detection method works as follows: + - Debian, Ubuntu, Raspbian: install the deb package from GitHub. + - Fedora, CentOS, RHEL, openSUSE: install the rpm package from GitHub. + - Arch Linux: install from the AUR (which pulls releases from GitHub). + - FreeBSD, Alpine: install from npm. + - macOS: install using Homebrew if installed otherwise install from GitHub. + - All others: install the release from GitHub. + +We only build releases on GitHub for amd64 and arm64 on Linux and amd64 for +macOS. When the detection method tries to pull a release from GitHub it will +fall back to installing from npm when there is no matching release for the +system's operating system and architecture. + +The standalone method will force installion using GitHub releases. It will not +fall back to npm so on architectures without pre-built releases this will error. + +The installer will cache all downloaded assets into ~/.cache/code-server + +More installation docs are at https://coder.com/docs/code-server/latest/install +EOF +} + +echo_latest_version() { + if [ "${EDGE-}" ]; then + version="$(curl -fsSL https://api.github.com/repos/coder/code-server/releases | awk 'match($0,/.*"html_url": "(.*\/releases\/tag\/.*)".*/)' | head -n 1 | awk -F '"' '{print $4}')" + else + # https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2758860 + version="$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/coder/code-server/releases/latest)" + fi + version="${version#https://github.com/coder/code-server/releases/tag/}" + version="${version#v}" + echo "$version" +} + +echo_npm_postinstall() { + echoh + cath << EOF +npm package has been installed. + +Extend your path to use code-server: + PATH="$NPM_BIN_DIR:\$PATH" +Then run with: + code-server +EOF +} + +echo_standalone_postinstall() { + echoh + cath << EOF +Standalone release has been installed into $STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION + +Extend your path to use code-server: + PATH="$STANDALONE_INSTALL_PREFIX/bin:\$PATH" +Then run with: + code-server +EOF +} + +echo_brew_postinstall() { + echoh + cath << EOF +Brew release has been installed. + +Run with: + code-server +EOF +} + +echo_systemd_postinstall() { + echoh + cath << EOF +$1 package has been installed. + +To have systemd start code-server now and restart on boot: + sudo systemctl enable --now code-server@\$USER +Or, if you don't want/need a background service you can run: + code-server +EOF +} + +echo_coder_postinstall() { + echoh + echoh "Deploy code-server for your team with Coder: https://github.com/coder/coder" +} + +main() { + if [ "${TRACE-}" ]; then + set -x + fi + + unset \ + DRY_RUN \ + METHOD \ + OPTIONAL \ + ALL_FLAGS \ + RSH_ARGS \ + EDGE \ + RSH + + ALL_FLAGS="" + while [ "$#" -gt 0 ]; do + case "$1" in + -*) + ALL_FLAGS="${ALL_FLAGS} $1" + ;; + esac + + case "$1" in + --dry-run) + DRY_RUN=1 + ;; + --method) + METHOD="$(parse_arg "$@")" + shift + ;; + --method=*) + METHOD="$(parse_arg "$@")" + ;; + --prefix) + STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")" + shift + ;; + --prefix=*) + STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")" + ;; + --version) + VERSION="$(parse_arg "$@")" + shift + ;; + --version=*) + VERSION="$(parse_arg "$@")" + ;; + --edge) + EDGE=1 + ;; + --rsh) + RSH="$(parse_arg "$@")" + shift + ;; + --rsh=*) + RSH="$(parse_arg "$@")" + ;; + -h | --h | -help | --help) + usage + exit 0 + ;; + --) + shift + # We remove the -- added above. + ALL_FLAGS="${ALL_FLAGS% --}" + RSH_ARGS="$*" + break + ;; + -*) + echoerr "Unknown flag $1" + echoerr "Run with --help to see usage." + exit 1 + ;; + *) + RSH_ARGS="$*" + break + ;; + esac + + shift + done + + if [ "${RSH_ARGS-}" ]; then + RSH="${RSH-ssh}" + echoh "Installing remotely with $RSH $RSH_ARGS" + curl -fsSL https://code-server.dev/install.sh | prefix "$RSH_ARGS" "$RSH" "$RSH_ARGS" sh -s -- "$ALL_FLAGS" + return + fi + + METHOD="${METHOD-detect}" + if [ "$METHOD" != detect ] && [ "$METHOD" != standalone ]; then + echoerr "Unknown install method \"$METHOD\"" + echoerr "Run with --help to see usage." + exit 1 + fi + + # These are used by the various install_* functions that make use of GitHub + # releases in order to download and unpack the right release. + CACHE_DIR=$(echo_cache_dir) + STANDALONE_INSTALL_PREFIX=${STANDALONE_INSTALL_PREFIX:-$HOME/.local} + VERSION=${VERSION:-$(echo_latest_version)} + # These can be overridden for testing but shouldn't normally be used as it can + # result in a broken code-server. + OS=${OS:-$(os)} + ARCH=${ARCH:-$(arch)} + + distro_name + + # Standalone installs by pulling pre-built releases from GitHub. + if [ "$METHOD" = standalone ]; then + if has_standalone; then + install_standalone + echo_coder_postinstall + exit 0 + else + echoerr "There are no standalone releases for $ARCH" + echoerr "Please try again without '--method standalone'" + exit 1 + fi + fi + + # DISTRO can be overridden for testing but shouldn't normally be used as it + # can result in a broken code-server. + DISTRO=${DISTRO:-$(distro)} + + case $DISTRO in + # macOS uses brew when available and falls back to standalone. We only have + # amd64 for macOS so for anything else use npm. + macos) + BREW_PATH="${BREW_PATH-brew}" + if command_exists "$BREW_PATH"; then + install_brew + else + echoh "Homebrew not installed." + echoh "Falling back to standalone installation." + npm_fallback install_standalone + fi + ;; + # The .deb and .rpm files are pulled from GitHub and we only have amd64 and + # arm64 there and need to fall back to npm otherwise. + debian) npm_fallback install_deb ;; + fedora | opensuse) npm_fallback install_rpm ;; + # Arch uses the AUR package which only supports amd64 and arm64 since it + # pulls releases from GitHub so we need to fall back to npm. + arch) npm_fallback install_aur ;; + # We don't have GitHub releases that work on Alpine or FreeBSD so we have no + # choice but to use npm here. + alpine | freebsd) install_npm ;; + # For anything else we'll try to install standalone but fall back to npm if + # we don't have releases for the architecture. + *) + echoh "Unsupported package manager." + echoh "Falling back to standalone installation." + npm_fallback install_standalone + ;; + esac + + echo_coder_postinstall +} + +parse_arg() { + case "$1" in + *=*) + # Remove everything after first equal sign. + opt="${1%%=*}" + # Remove everything before first equal sign. + optarg="${1#*=}" + if [ ! "$optarg" ] && [ ! "${OPTIONAL-}" ]; then + echoerr "$opt requires an argument" + echoerr "Run with --help to see usage." + exit 1 + fi + echo "$optarg" + return + ;; + esac + + case "${2-}" in + "" | -*) + if [ ! "${OPTIONAL-}" ]; then + echoerr "$1 requires an argument" + echoerr "Run with --help to see usage." + exit 1 + fi + ;; + *) + echo "$2" + return + ;; + esac +} + +fetch() { + URL="$1" + FILE="$2" + + if [ -e "$FILE" ]; then + echoh "+ Reusing $FILE" + return + fi + + sh_c mkdir -p "$CACHE_DIR" + sh_c curl \ + -#fL \ + -o "$FILE.incomplete" \ + -C - \ + "$URL" + sh_c mv "$FILE.incomplete" "$FILE" +} + +install_brew() { + echoh "Installing latest from Homebrew." + echoh + + sh_c "$BREW_PATH" install code-server + + echo_brew_postinstall +} + +install_deb() { + echoh "Installing v$VERSION of the $ARCH deb package from GitHub." + echoh + + fetch "https://github.com/coder/code-server/releases/download/v$VERSION/code-server_${VERSION}_$ARCH.deb" \ + "$CACHE_DIR/code-server_${VERSION}_$ARCH.deb" + sudo_sh_c dpkg -i "$CACHE_DIR/code-server_${VERSION}_$ARCH.deb" + + echo_systemd_postinstall deb +} + +install_rpm() { + echoh "Installing v$VERSION of the $ARCH rpm package from GitHub." + echoh + + fetch "https://github.com/coder/code-server/releases/download/v$VERSION/code-server-$VERSION-$ARCH.rpm" \ + "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm" + sudo_sh_c rpm -U "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm" + + echo_systemd_postinstall rpm +} + +install_aur() { + echoh "Installing latest from the AUR." + echoh + + sh_c mkdir -p "$CACHE_DIR/code-server-aur" + sh_c "curl -#fsSL https://aur.archlinux.org/cgit/aur.git/snapshot/code-server.tar.gz | tar -xzC $CACHE_DIR/code-server-aur --strip-components 1" + echo "+ cd $CACHE_DIR/code-server-aur" + if [ ! "${DRY_RUN-}" ]; then + cd "$CACHE_DIR/code-server-aur" + fi + sh_c makepkg -si --noconfirm + + echo_systemd_postinstall AUR +} + +install_standalone() { + echoh "Installing v$VERSION of the $ARCH release from GitHub." + echoh + + fetch "https://github.com/coder/code-server/releases/download/v$VERSION/code-server-$VERSION-$OS-$ARCH.tar.gz" \ + "$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz" + + # -w only works if the directory exists so try creating it first. If this + # fails we can ignore the error as the -w check will then swap us to sudo. + sh_c mkdir -p "$STANDALONE_INSTALL_PREFIX" 2> /dev/null || true + + sh_c="sh_c" + if [ ! -w "$STANDALONE_INSTALL_PREFIX" ]; then + sh_c="sudo_sh_c" + fi + + if [ -e "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION" ]; then + echoh + echoh "code-server-$VERSION is already installed at $STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION" + echoh "Remove it to reinstall." + exit 0 + fi + + "$sh_c" mkdir -p "$STANDALONE_INSTALL_PREFIX/lib" "$STANDALONE_INSTALL_PREFIX/bin" + "$sh_c" tar -C "$STANDALONE_INSTALL_PREFIX/lib" -xzf "$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz" + "$sh_c" mv -f "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION-$OS-$ARCH" "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION" + "$sh_c" ln -fs "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION/bin/code-server" "$STANDALONE_INSTALL_PREFIX/bin/code-server" + + echo_standalone_postinstall +} + +install_npm() { + echoh "Installing v$VERSION from npm." + echoh + + NPM_PATH="${YARN_PATH-npm}" + + if command_exists "$NPM_PATH"; then + sh_c="sh_c" + if [ ! "${DRY_RUN-}" ] && [ ! -w "$(NPM_PATH config get prefix)" ]; then + sh_c="sudo_sh_c" + fi + echoh "Installing with npm." + echoh + "$sh_c" "$NPM_PATH" install -g "code-server@$VERSION" --unsafe-perm + NPM_BIN_DIR="\$($NPM_PATH bin -g)" echo_npm_postinstall + return + fi + echoerr "Please install npm to install code-server!" + echoerr "You will need at least node v20 and a few C dependencies." + echoerr "See the docs https://coder.com/docs/code-server/latest/install#npm" + + exit 1 +} + +# Run $1 if we have a standalone otherwise run install_npm. +npm_fallback() { + if has_standalone; then + $1 + else + echoh "No standalone releases for $ARCH." + echoh "Falling back to installation from npm." + install_npm + fi +} + +# Determine if we have standalone releases on GitHub for the system's arch. +has_standalone() { + case $ARCH in + arm64) return 0 ;; + # We only have arm64 for macOS. + amd64) + [ "$(distro)" != macos ] + return + ;; + *) return 1 ;; + esac +} + +os() { + uname="$(uname)" + case $uname in + Linux) echo linux ;; + Darwin) echo macos ;; + FreeBSD) echo freebsd ;; + *) echo "$uname" ;; + esac +} + +# Print the detected Linux distro, otherwise print the OS name. +# +# Example outputs: +# - macos -> macos +# - freebsd -> freebsd +# - ubuntu, raspbian, debian ... -> debian +# - amzn, centos, rhel, fedora, ... -> fedora +# - opensuse-{leap,tumbleweed} -> opensuse +# - alpine -> alpine +# - arch, manjaro, endeavouros, ... -> arch +# +# Inspired by https://github.com/docker/docker-install/blob/26ff363bcf3b3f5a00498ac43694bf1c7d9ce16c/install.sh#L111-L120. +distro() { + if [ "$OS" = "macos" ] || [ "$OS" = "freebsd" ]; then + echo "$OS" + return + fi + + if [ -f /etc/os-release ]; then + ( + . /etc/os-release + if [ "${ID_LIKE-}" ]; then + for id_like in $ID_LIKE; do + case "$id_like" in debian | fedora | opensuse | arch) + echo "$id_like" + return + ;; + esac + done + fi + + echo "$ID" + ) + return + fi +} + +# Print a human-readable name for the OS/distro. +distro_name() { + if [ "$(uname)" = "Darwin" ]; then + echo "macOS v$(sw_vers -productVersion)" + return + fi + + if [ -f /etc/os-release ]; then + ( + . /etc/os-release + echo "$PRETTY_NAME" + ) + return + fi + + # Prints something like: Linux 4.19.0-9-amd64 + uname -sr +} + +arch() { + uname_m=$(uname -m) + case $uname_m in + aarch64) echo arm64 ;; + x86_64) echo amd64 ;; + *) echo "$uname_m" ;; + esac +} + +command_exists() { + if [ ! "$1" ]; then return 1; fi + command -v "$@" > /dev/null +} + +sh_c() { + echoh "+ $*" + if [ ! "${DRY_RUN-}" ]; then + sh -c "$*" + fi +} + +sudo_sh_c() { + if [ "$(id -u)" = 0 ]; then + sh_c "$@" + elif command_exists doas; then + sh_c "doas $*" + elif command_exists sudo; then + sh_c "sudo $*" + elif command_exists su; then + sh_c "su root -c '$*'" + else + echoh + echoerr "This script needs to run the following command as root." + echoerr " $*" + echoerr "Please install doas, sudo, or su." + exit 1 + fi +} + +echo_cache_dir() { + if [ "${XDG_CACHE_HOME-}" ]; then + echo "$XDG_CACHE_HOME/code-server" + elif [ "${HOME-}" ]; then + echo "$HOME/.cache/code-server" + else + echo "/tmp/code-server-cache" + fi +} + +echoh() { + echo "$@" | humanpath +} + +cath() { + humanpath +} + +echoerr() { + echoh "$@" >&2 +} + +# humanpath replaces all occurrences of " $HOME" with " ~" +# and all occurrences of '"$HOME' with the literal '"$HOME'. +humanpath() { + sed "s# $HOME# ~#g; s#\"$HOME#\"\$HOME#g" +} + +# We need to make sure we exit with a non zero exit if the command fails. +# /bin/sh does not support -o pipefail unfortunately. +prefix() { + PREFIX="$1" + shift + fifo="$(mktemp -d)/fifo" + mkfifo "$fifo" + sed -e "s#^#$PREFIX: #" "$fifo" & + "$@" > "$fifo" 2>&1 +} + +main "$@" \ No newline at end of file diff --git a/containers.json b/containers.json new file mode 100644 index 0000000..e69de29 diff --git a/eliminar_1_contenedor.py b/eliminar_1_contenedor.py new file mode 100644 index 0000000..afd3840 --- /dev/null +++ b/eliminar_1_contenedor.py @@ -0,0 +1,80 @@ +import os +import uuid +import shutil +import json +import subprocess +import hashlib +from datetime import datetime + +# Archivo JSON para guardar los datos de los contenedores +CONTAINER_DATA_FILE = 'containers.json' +# Nombre y etiqueta para la imagen base +BASE_IMAGE_TAG = 'alpine_vscode:latest' + +CONTENEDOR_IDENTIFICADOR = "easily-sound-ant" + +# ------------------------------- +# Función: Eliminar un contenedor por ID o nombre y actualizar el JSON +# ------------------------------- +def delete_container(identifier): + if not os.path.exists(CONTAINER_DATA_FILE): + print("❌ No hay archivo JSON de contenedores.") + return + + with open(CONTAINER_DATA_FILE, 'r') as file: + containers = json.load(file) + + # Determinar si el identificador es un ID o un nombre + container = next((c for c in containers if c['id'] == identifier or c['name'] == identifier), None) + if not container: + print(f"❌ No se encontró ningún contenedor con ID o nombre: {identifier} en el JSON.") + return + + try: + # Comprobar si el contenedor existe realmente en Docker + result = subprocess.getoutput(f"docker ps -a -q -f id={container['id']}") + if not result: + print(f"⚠️ El contenedor {container['name']} ya no existe en Docker. Eliminando del JSON...") + else: + # Eliminar el contenedor y su red asociada + print(f"➤ Eliminando contenedor: {container['name']} con ID: {container['id']}") + os.system(f"docker rm -f {container['id']}") + print(f"➤ Eliminando red: {container['network']}") + os.system(f"docker network rm {container['network']}") + + # Actualizar el JSON excluyendo el contenedor eliminado + containers = [c for c in containers if c['id'] != container['id']] + with open(CONTAINER_DATA_FILE, 'w') as file: + json.dump(containers, file, indent=4) + + print(f"✔ Contenedor {container['name']} eliminado correctamente.") + except Exception as e: + print(f"❌ Error eliminando el contenedor {container['name']}: {e}") + +# ------------------------------- +# Función: Limpiar imágenes huérfanas +# ------------------------------- +def clean_unused_images(): + print("➤ Eliminando imágenes huérfanas...") + os.system('docker image prune -f') + +# ------------------------------- +# Función: Limpiar redes huérfanas +# ------------------------------- +def clean_unused_networks(): + print("➤ Eliminando redes huérfanas...") + os.system('docker network prune -f') + + +if __name__ == "__main__": + identifier = CONTENEDOR_IDENTIFICADOR + + if identifier: + delete_container(identifier) + + # Limpiar imágenes y redes huérfanas + clean_unused_images() + clean_unused_networks() + + else: + print("❌ No se ingresó ningún ID o nombre.") diff --git a/eliminar_contenedores.py b/eliminar_contenedores.py new file mode 100644 index 0000000..b25e8af --- /dev/null +++ b/eliminar_contenedores.py @@ -0,0 +1,89 @@ +import os +import uuid +import shutil +import json +import subprocess +import hashlib +from datetime import datetime + +# Archivo JSON para guardar los datos de los contenedores +CONTAINER_DATA_FILE = 'containers.json' +# Nombre y etiqueta para la imagen base +BASE_IMAGE_TAG = 'alpine_vscode:latest' + + +# ------------------------------- +# Función: Eliminar todos los contenedores listados en el JSON +# ------------------------------- +def delete_all_containers(): + if not os.path.exists(CONTAINER_DATA_FILE): + print("❌ No hay contenedores para eliminar.") + return + + with open(CONTAINER_DATA_FILE, 'r') as file: + containers = json.load(file) + + if not containers: + print("❌ No hay contenedores listados en el archivo JSON.") + return + + # Lista para los contenedores que no pudieron eliminarse + remaining_containers = [] + + # Eliminar contenedores y redes + for container in containers: + try: + # Comprobar si el contenedor existe realmente + result = subprocess.getoutput(f"docker ps -a -q -f id={container['id']}") + if not result: + print(f"⚠️ El contenedor {container['name']} ya no existe. Eliminando del JSON...") + else: + print(f"➤ Eliminando contenedor: {container['name']} con ID: {container['id']}") + os.system(f"docker rm -f {container['id']}") + print(f"➤ Eliminando red: {container['network']}") + os.system(f"docker network rm {container['network']}") + except Exception as e: + print(f"❌ Error eliminando el contenedor {container['name']}: {e}") + # Guardar el contenedor en la lista si no se pudo eliminar + remaining_containers.append(container) + continue + + # Actualizar el archivo JSON solo con los contenedores que no pudieron eliminarse + if remaining_containers: + with open(CONTAINER_DATA_FILE, 'w') as file: + json.dump(remaining_containers, file, indent=4) + print("⚠️ Algunos contenedores no pudieron eliminarse y se mantuvieron en el JSON.") + else: + # Si todos los contenedores fueron eliminados, vaciar el archivo JSON + open(CONTAINER_DATA_FILE, 'w').close() + print("✔ Todos los contenedores y redes han sido eliminados y el archivo JSON ha sido limpiado.") + + +# ------------------------------- +# Función: Limpiar imágenes huérfanas +# ------------------------------- +def clean_unused_images(): + print("➤ Eliminando imágenes huérfanas...") + os.system('docker image prune -f') + +# ------------------------------- +# Función: Limpiar redes huérfanas +# ------------------------------- +def clean_unused_networks(): + print("➤ Eliminando redes huérfanas...") + os.system('docker network prune -f') + + +############################################## +# Ejecución del script +############################################## + +if __name__ == "__main__": + + # Eliminar todos los contenedores y redes + delete_all_containers() + + clean_unused_images() + clean_unused_networks() + + diff --git a/generar_contenedores.py b/generar_contenedores.py new file mode 100644 index 0000000..d0b55a7 --- /dev/null +++ b/generar_contenedores.py @@ -0,0 +1,241 @@ +import os +import uuid +import shutil +import json +import socket +import subprocess +import petname +import hashlib +import platform +from datetime import datetime + +# Archivo JSON para guardar los datos de los contenedores +CONTAINER_DATA_FILE = 'containers.json' +# Nombre y etiqueta para la imagen base +BASE_IMAGE_TAG = 'debian_vscode:tag' + +#Lita de puertos internos +PUERTOS_INTERNOS = [3000, 5000, 8000, 8080, 17000] + +# Numero de conteineres a crear +NUM_CONTAINERS = 1 + + + +# ------------------------------- +# Función: Comprobar si un puerto está libre con nmap +# ------------------------------- +def is_port_available(port): + # Ejecuta nmap para comprobar si el puerto está abierto + command = f"nmap -p {port} 127.0.0.1" + print(f"[INFO] Ejecutando nmap para el puerto {port}...") + result = subprocess.run(command, shell=True, capture_output=True, text=True) + + # Muestra el resultado del comando nmap + print(f"[DEBUG] Resultado de nmap para el puerto {port}:\n{result.stdout}") + + # Analiza el resultado para ver si el puerto está cerrado + if "closed" in result.stdout: + return True # Puerto libre + else: + return False # Puerto ocupado + + + +# ------------------------------- +# Función: Ejecutar contenedor y guardar datos +# ------------------------------- +def run_docker_compose(internal_ports=None): + # Genera un UUID único + unique_uuid = str(uuid.uuid4()) + # Genera un nombre único para el contenedor + uuid_palabras = petname.Generate(3, separator='-') + + + # Nombres únicos para el servicio, contenedor y la red + service_name = f"{uuid_palabras}" + container_name = f"{uuid_palabras}" + network_name = f"alpine_network_{unique_uuid}" + + # Nombre de la imagen local a usar + image_tag = BASE_IMAGE_TAG # Usar la imagen local directamente + + # Nombre del archivo docker-compose nuevo + new_docker_compose_file = f'docker-compose-{unique_uuid}.yml' + + try: + # Configuración personalizada de puertos + ports_mapping = [] + custom_ports = [] + host_port = 27000 # Puerto inicial + print(f"[INFO] Iniciando la configuración de puertos a partir del puerto {host_port}") + + if internal_ports: + for internal_port in internal_ports: + print(f"[INFO] Configurando puerto interno: {internal_port}") + + # Buscar el siguiente puerto disponible usando nmap + while host_port <= 65000: + if is_port_available(host_port): + print(f"[INFO] Asignando puerto {host_port} para el puerto interno {internal_port}...") + custom_ports.append(f" - \"{host_port}:{internal_port}\"") + ports_mapping.append({ + "host_port": host_port, + "internal_port": internal_port + }) + host_port += 1 # Incrementa el puerto para el siguiente uso + break + else: + print(f"[WARNING] Puerto {host_port} ocupado, probando el siguiente...") + host_port += 1 # Incrementa si el puerto está ocupado + + if host_port > 65000: + raise Exception("Se superó el límite de puertos disponibles.") + + custom_ports_yaml = "\n".join(custom_ports) + print(f"[INFO] Puertos personalizados configurados:\n{custom_ports_yaml}") + else: + custom_ports_yaml = "" # No agrega puertos si no se especifican + print("[INFO] No se especificaron puertos internos.") + + # Genera el contenido del archivo docker-compose dinámicamente + docker_compose_content = f""" +version: '3.8' + +services: + {service_name}: + image: {image_tag} # Usar la imagen base directamente + container_name: {container_name} + networks: + - {network_name} + restart: always + tty: true + volumes: + - ./app:/app + ports: +{custom_ports_yaml} + command: tail -f /dev/null # Mantener activo el contenedor + +networks: + {network_name}: + driver: bridge +""" + + # Guarda el archivo docker-compose generado + with open(new_docker_compose_file, 'w') as file: + file.write(docker_compose_content) + + # Muestra el contenido generado para depuración + print(f"[DEBUG] Contenido del archivo {new_docker_compose_file}:\n") + print(docker_compose_content) + + # Ejecuta docker-compose con el archivo nuevo y captura la salida + print("[INFO] Ejecutando docker compose...") + result = subprocess.run( + f'docker compose -f {new_docker_compose_file} up -d --no-build', + shell=True, + capture_output=True, + text=True + ) + + # Muestra el resultado del comando + if result.returncode != 0: + print(f"[ERROR] Error al ejecutar docker compose:\n{result.stderr}") + raise Exception("Error al ejecutar docker-compose") + else: + print(f"[INFO] Contenedor iniciado exitosamente:\n{result.stdout}") + + # Mostrar contenedores activos y detenidos + print("[DEBUG] Contenedores activos y detenidos:") + subprocess.run("docker ps -a", shell=True) + + # Obtener el ID del contenedor creado + container_id = subprocess.getoutput(f"docker ps -qf name={container_name}") + if not container_id: + print(f"[ERROR] No se pudo obtener el ID del contenedor {container_name}.") + raise Exception("No se pudo obtener el ID del contenedor") + + print(f"[INFO] ID del contenedor: {container_id}") + + # Mostrar logs del contenedor si está detenido + print("[INFO] Mostrando logs del contenedor:") + subprocess.run(f"docker logs {container_id}", shell=True) + + # Guardar los datos del contenedor en el archivo JSON + save_container_data({ + 'id': container_id, + 'name': container_name, + 'network': network_name, + 'image': image_tag, + 'compose_file': new_docker_compose_file, + 'creation_timestamp': datetime.now().isoformat(), + 'ports': ports_mapping # Agrega la información de los puertos mapeados + }) + + except Exception as e: + print(f"[ERROR] Error: {str(e)}") + + finally: + # Eliminar el archivo docker-compose generado si existe + if os.path.exists(new_docker_compose_file): + print(f"[INFO] Eliminando archivo temporal: {new_docker_compose_file}") + os.remove(new_docker_compose_file) + + + +# ------------------------------- +# Función: Guardar datos del contenedor en JSON +# ------------------------------- +def save_container_data(container_data): + # Cargar datos existentes si el archivo existe y no está vacío + if os.path.exists(CONTAINER_DATA_FILE) and os.path.getsize(CONTAINER_DATA_FILE) > 0: + with open(CONTAINER_DATA_FILE, 'r') as file: + try: + data = json.load(file) # Cargar datos existentes + except json.JSONDecodeError: + data = [] # Si hay error al leer, inicializar como lista vacía + else: + # Crear el archivo vacío y usar una lista vacía + with open(CONTAINER_DATA_FILE, 'w') as file: + json.dump([], file) + data = [] # Inicializar como lista vacía + + # Agregar nuevo contenedor + data.append(container_data) + + # Guardar datos actualizados + with open(CONTAINER_DATA_FILE, 'w') as file: + json.dump(data, file, indent=4) + + + +# ------------------------------- +# Función: Limpiar imágenes huérfanas +# ------------------------------- +def clean_unused_images(): + print("➤ Eliminando imágenes huérfanas...") + os.system('docker image prune -f') + +# ------------------------------- +# Función: Limpiar redes huérfanas +# ------------------------------- +def clean_unused_networks(): + print("➤ Eliminando redes huérfanas...") + os.system('docker network prune -f') + + +######################################### ------------------------------- +# Ejecución del script +######################################### ------------------------------- +if __name__ == "__main__": + + + # Crear contenedores y guardarlos en el JSON + for _ in range(NUM_CONTAINERS): + run_docker_compose(internal_ports=PUERTOS_INTERNOS) + print("➤ Contenedores creados y guardados en el JSON") + + # Limpiar imágenes huérfanas + clean_unused_images() + # Limpiar redes huérfanas + clean_unused_networks()