Paquete de software y datos con scripts autocomprimidos

A veces, necesita una forma rápida y confiable de distribuir datos o software a los usuarios sin usar un administrador de paquetes (por ejemplo, es posible que el usuario final no tenga acceso raíz para instalar una aplicación).

Este problema podría resolverse usando contenedores y Podman o Docker, pero ¿qué pasa si no están disponibles en el sistema de destino? ¿Qué ocurre si uno de los requisitos es que la aplicación se ejecute en un entorno bare metal?

Puedes usar Python con pip (y probablemente sepa que también puede empaquetar artefactos que no sean de Python), pero es posible que enfrente algunas limitaciones de instalación (un entorno virtual o el --user opción), sin mencionar que necesita un código maestro para empaqueta tu código Python.

Entonces, ¿está todo perdido? No tengas miedo ! En este artículo, demuestro una técnica muy pequeña pero eficiente para escribir un script autoextraíble que no requiere privilegios elevados.

Índice

Configura tus datos

Damiaan Zwietering tiene una genial repositorio Git sobre coronavirus con datos y visualizaciones (libros de Jupyter y hojas de cálculo de Excel), pero sin instalador. Suponga que quiere dar esto a sus usuarios, pero no tienen acceso a Git. Puede crear un instalador autoextraíble para sus usuarios.

En la vida real, ya tendría datos que desea distribuir. Pero para que tenga algunos datos de muestra con los que trabajar, primero clone este repositorio en su directorio de inicio:

$ git clone https://gitlab.com/dzwietering/corona.git

Ahora hay una gran cantidad de datos y una estructura de directorios no tan superficial, pero puede crear un archivo .tar usando el git archive pedido:

$ cd $HOME/corona
$ git archive --verbose --output $tempdir/corona.tar.gz HEAD

Para este ejemplo, este tarball es el archivo que desea compartir con sus usuarios.

La estructura del script autoextraíble.

El script autoextraíble se divide en las siguientes secciones:

  1. Código que ayuda a los usuarios a extraer datos (la "carga útil")
  2. Un ancla que separa los datos (a extraer) del script
  3. La posición del ancla para extraer los datos que vienen. después esta

Resulta que Bash es bastante bueno para definir un script de esta manera.

[ Download the free Bash shell scripting cheat sheet. ]

Crear la carga útil

He aquí una idea: digamos que los datos que necesita distribuir son un directorio con muchos scripts y también datos. Desea mantener sus permisos y estructura intactos, y desea que el usuario simplemente los "descomprima" en su directorio de inicio.

Parece un trabajo para el tar pedido. Pero, por el bien del argumento, digamos que sus usuarios no saben cómo usar tar, o quieren opciones especiales al instalar el archivo tarball (como extraer solo un archivo específico).

Otro problema es que su archivo .tar es un archivo binario. Si desea enviarlo por correo electrónico, debe codificarlo correctamente con Uuencode o Base64 para que pueda transmitirse de forma segura.

¿Que hacer? No deseche el archivo .tar todavía. En su lugar, prepárelo para que pueda añádelo a un script Bash (que escribirá en breve):

$ base64 $tempdir/corona.tar.gz > $tempdir/corona_payload
$ file $tempdir/corona_payload
/tmp/tmp.8QNdzdKEkG/corona_payload: ASCII text

Extraer datos de un archivo .tar

Puede volcar todo el contenido en un nuevo directorio:

$ newbase=$HOME/coronadata
$ test ! -d $newbase && /bin/mkdir --parents --verbose $newbase
$ tar --directory $newbase 
--file corona.tar.gz --extract --gzip --verbose

O puede extraer solo una parte, como los directorios de métricas, experimentos y pruebas:

$ newbase=$HOME/coronadata
$ test ! -d $newbase && /bin/mkdir --parents --verbose $newbase
$ tar --directory $newbase --file corona.tar.gz 
--extract --gzip --verbose measures experiment test

Para este ejercicio, extraiga todo en un directorio base (como $HOME), por lo que el resultado es:

