Chiamare un programma nativo IBM-i (o AS400) da Windows fuori dall’emulatore e con soluzioni automatizzate è sempre stato un incubo: Molti nel tempo hanno sviluppato soluzioni basate sulla DLL di Client Access cwbx.dll, che purtroppo ad oggi è considerata deprecata. Molti hanno preferito usare OleDB con moltissimi limiti (ad esempio non è possibile passare parametri). Altri temerari hanno intrapreso invece lo sviluppo di WS appositi o l’uso di JT400 (ed a loro va tutto il mio rispetto!).
C’è un altro metodo, molto semplice e performante per far iteragire Windows ed il nostro monolite preferito: WinSCP ed SSH!
Perchè chiamare un programma IBM al di fuori del terminale?
In sistemi informativi complessi spesso è necessario far interfacciare componenti Legacy con applicazioni windows.
Orchestrare una serie di programmi/iterazioni complesse, schedulare applicazioni in catene e far comunicare applicazioni differenti è una delle sfide giornaliere che devono affrontare i i system integrator e gli architect solutions.
Prerequisiti
Sul sistema target deve essere presente SSH (il componente è 5733-SC1 Licensed Program Product) configurato e funzionante. Una credenziale d’accesso ed un collegamento aperto sulla porta.
WinSCP e .NET
Molti di voi conoscono WinSCP come un software molto utile per fare file-transfer come alternativa di Filezilla ma in pochi sanno che nella cartella del programma c’è una magnifica DLL, winscpnet.dll che può essere referenziata in un progetto .NET.
Di setuito, un elenco di esempi presi dal sito ufficiale:
Documentazione .net: https://winscp.net/eng/docs/library
- C# Example
- VB.NET Example
- PowerShell Example
- JScript Example
- VBScript Example
- VBA Example
- Perl Example
- SSIS Example
Esempio di chiamata in C#
Di seguito il POC da cui sono partito. Io per semplificarmi le cose ho messo parte delle configurazioni in un config file:
using System;
using WinSCP;
using System.Configuration;
using System.Xml;
using System.Xml.Serialization;
class Programma
{
public static int Main()
{
string server = ConfigurationManager.AppSettings["server"];
string SshHostKeyFingerprint = ConfigurationManager.AppSettings["SshHostKeyFingerprint"];
string UserName = ConfigurationManager.AppSettings["UserName"];
string password = ConfigurationManager.AppSettings["password"];
string SshPrivateKey = ConfigurationManager.AppSettings["SshPrivateKey"];
string SshPrivateKeyPassphrase = ConfigurationManager.AppSettings["SshPrivateKeyPassphrase"];
string LogPath = ConfigurationManager.AppSettings["LogPath"];
try
{
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = server,
UserName = UserName,
//Password = password,
SshPrivateKeyPath = SshPrivateKey,
PrivateKeyPassphrase = SshPrivateKeyPassphrase,
SshHostKeyFingerprint = SshHostKeyFingerprint
};
using (Session session = new Session())
{
// Connect
session.SessionLogPath = LogPath;
session.Open(sessionOptions);
string CommandAS400 = string.Format(@"system ""CALL PGM(LIBRERIA/PROGRAMMA) PARM('PARAMETRO')""");
string output;
output = session.ExecuteCommand(CommandAS400).Output.ToString();
}
return 0;
}
catch (Exception e)
{
Console.WriteLine("Error: {0}", e);
return 1;
}
}
}
Analizziamo il programma nelle componenti su cui prestare attenzione:
La sezione di SessionOptions raccoglie tutte le informazioni di connessione:
Protocol: Protocol.Sftp Questo è un valore fisso
HostName: Nome del server o il suo IP
UserName: Login AS400
Password: Password AS400
SshHostKeyFingerprint: Chiave pubblica del server
In alternativa alla password è possibile usare una chiave privata SSH:
SshPrivateKeyPath: Posizione del file PPK contenente la chiave privata
PrivateKeyPassphrase: Eventuale password della chiave privata
il blocco successivo contiene la chiamata:
il comando va costruito così:
system ""CALL PGM(LIBRERIA/PGM) PARM('PARM')""
La chiamata sfrutta il comando QSH System che permette di chiamare da console POSIX i comandi e programmi di sistema della CLI nativa del sistema operativo.
Invece tramite questo statement:
output = session.ExecuteCommand(CommandAS400).Output.ToString();
Permette di intercettare l’output del programma.
– Se il chiamato è un CLP, può essere usato il comando SNDPGMMSG MSG(&MSG1)
– Se il chiamato è uno script SH, viene wrappato lo STDout
Usando questo statement poi
session.SessionLogPath = LogPath;
è possibile loggare in maniera molto dettagliata il log di connessione, utile per fare eventuale troubleshooting.
Conclusione
La soluzione si presta per molti scenari, personalmente la uso per chiamare programmi da SSIS o per gestire schedulazioni centralizzate ed orchestrate.