Mostrando entradas con la etiqueta shell. Mostrar todas las entradas
Mostrando entradas con la etiqueta shell. Mostrar todas las entradas

martes, 19 de noviembre de 2024

Python (XII) Ejecutar un fichero sh (bash de linux) que utilice un entorno virtual y ejecute un programa python. Ojo con los parámetros tipo "regex pattern"!!!

1. Introducción

Pasos:

  1. Desde el programa python creamos un array que contenga la ruta del script (bash de linux) como primer componente. Cada componente restante estará formada por la cadena "clave=valor", donde las comillas dobles forman parte del parámetro. Ojo los espacios en blanco pueden dar problemas, para ello se pueden sustituir por algúna cadena , en mi caso he utilizado "¬spc¬"(sin colillas dobles)
  2. Desde el script de linux verificamos que recibimos obligatoriamente los parámetros "folder", "module","funcion" y "venv". Siendo "folder" la carpeta donde tenemos que situarnos, "venv" la carpeta dentro de folder donde está el entrono virtual, "module" el módulo a llamar y "function" la función del módulo a ejecutar. En el script cambiamos a la carpeta definida en la variable "folder" y activamos el entorno virtual de la variable "venv" y ejecutamos  pyton xmexec.py "module=miModulo" "function=miFuncion" ..... 
  3. El módulo xmexec.py que se encuentra en la carpeta "folder" se encarga de recibir los parámetros, arreglar los mismos sustituyendo "¬spc¬" por espacios en blanco, cargando el módulo indicado en el parámetro "module" y ejecutando la función indicada  "function".

2. Llamada al script desde python

Para ello supongamos que tenemos un diccionario con el nombre del script, del módulo, función a ejecutar, entorno virtual y otros parámetros.
Sustituimos los espacios en blanco por "¬spc¬" y construimos el array para llamar a "subproces.run".
Observar que el modulo se puede definir como:
  • "carpeta.modulo" ó
  • "carpeta/modulo.py"
siendo "carpeta" la carpeta que contien a "modulo.py" que vamos a llamar

El script a llamar está en la carpeta "static/scripts" y se llama "execShell.sh"


import subprocess

# Diccionario que contiene los parámetros PARA EL SHELL SCRIPT
execDict={
	'shell':'static/scripts/execShell.sh',
	'folder':'../02.llibreries',
	'venv':'/static/scripts/llibreries.sh',
	'module':'eni/xmexpeni.py',
	#'module':'eni.xmexpeni',
	'function':'expedientENI',
	'param1':'1814787N',
	'param2':12,
	'param3':'TD02',
	'param4':'INDEX_ACTES_PLE',
	'param5':'ENIExpTemplate.xml',
}

if __name__ == '__main__':
	# Recogemos la ruta del shell y lo quitamos del diccionario
	myShell=execDict['shell']
	del execDict['shell']
	execProgs=[myShell]
	
	#Creamos la cadena con los parámetros paraejecuar
	for key,value in execDict.items():
		value1=value.replace(" ","¬spc¬")
		st=f'"{key}={value1}"'
		execProgs.append(st) #Exec progs.

	print(str(subprocess.run(execProgs, capture_output=True)))


3. Llamada al programa xmexec.

Desde el script vamos a llamar al programa pyhon xmexec, paa ello:
  1. Verificamos que recibimos los parámetros "folder", "venv", module" y "function"
  2. Nos situamos a la carpeta del parámetro "folder"
  3. Activamos el entorno virtual de la carpeta indicada en el parámetro "venv"
  4. Ejecutamos "python" al que pasamos el propgrama xmexec.py y el resto de parámetros (excepto "venv" y "folder") 
#!/bin/bash

#--------------------------
# 0. Exemple de crida
# ./static/scripts/llibreries.sh \
#  "folder=../02.llibreries" "venv=venv02" \
#  "module=eni.xmexpeni" "function=expedientENI" \
#  "docsFolderPath=docs/actes2022/" \
#  "templatesPath=templates/ENI/" \
#  "filter=*ord*aprov*sio*_signed.pdf" \
#  "anyPle=2022" \
#  "expCodi=1814787N" \
#  "organo=L01462384" \
#  "tDocu=TD02" \
#  "prefPle=INDEX_ACTES_PLE" \
#  "plantillaXML=ENIExpTemplate.xml" \
#  "docxIndex=indexTemplate.docx"
#
#
# O també podriem executar en background
# Run the Python script in the background
#  nohup python myscript.py > /dev/null 2>&1 &
#
#---------------------------