$HOME/$COVIDUSERDIR

[ You might also be interested in More tips for packaging your Linux software with RPM. ]

Anatomía del guión autoextraíble

A continuación se muestra el código mi script autoextraíble. Puede guardar el script en su repositorio de Git y reutilizarlo para otras implementaciones. Anotar :

  • SCRIPT_END es la posición donde comienza la carga útil dentro del script
  • Desinfecta las entradas del usuario.
  • Una vez que haya determinado la posición de los metadatos, extráigalos del script ($0), decodificarlo a binario, luego descomprimirlo.
#!/usr/bin/env bash
# Author: Jose Vicente Nunez
SCRIPT_END=$(/bin/grep --max-count 2 --line-number ___END_OF_SHELL_SCRIPT___ "$0"| /bin/cut --field 1 --delimiter :| /bin/tail -1)|| exit 100
((SCRIPT_END+=1))
basedir=
while test -z "$basedir"; do
    read -r -p "Where do you want to extract the COVID-19 data, relative to $HOME? (example: mydata -> $HOME/mydata. Press CTRL-C to abort):" basedir
done
:<<DOC
Sanitize the user input. This is quite restrictive, so it depends of the real application requirements.
DOC
CLEAN=${basedir//_/}
CLEAN=${CLEAN// /_}
CLEAN=${CLEAN//[^a-zA-Z0-9_]/}
if [ ! -d "$HOME/$CLEAN" ]; then
    echo "[INFO]: Will try to create the directory $HOME/$CLEAN"
    if ! /bin/mkdir --parent --verbose "$HOME/$CLEAN"; then
        echo "[ERROR]: Failed to create $HOME/$CLEAN"
        exit 100
    fi
fi

/bin/tail --lines +"$SCRIPT_END" "$0"| /bin/base64 -d| /bin/tar --file - --extract --gzip --directory "$HOME/$CLEAN"

exit 0
# Here's the end of the script followed by the embedded file
___END_OF_SHELL_SCRIPT___

Entonces, ¿cómo se agrega la carga útil al script? Simplemente ponga las dos piezas juntas con un poco cat el pegamento:

$ cat covid_extract.sh 
$tempdir/corona_payload > covid_final_installer.sh

Hazlo ejecutable:

$ chmod u+x covid_final_installer.sh

Puedes ver cómo el el instalador se combina con la carga útil. Es grande porque contiene la carga útil.

Ejecute el instalador

¿Funciona? Pruébelo usted mismo:

$ ./covid_final_installer.sh 
Where do you want to extract the COVID-19 data, relative to /home/josevnz? (example: mydata -> /home/josevnz/mydata. Press CTRL-C to abort):COVIDDATA

[INFO]: Will try to create the directory /home/josevnz/COVIDDATA

/bin/mkdir: created directory '/home/josevnz/COVIDDATA'

$ tree /home/josevnz/COVIDDATA
/home/josevnz/COVIDDATA
├── acaps_covid19_government_measures_dataset_0.xlsx
├── acaps_covid19_government_measures_dataset.xlsx
├── COVID-19-geographic-disbtribution-worldwide.xlsx
├── EUCDC.ipynb
├── experiment
...

Los instaladores autoextraíbles son útiles

Considero que los instaladores autoextraíbles son útiles por varias razones.

En primer lugar, puedes hacerlos tan complicados o simples como quieras. La parte más compleja es dictar dónde el script debe extraer la carga útil.

Y es útil conocer esta técnica porque los instaladores de malware también pueden usarla. Ahora está mejor preparado para detectar código como este en un script. Igualmente importante, ahora sabe cómo evitar el uso indebido de la inyección de caparazón por validación de la entrada del usuario en sus propios scripts autoextraíbles.

Hay buenas herramientas para automatizar esto. Pruébelos (pero verifique su código primero).


Si quieres conocer otros artículos similares a Paquete de software y datos con scripts autocomprimidos puedes visitar la categoría Package management.

Artículos de interés

Subir

Si continuas utilizando este sitio aceptas el uso de cookies. Más información