PASE for i como capa de compatibilidad AIX, gestion de paquetes con yum, Node.js, Python, PHP, Git y herramientas open source ejecutandose nativamente en IBM i. Integracion entre el mundo open source y la plataforma nativa.
PASE for i (Portable Application Solutions Environment) es una capa de runtime integrada en IBM i que permite ejecutar binarios compilados para AIX (IBM Unix) directamente en el sistema. PASE proporciona un entorno POSIX completo con su propio sistema de archivos, shell y librerias compartidas, todo corriendo sobre el mismo kernel de IBM i.
Compatibilidad AIX
Ejecuta binarios PowerPC AIX sin recompilacion. Mismas librerias y APIs POSIX.
IFS integrado
Comparte el sistema de archivos IFS con el entorno nativo IBM i. Acceso transparente.
Shell completo
Bash, sh, ksh disponibles. Pipes, redirects, scripts funcionan igual que en Unix.
Perfiles IBM i
PASE usa los mismos perfiles de usuario y permisos que el entorno nativo.
Networking compartido
PASE comparte la misma pila TCP/IP. Las apps escuchan en los mismos puertos.
Open source
Node.js, Python, PHP, Ruby, Git, gcc y cientos de paquetes disponibles.
+--------------------------------------------------+ | Aplicaciones IBM i | | RPG | COBOL | CL | SQL | Java | +--------------------------------------------------+ | MI (Machine Interface) - Kernel IBM i | +--------------------------------------------------+ | PASE for i Runtime | | +--------------------------------------------+ | | | Binarios AIX / PowerPC | | | | Node.js | Python | PHP | Git | gcc | | | | Bash | coreutils | openssl | curl | | | +--------------------------------------------+ | | | Librerias AIX: libc, libpthread, libdl | | | +--------------------------------------------+ | +--------------------------------------------------+ | IFS (Integrated File System) compartido | | /home /QOpenSys /QSYS.LIB /tmp | +--------------------------------------------------+
// Acceder a PASE desde 5250 con CALL QP2TERM CALL QP2TERM // O desde SSH (recomendado): ssh miusuario@miibmi // Verificar que estamos en PASE $ uname -a AIX miibmi 1 7 00F6B9F74C00 // Verificar version de PASE $ /QOpenSys/usr/bin/oslevel 7.2.0.0 // Ver el PATH por defecto $ echo $PATH /QOpenSys/pkgs/bin:/QOpenSys/usr/bin:/usr/bin // Listar archivos en IFS (acceso completo) $ ls /QSYS.LIB/MILIB.LIB/ CLIENTES.FILE FACTURAS.FILE MIPGM.PGM
IBM distribuye paquetes open source para IBM i a traves de un repositorio RPM gestionado con yum (el mismo gestor de paquetes de Red Hat/CentOS). La instalacion inicial se realiza desde ACS (Access Client Solutions)y luego se gestionan los paquetes desde la linea de comandos.
Instalacion inicial (una sola vez)
Estructura de directorios
/QOpenSys/pkgs/ -- Raiz de paquetes open source/QOpenSys/pkgs/bin/ -- Binarios (node, python3, git)/QOpenSys/pkgs/lib/ -- Librerias compartidas/QOpenSys/pkgs/etc/ -- Configuracion/QOpenSys/pkgs/share/ -- Datos y documentacion// Actualizar el catalogo de paquetes $ yum update // Buscar paquetes disponibles $ yum search nodejs $ yum search python3 // Ver informacion de un paquete $ yum info nodejs18 // Instalar paquetes $ yum install nodejs18 $ yum install python39 $ yum install git $ yum install bash $ yum install curl $ yum install openssh // Instalar multiples paquetes de una vez $ yum install nodejs18 python39 git bash-completion // Ver paquetes instalados $ yum list installed // Eliminar un paquete $ yum remove nodejs14 // Ver paquetes que tienen actualizacion disponible $ yum check-update // Actualizar un paquete especifico $ yum upgrade nodejs18
yum update antes de instalar paquetes nuevos para asegurar que el catalogo esta actualizado. Los paquetes se instalan en /QOpenSys/pkgs/ y no interfieren con el sistema operativo nativo de IBM i.Node.js corre nativamente en IBM i gracias a PASE. Es una de las opciones mas populares para crear aplicaciones web modernas que interactuan con datos y programas IBM i. Soporta npm completo, Express, frameworks modernos y acceso a Db2 via ODBC.
// Instalar Node.js 18 LTS $ yum install nodejs18 // Verificar instalacion $ node --version v18.19.0 $ npm --version 9.8.1 // Crear directorio de proyecto $ mkdir -p /home/MIUSER/proyectos/mi-api $ cd /home/MIUSER/proyectos/mi-api // Inicializar proyecto Node.js $ npm init -y // Instalar dependencias comunes $ npm install express $ npm install odbc # Driver ODBC para Db2 $ npm install itoolkit # Llamar programas RPG $ npm install dotenv # Variables de entorno
const express = require('express');
const odbc = require('odbc');
const app = express();
app.use(express.json());
// Conexion ODBC a Db2 for i
const DSN = 'DSN=*LOCAL;DBQ=MILIB;';
// GET /api/clientes - Listar clientes
app.get('/api/clientes', async (req, res) => {
try {
const conn = await odbc.connect(DSN);
const result = await conn.query(
'SELECT CLI_ID as id, CLI_NOM as nombre, ' +
'CLI_MAIL as email, CLI_SALDO as saldo ' +
'FROM MILIB.CLIENTES ' +
'WHERE CLI_ACTIV = ? ORDER BY CLI_NOM',
['A']
);
await conn.close();
res.json({ data: result, count: result.length });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// GET /api/clientes/:id - Obtener un cliente
app.get('/api/clientes/:id', async (req, res) => {
try {
const conn = await odbc.connect(DSN);
const result = await conn.query(
'SELECT * FROM MILIB.CLIENTES WHERE CLI_ID = ?',
[req.params.id]
);
await conn.close();
if (result.length === 0) {
return res.status(404).json({ error: 'No encontrado' });
}
res.json(result[0]);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// POST /api/clientes - Crear cliente
app.post('/api/clientes', async (req, res) => {
const { nombre, email } = req.body;
try {
const conn = await odbc.connect(DSN);
await conn.query(
'INSERT INTO MILIB.CLIENTES ' +
'(CLI_NOM, CLI_MAIL, CLI_SALDO, CLI_ACTIV) ' +
'VALUES (?, ?, 0, ?)',
[nombre, email, 'A']
);
await conn.close();
res.status(201).json({ message: 'Cliente creado' });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log('API corriendo en puerto ' + PORT);
});// Ejecutar en primer plano (desarrollo)
$ cd /home/MIUSER/proyectos/mi-api
$ node app.js
API corriendo en puerto 3000
// Ejecutar en background con nohup
$ nohup node app.js > /home/MIUSER/logs/api.log 2>&1 &
// Usar PM2 para gestion de procesos en produccion
$ npm install -g pm2
$ pm2 start app.js --name "mi-api"
$ pm2 list
$ pm2 logs mi-api
$ pm2 restart mi-api
// Probar el endpoint
$ curl http://localhost:3000/api/clientes
{"data":[...],"count":42}Python es ideal para scripting, automatizacion, ETL, analisis de datos y aplicaciones web en IBM i. Incluye soporte completo para pip, virtualenvs y acceso a Db2 mediante el paquete ibm_db o via ODBC.
// Instalar Python 3.9 $ yum install python39 python39-pip python39-devel // Verificar instalacion $ python3 --version Python 3.9.18 $ pip3 --version pip 23.2.1 // Crear virtual environment (buena practica) $ python3 -m venv /home/MIUSER/venvs/miproyecto $ source /home/MIUSER/venvs/miproyecto/bin/activate // Instalar dependencias (miproyecto)$ pip install ibm_db # Driver nativo Db2 (miproyecto)$ pip install itoolkit # Llamar programas RPG (miproyecto)$ pip install flask # Framework web (miproyecto)$ pip install pandas # Analisis de datos (miproyecto)$ pip install openpyxl # Manejo de Excel
import ibm_db_dbi as db2
# Conexion local a Db2 for i
conn = db2.connect()
# Consultar clientes activos
cursor = conn.cursor()
cursor.execute("""
SELECT CLI_ID, CLI_NOM, CLI_MAIL, CLI_SALDO
FROM MILIB.CLIENTES
WHERE CLI_ACTIV = 'A'
ORDER BY CLI_NOM
FETCH FIRST 100 ROWS ONLY
""")
# Iterar resultados
for row in cursor:
print(f"ID: {row[0]}, Nombre: {row[1]}, "
f"Saldo: {row[3]:,.2f}")
# Insert con parametros
cursor.execute("""
INSERT INTO MILIB.CLIENTES
(CLI_NOM, CLI_MAIL, CLI_SALDO, CLI_ACTIV)
VALUES (?, ?, ?, ?)
""", ('Nuevo Cliente', 'nuevo@email.com', 0, 'A'))
conn.commit()
cursor.close()
conn.close()#!/QOpenSys/pkgs/bin/python3
"""
Script de automatizacion: exportar clientes a CSV
Puede ejecutarse desde CL con: QSH CMD('python3 /path/automatizar.py')
"""
import ibm_db_dbi as db2
import csv
from datetime import datetime
conn = db2.connect()
cursor = conn.cursor()
cursor.execute("""
SELECT CLI_ID, CLI_NOM, CLI_MAIL, CLI_SALDO,
CLI_ACTIV, CLI_FALTA
FROM MILIB.CLIENTES
ORDER BY CLI_NOM
""")
# Generar archivo CSV en IFS
fecha = datetime.now().strftime('%Y%m%d')
archivo = f'/home/MIUSER/exports/clientes_{fecha}.csv'
with open(archivo, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['ID', 'Nombre', 'Email',
'Saldo', 'Activo', 'FechaAlta'])
for row in cursor:
writer.writerow(row)
print(f"Exportados {cursor.rowcount} registros a {archivo}")
cursor.close()
conn.close()QSH CMD('python3 /ruta/script.py') o programando su ejecucion con el planificador de jobs de IBM i (ADDJOBSCDE).PHP tiene una larga historia en IBM i y sigue siendo una opcion solida para aplicaciones web, especialmente para modernizar interfaces 5250 a web. El driver nativo ibm_db2 permite acceso directo a Db2 for i.
// Instalar PHP 8.1 con extensiones comunes
$ yum install php81 php81-cli php81-fpm
$ yum install php81-ibm_db2 # Driver Db2
$ yum install php81-odbc # ODBC alternativo
$ yum install php81-json php81-xml php81-mbstring
$ yum install php81-curl php81-zip
// Verificar instalacion
$ php --version
PHP 8.1.25
// Verificar extensiones
$ php -m | grep -i db2
ibm_db2
// Instalar Composer (gestor de dependencias PHP)
$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ php composer-setup.php --install-dir=/QOpenSys/pkgs/bin --filename=composer<?php
// clientes.php - Listado de clientes desde Db2 for i
$conn = db2_connect('*LOCAL', '', '');
if (!$conn) {
die('Error de conexion: ' . db2_conn_errormsg());
}
// Consultar clientes
$sql = "SELECT CLI_ID, CLI_NOM, CLI_MAIL, CLI_SALDO
FROM MILIB.CLIENTES
WHERE CLI_ACTIV = 'A'
ORDER BY CLI_NOM";
$stmt = db2_exec($conn, $sql);
// Generar respuesta JSON (para APIs)
header('Content-Type: application/json');
$clientes = [];
while ($row = db2_fetch_assoc($stmt)) {
$clientes[] = [
'id' => (int)$row['CLI_ID'],
'nombre' => trim($row['CLI_NOM']),
'email' => trim($row['CLI_MAIL']),
'saldo' => (float)$row['CLI_SALDO'],
];
}
echo json_encode([
'data' => $clientes,
'count' => count($clientes)
]);
db2_close($conn);Git corre nativamente en IBM i via PASE y es la base del flujo de trabajo moderno para versionado de fuentes. Tanto el codigo fuente almacenado en IFS como el extraido de source physical files puede gestionarse con Git.
// Instalar Git $ yum install git // Verificar $ git --version git version 2.39.3 // Configuracion inicial $ git config --global user.name "Fernando Secchi" $ git config --global user.email "fernando@empresa.com" $ git config --global core.autocrlf input $ git config --global init.defaultBranch main // Configurar SSH para GitHub/GitLab $ ssh-keygen -t ed25519 -C "fernando@empresa.com" $ cat ~/.ssh/id_ed25519.pub // Copiar la clave publica y agregarla en GitHub/GitLab
// Crear repositorio para fuentes RPG
$ mkdir -p /home/MIUSER/repos/mi-proyecto
$ cd /home/MIUSER/repos/mi-proyecto
$ git init
// Estructura de directorios recomendada
$ mkdir -p qrpglesrc qclsrc qddssrc qcmdsrc qsqlsrc
// Copiar fuentes desde source physical files
$ system "CPYTOSTMF FROMMBR('/QSYS.LIB/MILIB.LIB/QRPGLESRC.FILE/GESTCLI.MBR') TOSTMF('/home/MIUSER/repos/mi-proyecto/qrpglesrc/gestcli.rpgle') STMFOPT(*REPLACE) STMFCCSID(1208)"
// Agregar archivos y hacer primer commit
$ git add .
$ git commit -m "feat: migracion inicial de fuentes RPG"
// Conectar con repositorio remoto
$ git remote add origin git@github.com:empresa/mi-proyecto.git
$ git push -u origin main
// Flujo diario de trabajo
$ git pull origin main # Traer cambios
$ git checkout -b feature/nueva # Crear branch
// ... editar archivos ...
$ git add qrpglesrc/gestcli.rpgle
$ git commit -m "feat: agregar validacion de email"
$ git push origin feature/nueva # Subir cambiosSource Physical Files (tradicional)
Git + IFS (moderno)
iToolkit es una libreria disponible para Node.js, Python y PHP que permite llamar programas RPG, ejecutar comandos CL y acceder a data queues directamente desde codigo open source. Es el puente entre el mundo PASE y el entorno nativo IBM i.
const { Connection, ProgramCall } = require('itoolkit');
const { parseString } = require('itoolkit/lib/utils');
// Conexion al sistema local
const conn = new Connection({
transport: '*local',
transportOptions: { database: '*LOCAL' }
});
// Llamar al programa GESTCLI con parametros
const pgm = new ProgramCall('GESTCLI', { lib: 'MILIB' });
pgm.addParam({ name: 'accion', type: '10A', value: 'CONS' });
pgm.addParam({ name: 'id', type: '7P0', value: '1001' });
pgm.addParam({ name: 'nombre', type: '100A', value: '' });
pgm.addParam({ name: 'email', type: '200A', value: '' });
pgm.addParam({ name: 'resultado', type: '1A', value: '' });
conn.add(pgm);
conn.run((error, xmlOutput) => {
if (error) {
console.error('Error:', error);
return;
}
const results = parseString(xmlOutput);
console.log('Nombre:', results[2].value.trim());
console.log('Email:', results[3].value.trim());
console.log('Resultado:', results[4].value);
});from itoolkit import iToolKit, iPgm, iData, iDS
from itoolkit.transport import DatabaseTransport
# Conexion local
import ibm_db_dbi as db2
conn = db2.connect()
transport = DatabaseTransport(conn)
tk = iToolKit()
# Llamar programa GESTCLI
tk.add(iPgm('gestcli', 'GESTCLI', {'lib': 'MILIB'})
.addParm(iData('accion', '10A', 'CONS'))
.addParm(iData('id', '7P0', '1001'))
.addParm(iData('nombre', '100A', ''))
.addParm(iData('email', '200A', ''))
.addParm(iData('resultado', '1A', ''))
)
tk.call(transport)
result = tk.dict_out('gestcli')
print(f"Nombre: {result['nombre'].strip()}")
print(f"Email: {result['email'].strip()}")
print(f"Resultado: {result['resultado']}")
conn.close()<?php
require_once 'ToolkitService.php';
// Conexion al toolkit
$conn = ToolkitService::getInstance('*LOCAL', '', '');
// Parametros del programa
$params = [
$conn->AddParameterChar('in', 10, 'accion', 'ACCION', 'CONS'),
$conn->AddParameterPackDec('in', 7, 0, 'id', 'ID', '1001'),
$conn->AddParameterChar('out', 100, 'nombre', 'NOMBRE', ''),
$conn->AddParameterChar('out', 200, 'email', 'EMAIL', ''),
$conn->AddParameterChar('out', 1, 'resultado','RESULTADO', ''),
];
// Llamar al programa RPG
$result = $conn->PgmCall('GESTCLI', 'MILIB', $params);
if ($result !== false) {
echo "Nombre: " . trim($result['io_param']['nombre']) . "
";
echo "Email: " . trim($result['io_param']['email']) . "
";
echo "Resultado: " . $result['io_param']['resultado'] . "
";
}
?>SSH es el metodo recomendado para acceder a PASE de forma remota. Reemplaza a CALL QP2TERM (desde 5250) y proporciona una experiencia de terminal completa con soporte para claves publicas, tuneles y SCP para transferencia de archivos.
// Iniciar el servidor SSH (como administrador) STRTCPSVR SERVER(*SSHD) // Verificar que esta activo WRKACTJOB SBS(QUSRWRK) JOB(SSHD) // Configurar inicio automatico con IPL CHGTCPSVR SVRSPCVAL(*SSHD) AUTOSTART(*YES) // Verificar puerto (default 22) NETSTAT *CNN // Buscar Local Port 22
# En tu maquina local: ~/.ssh/config
Host miibmi
HostName 192.168.1.100
User MIUSER
Port 22
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
# Conectar con un simple:
$ ssh miibmi
# Copiar archivos con SCP
$ scp archivo.rpgle miibmi:/home/MIUSER/repos/src/
$ scp miibmi:/home/MIUSER/exports/datos.csv ./local/
# Copiar directorios completos
$ scp -r ./mi-proyecto/ miibmi:/home/MIUSER/repos/
# Ejecutar comando remoto sin sesion interactiva
$ ssh miibmi "system 'DSPLIB MILIB'"
$ ssh miibmi "python3 /home/MIUSER/scripts/backup.py"Una de las mayores fortalezas de PASE es la integracion transparente con el entorno nativo de IBM i. Desde PASE se pueden ejecutar comandos CL, acceder a objetos QSYS, leer/escribir data queues y ejecutar sentencias SQL directamente.
// El comando 'system' permite ejecutar CL desde PASE
$ system "DSPLIB MILIB"
$ system "WRKOBJPDM LIB(MILIB)"
// Compilar un programa RPG desde PASE
$ system "CRTBNDRPG PGM(MILIB/GESTCLI) SRCSTMF('/home/MIUSER/repos/qrpglesrc/gestcli.rpgle') DBGVIEW(*SOURCE)"
// Ejecutar un programa nativo desde PASE
$ system "CALL MILIB/GESTCLI PARM('CONS' X'001001F' ' ' ' ' ' ')"
// Enviar mensaje a QSYSOPR
$ system "SNDMSG MSG('Deploy completado') TOUSR(*SYSOPR)"
// Usar db2util para SQL desde shell
$ /QOpenSys/pkgs/bin/db2util "SELECT COUNT(*) FROM MILIB.CLIENTES"
// Usar variables de entorno IBM i
$ system "ADDENVVAR ENVVAR('MI_CONFIG') VALUE('/home/app/config')"
$ echo $MI_CONFIGsystem 'DSPLIB MILIB'SELECT * FROM MILIB.TABLAiPgm('MIPGM', 'MILIB')ls /QSYS.LIB/MILIB.LIB/iDataQueue('MIDTAQ', 'MILIB')system 'DSPDTAARA MIDTAARA'Organizacion de proyectos
Seguridad
Rendimiento
Mantenimiento
# /home/MIUSER/.bash_profile
# Configuracion recomendada para desarrollo en IBM i
# PATH con paquetes open source primero
export PATH="/QOpenSys/pkgs/bin:$PATH"
# Editor por defecto
export EDITOR=vim
# Locale UTF-8
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
# Node.js
export NODE_ENV=development
# Python virtual env por defecto
alias activate='source /home/MIUSER/venvs/miproyecto/bin/activate'
# Alias utiles para IBM i
alias cls='system "CLRLIB QTEMP"'
alias dsplib='system "DSPLIB"'
alias wrkobjpdm='system "WRKOBJPDM"'
alias db2='db2util'
# Git prompt (muestra branch actual)
parse_git_branch() {
git branch 2>/dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\u@\h:\w\$(parse_git_branch)\$ "