remove_quotes() {
    local arg="$1"
	# Remove leading double quote if present
    arg="${arg#\"}"
	# Remove leading double quote if present
    arg="${arg%\"}"
    echo "$arg"
}

#------------------------------------
# 1. Recogemos los parametros
#------------------------------------

# Inicialize variables
folder_value=""
venv_value=""
module_value=""
other_params=""

# Función para mostrar uso del script
usage() {
  echo "Uso: $0 'folder=RUTA'  'venv=carpeta entorno virtual' 'module=carpeta.modulo.py'  ... otros_parametros=VALOR ..."
  echo "Ejemplo:"
  echo "  $0 folder=/mi/carpeta env=producción venv=venv02 module=eni.xmexpeni config=ejemplo version=1.0"
  exit 1
}

# Verificar si se proporcionaron argumentos
if [ $# -lt 3 ]; then
  usage
fi

# Procesar cada argumento
for argIni in "$@"; do
  # Remover comillas
  arg=$(remove_quotes "$argIni")
  
  # Verificar si el argumento contiene un '='
  if [[ "$arg" == *=* ]]; then
    # Dividir el argumento en clave y valor
    key="${arg%%=*}"
    value="${arg#*=}"
	#echo "$key    AAAA   $value  AAAAA  $arg"
	
    case "$key" in
      folder)
        folder_value="$value"
        ;;
      venv)
        venv_value="$value"
        ;;
	  module) 
        module_value="$arg"
		;;
      *)
        # Concatenar otros parámetros
        other_params+=" \"$arg\""
        ;;
    esac
	#echo "$key    BBBBB   $value"
  else
    echo "Argumento inválido: $arg"
    usage
  fi
done

#echo "FOLDER=  $folder_value"
#echo "VENV= $venv_value"
#echo "MODULE= $module_value"

# Verificar que 'folder' y 'env' hayan sido proporcionados
if [[ -z "$folder_value" || -z "$venv_value" || -z "$module_value" ]]; then
  echo "Error: Se requieren al menos un argumento 'folder' 'venv'y 'module'."
  usage
fi


#--------------------------------------
# 2. Nos cambiamos a la carpeta del modulo
#-------------------------------------
pwd
cd "$folder_value"
pwd

#--------------------------------------
# 3. Activamos el entorno virtual
#-------------------------------------
source "$venv_value"/bin/activate


# Crear la cadena concatenada
final_string1="python xmexec.py \"${module_value}\" ${other_params}"
echo "--------------------------------------"
echo "FINAL STRING=$final_string1"
echo "--------------------------------------"
python xmexec.py \"${module_value}\" ${other_params}


4. Verificar que la carpeta del entrono virtual "venv" está creado dentro de la carpteta "folder"


5. Crear el programa python "xmexec.py" en la crpeta folder.

Este programa:
  1. Recoge los argumentos y cambia "¬spc¬ por espacio " "
  2. Carga el módulo "module" y
  3. Ejecuta la función con el diccionario que recoge todos los parámetrso menos "module" y "function" 
'''
Execute a function from a module
paramenters:
	"module= module name"
	"function= function name"		
	"param1 = value1"
	"param2 = value2"
	"param_n = value_n"

'''
import importlib
import sys

requiredProps=['module','function']

def arreglaArg(arg:str)->str:
	if arg.startswith('"') or arg.startswith("'"):
		arg=arg[1:] 
	if arg.endswith('"') or arg.endswith("'"): 
		arg=arg[:-1]
	arg=arg.replace('¬spc¬',' ')	
	return arg

if __name__ == '__main__':
	argDict={}
	for i, arg1 in enumerate (sys.argv):
		arg=arreglaArg(arg1)
		#print(i, "--", arg1, '===', arg)
		if i>0:
			aArg=arg.split('=')
			#print(aArg)
			argDict[aArg[0]]=aArg[1]
			

	keys=argDict.keys()
	for prop in requiredProps:
		if prop not in keys:
			raise Exception (prop + ' not in arguments')
		
	moduleName=argDict['module'].replace('.py','').replace("/",".")
	#print (moduleName)
	#module = __import__(argDict['module']) # No acaba d'anar be
	module = importlib.import_module(moduleName)
	#print (module)
	aFunc=argDict['function']
	func = getattr(module, aFunc)
	
	# Remove module and function props
	for prop in requiredProps: del argDict[prop]


	# Execute the function with arguments
	#print ("executing the function "+ aFunc)
	#print (argDict)
	#print ("=======================================================")
	func (**argDict)
	

6. Verificaciones

Verificar que :
  1. Exista el módulo dentro de la carpeta correcta
  2. Que el módulo tenga la funcion que vamos a llamar
  3. Que los parámetros de la fucnión tengan los mismos nombres y sean del mismo tipo que los parámetros que le pasamos.

7. Parámetros regex pattern


Si los parámetros "regex pattern" pueden estar definidos en un fichero u¡yaml o dentro del programa python

Por ejemplo en este fichero yaml hay 2 elementos tipo pattern.

pattern1: '^Ple \d{2} ord \d{2}-\d{2}-\d{4} .* \d{2} \d{2} \d{4}(?:_|\.)signed(?:_|\.)signed\.pdf$'

params: [1, '^Acta d{2} .* \d{2} \d{2} \d{4}.pdf$', 'otro valor']

Para el caso de der definidos en un progama python vale la pena  utilizar un string "rau" que se hace  anteponiendo r al string

pattern = r'^Acta d{2} .* \d{2} \d{2} \d{4}.pdf$'


Los posibles problemas que pueden aparecer son:
  1. Las interrogaciones "?"
  2. Los espacios en blanco
Las interrogaciones pueden dar problemas al convertirlas en una cadena dela URL, mientras que los espacios en blanco pueden dar problemas al pasarlos a un script como parámetro, pues los trocea. 

Para el caso de las interrogaciones, se puede pasar el parámetro codificado en base64 y a veces aún así puede fallar. A un caso se pueden cambiar por "¬qm¬" y luego deshacer el cambio. Para el caso de los espacios hemos optado por sustituirlos por "¬spc¬".
 



miércoles, 8 de diciembre de 2021

Instalar certificado LetsEncrypt en Tomcat Ubuntu manual. Shell de actualización del certificado

 0. Introducción

Vamos a seguir a Mahdi Mashrur Matin a ver si esta vez sale bien. 

1. Prerequisitos

  • Tener privilegio de superusuario
  • Tener un dominio registrado ("webprop.es" en mi caso)
  • Versión de Java reciente instalada
  • Versión reciente de Tomcat instalada
  • Tener abiertos los puertos 80 y 8443 en el firewall
  • Tener instalado Openssl

2. Instalar Certbot

Tal como vimos en el fallido blog anterior, primero añadimos al repositorio

  • sudo add-apt-repository ppa:certbot/certbot

Instalamos el paquete Apache Certbot

  • sudo apt install python-certbot-apache


3. Genera keypair y el certificado sobre el dominio con Certbot.


En el fallido blog anterior, estos ficheros si que los tenemos (por tanto podemos saltar este paso). 

Para los que no hayais pasado por el blog anterior, debeis ejecutar:

sudo certbot certonly --standalone -d myweb.es

Y si toda ha ido bien, en el directorio /etc/letsencrypt/live/myweb.es (OJO: normalmente las direcciones suelen ser "csv.rocasdemar.es"  o algo por el estilo, siendo el directorio /etc/letsencrypt/live/csv.rocasdemar.es) Deben existir estos ficheros:
  • cert.pem (certificado "solo")
  • chain.pem (cadena de certificados del root)
  • fullchain.pem (certificado "solo" + cadena de certificados del root. Equivale a los 2 ficheros anteriores juntos)
  • privkey.pem (clave privada)
Si no utilizais LetsEncript, tenéis que realizar estos pasos:
=============================================================
1. Generar un par de clave privada y el CSR público (Certificate Signing Request) para el servidor web ("server"), con este comando

openssl req -nodes -newkey rsa:2048 -keyout domain.name.key -out domain.name.csr

2. Enviar el CSR al la entidad certificadora (CA) y ésta verificará tu dominio, y te suministrará un certificado (fichero .crt)  y cadena de certificados (certificate chain)
=============================================================

4. Configurar https en el puerto 19443 u otro de forma fácil (Opción recomendada)

Modificamos el conector en el fichero server.xml de la carpeta conf de tomcat y para el puerto 19443 para que quede así

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 <Connector port="19443"
     protocol="HTTP/1.1"
     SSLEnabled="true"
     maxThreads="150"
     scheme="https"
     secure="true"
     sslProtocol="TLS"

     clientAuth="true"
     keyAlias="tomcat"


     SSLCertificateFile="/etc/letsencrypt/live/midominio.es/cert.pem"
     SSLCertificateChainFile="/etc/letsencrypt/live/midominio.es/chain.pem"
     SSLCertificateKeyFile="/etc/letsencrypt/live/midominio.es/privkey.pem"
 />


5. Renovar el certificado en el servidor

Solo hace falta ejecutar el comando visto anteriormente, y ya está

sudo certbot certonly --standalone -d myweb.es

Si no funciona pues dice 
Problem binding to port 443: Could not bind to IPv4 or IPv6
Entonces hay que parar el servidor (./shutdown.sh) y ejecutar el comando anterio cambiando
 --standalone por --apache

sudo certbot certonly --apache -d myweb.es

PERO DA PROBLEMAS SI SE ACCEDE DESDE FUERA DE LA ORGANIZACION.


Lo mejor en estos casos es volver a instalar el cerbot, (paso 2)
Solo hay que reaarancar el Tomcat, para ello vamos al directorio "bin" del tomcat y ejecutamos

./shutdown.sh
./startup.sh

6. Configurar https en el puerto 8443 u otro con conversiones (NO RECOMENDADO)

El problema es que queremos utilizar el formato JKS, por tanto tenemos que realizar 2 conversiones

6.1. Convertir "keypair" + certificado a java keystore

1. Crear un PKCS12 que contenga la cadena de certrificados completa y la clave privada con openssl

openssl pkcs12 -export -out /tmp/webprop.es_fullchain_and_key.p12 \ -in /etc/letsencrypt/live/webprop.es/fullchain.pem \ -inkey /etc/letsencrypt/live/webprop.es/privkey.pem \ -name tomcat

2. Convertir el PVCS12 a JKS con keytool de java

keytool -importkeystore \ -deststorepass mi_password -destkeypass mi_password -destkeystore /tmp/webprop.es.jks \ -srckeystore /tmp/webprop.es_fullchain_and_key.p12 -srcstoretype PKCS12 -srcstorepass mi_password \ -alias tomcat


Donde hay que cambiar mi_password por la contraseña que querais

Si no utilizais LetsEncript, tenéis que realizar estos pasos:
=============================================================
1. Con el paso del punto anterior ya tienes la clave privada (fichero .key) y el certificado (fichero .cert) de la entidad certificadora. Se deberá generrar el fichero pfx, con este comando

openssl pkcs12-export -out domain.name.pfx -inkey domain.name.key -in domain.name.crt

2. Convertir el fichero pfx a JKS

keytool-importkeystore -srckeystore webprop.pfx -srcstoretype pkcs12 \ -destkeystore webprop.jks -deststoretype JKS

=============================================================

6.2. Configurar Tomcat con el java keystore


Aseguratrse que esta sección de conf/server.xml está comentada 

<!--- <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> -->

Y configurar el conector para que use el "shared thread pool" 

<Connector
executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

Ahora definir el conector SSL HTTP/1.1 En el puerto 8443

<Connector port="8443"
<!-- protocol="org.apache.coyote.http11.Http11Protocol"-->
protocol="HTTP/1.1"
maxThreads="150" cd ..
SSLEnabled="true"
scheme="https"
secure="true" keystoreFile="/tmp/webprop.es.jks" keystorePass="mi_password" clientAuth="false"
sslProtocol="TLS" />

NOTA: He tenido que comentar la línea:
 "<!-- protocol="org.apache.coyote.http11.Http11Protocol"-->
y cambiarla por la línea de rojo (protocol="HTTP/1.1") pues no me funcionaba.

Ahora hay que rearrancar el Tomcat y debería funcionar. Aunque a mi me ha tardado mucho en arrancar!!


6.3. Crear un shell scrypt para renovar el certificado.

Para ello debemos tener los siguientes prerequisitos:
  • Tener privilegio de superusuario
  • Tener un dominio registrado ("webprop.es" en mi caso)
  • Versión de Java reciente instalada
  • Versión reciente de Tomcat instalada
  • Tener abiertos los puertos 80 y 8443 en el firewall
  • Tener instalado Openssl
  • Tener configurado Tomcat para el puerto 8443 tal como hemos visto en el punto anterior
Veamos el bash

#!/bin/bash

#--Explicació
#---------------------------------------------------------------------------
# S'ha d'executar des de la màquina que s'ha d'instal·lar el certificat 
# Ha d'estar instal·lat el cerbot a la màquina:
#    sudo add-apt-repository ppa:certbot/certbot
#    sudo apt install python-certbot-apache

# La carpeta /etc/letsencrypt/live/csv.tavernesvalldigna.es/ ha de tindre 
#   permissos d'escritura per a eviar cridar-la amb "sudo" 
#   per tant cal executar abans esta orden:    
#     sudo chmod -R ugo+rwx /etc/letsencrypt
#     sudo chmod -R ugo+rwx /var/log
#     sudo chmod -R ugo+rwx /var/lib/letsencrypt

# 1. Indicar el domini
# 2. Indicarla carpeta on guarda el certbot els certificats
# 3. Indicar la carpeta on guardar els certificats tipus jks
#    que és la ruta on Tomcat els busca
# 4. Indicar la paraula de pas del certificat
#---------------------------------------------------------------------------

#--Parameters
myuser='ximo'
domain='webprop.es'
download_certbot='/etc/letsencrypt/live/'${domain}
keystore_folder='/home/'${myuser}'/MyKeystores'
psswrd='mi_password'

work_folder=${keystore_folder}'/letsencrypt/'$(date +%Y.%m.%d)
ks_prefix=${work_folder}'/'${domain}
JAVA_HOME='/home/'${myuser}'/MyPrograms/jdk-15.0.2+7.OpenJ7'

echo '--------------------------------------------------------------'
echo 'Usuari:           ' $myuser
echo 'Domain:           ' $domain
echo 'Descarga Certbot: ' $download_certbot
echo 'Keystore folder:  ' $keystore_folder
echo 'Paraula de pas :  ' $psswrd
echo 'Work folder :     ' $work_folder
echo 'Keystore prefix : ' $ks_prefix
echo 'JAVA_HOME :       ' $JAVA_HOME
echo '--------------------------------------------------------------'

certbot certificates

echo '--------------------------------------------------------------'
echo Por favor, verificar que los datos son correctos
read continuar

# No se si vol "csv.tavernesvalldigna.es" o si "vol sols tavernesvalldigna.es"
# Descarreguem  el certificat a /etc/letsencrypt/live/csv.tavernesvalldigna.es/ 
certbot certonly --standalone -d ${domain}

echo Creem la carpeta ${work_folder}
mkdir -p ${work_folder}
 
echo Convertir el p12 i el pem a PKCS12 
openssl pkcs12 -export -out ${ks_prefix}'_fullchain_and_key.p12' -in ${download_certbot}'/fullchain.pem' -inkey ${download_certbot}'/privkey.pem' -password pass:${psswrd} -name 'tomcat'


echo Convertir el PKCS12 a JKS 
$(${JAVA_HOME}'/bin/keytool' -importkeystore -deststorepass ${psswrd} -destkeypass ${psswrd} -destkeystore ${ks_prefix}'.jks' -srckeystore ${ks_prefix}'_fullchain_and_key.p12'  -srcstoretype PKCS12 -srcstorepass ${psswrd} -alias 'tomcat')

echo Copiar a la carpeta MyKeystore 
cp ${ks_prefix}'.jks' ${keystore_folder} 



lunes, 3 de mayo de 2021

Ubuntu establecer la variable PATH definitivamente

 Según HackProgramming se puede hacer modificando el fichero ~/.profile

Se le puede añadir esto al fichero (se le añade al path la carpeta MyShells al PATH)


# set PATH so it includes user's private MyShells if it exists

if [ -d "$HOME/MyShells" ] ; then

    PATH="$HOME/MyShells:$PATH"

fi


y ahora le damos este comando para que recoja el nuevo PATH

source ~/.profile

Y ya podemos ver esta carpeta en el path haciendo

echo $PATH