, , Les Fichiers Markdown

Ce son des fichiers qui ont l’extension MD, ce format a été créer par John Gruber, son but était de produire des fichiers formatés très simple à administrer un peu comme RTF mais encore en plus simple.

Ce format a été adopté dans le monde open source comme un standard, par exemple les gens qui publient sur Github, mettrons un readme.md pour décrire leurs publications.
https://gist.github.com/JulienRAVIA/1cc6589cbf880d380a5bb574baa38811

La syntaxe est très simple vous pouvez l’apprendre ici :

https://blindhelp.github.io/recapitulatifsyntaxemarkdown.html

Par exemple, pour mettre des titres vous devrez utiliser le caractère #

Si la syntaxe est relativement simple, nous vous conseillons d’utiliser un éditeur pour commencer

Celui que nous utilisons s’appelle JOPLIN (Merci à Yvon qui nous l’a fait découvrir)

Vous pouvez le télécharger là https://joplinapp.org/

(il existe sous forme d’extension pour VSE également, et même sur téléphone)

L’utilisation est très simple, et relativement classique pour les utilisateurs de produits Windows

Vous avez une barre avec les différents éléments que vous voulez intégrer.

L’outil est WYSIWYG ce qui permet de voir en temps réel ce que vous voulez faire

il dispose également de nombreuses possibilités d’exportation comme HTML et PDF

Conclusion :

C’est un format simple à utiliser et c’est un standard pour les nouveaux qui arrivent sur notre plateforme.
il est donc fortement conseillé de vous y mettre, et l’effort n’est pas important au regard de ce qu’il peut rapidement vous apporter.

Vous pourrez facilement faire des docs techniques de qualité et les exporter, il existe de nombreuses extensions pour vous aider

Sites à connaitre

https://fr.wikipedia.org/wiki/Markdown

https://www.markdownguide.org/basic-syntax/

https://www.ionos.fr/digitalguide/sites-internet/developpement-web/markdown/ (en français)

, , Appel d’API en CL

Nous utilisons de plus en plus les services SQL pour de nombreuses actions : accès aux *DTAQ, *DTAARA, travaux etc …

Par exemple, pour accéder au contenu d’une variable d’environnement, la vue QSYS2.ENVIRONMENT_VARIABLE_INFO est très simple à utiliser :

Dans un programme RPG, il est très simple d’effectuer une lecture SQL.

Mais dans certains cas, nous préférerons utiliser les APIs système : pour la performance, ou dans le CL ! En CL, il est possible d’exécuter une instruction SQL, mais pas de récupérer un result sets (en tout cas pas simplement et avec une bonne performance).

L’appel d’API depuis le CL ne pose pas de soucis, principalement depuis les évolutions permettant de maitriser l’allocation mémoire des variables (variables autonomes, basées sur un pointeur, ou basée sur une autre variable – équivalent OVERLAY du RPG) :

Maintenant, lorsque l’on utilise des API, il est (souvent) nécessaire de passer par des pointeurs, de façon explicite ou non. Par exemple, c’est le cas pour QUSRJOBI même si l’on a pas déclaré de pointeur dans notre programme CL :

En réalité, lors d’un appel de programme ou procédure, les paramètres sont transmis par défaut par référence : concrètement on passe un pointeur sur le début de la valeur, mais pas la valeur elle-même !

Il faut commencer à interpréter les prototypes des API en fonction du langage d’appel …

Le système étant écrit en C, certaines API utilisent la définition C d’une chaine de caractères : un pointeur sur le premier caractère, la fin de la chaîne étant marquée par le premier octet null !

En RPG, nous avons la fonction %str() qui permet de gérer ceci :

En CL, pas de fonction équivalent pour gérer cela.

Prenons par exemple l’API getEnv() (en fait une fonction de la bibliothèque standard C) :

Il faut fournir en entrée le nom de la variable d’environnement, au format C String, c’est à dire à terminaison nulle.

De même, la valeur de retour est un pointeur sur le début de la valeur. La fin se situe au premier octet null rencontré …

Voici un exemple d’appel :

Nous déclarons simplement une variable de type CHAR(1) initialisée à x’00’ :

DCL VAR(&SPC_INIT) TYPE(*CHAR) LEN(1) VALUE(X'00')

Cela nous sert à créer la valeur pour l’appel : chaine à terminaison nulle contenant le nom de la variable d’environnement recherchée (ici CLASSPATH) :

CHGVAR &ENVVAR ( 'CLASSPATH' *CAT &SPC_INIT )

Pour décoder la valeur de retour, il nous faut parcourir la valeur reçue jusqu’à trouver la terminaison nulle. On utilise simplement %SCAN pour trouver la position et redécouper :

CHGVAR VAR(&POSNULL) VALUE(%SCAN(&SPC_INIT &ENVVARVAL) - 1 )
CHGVAR &FINALVAL %SUBSTRING(&ENVVARVAL 1 &POSNULL)

Au final, très peu de code à ajouter, mais nécessite une compréhension de la documentation des APIs, des types de données dans les différents langages, et des mécanismes de transmission de paramètres !


, , Visual studio code IBM i Snippets

Vous connaissez tous, au moins de nom l’extension « code for i » qui vous permet d’éditer vos sources RPGLE dans votre éditeur favori qui est publié par notre Ami Liam Allan

Si voulez en savoir plus une vidéo très bien faite de notre ami de Yvon est disponible sur la chaine youtube de Volubis ici

Mais il existe également des extensions créé par d’autres contributeurs en voici une qui est apparu en 2022 « IBM i Snippets », elle a été créée par Andy Youens.

L’installation est très simple à partir de la gestion des extensions

Le principe de cette extension est de vous proposer des exemples de codes (par exemple des squelettes pour du RPGLE ou CLLE).

Son usage est très simple vous devez saisir « !i » dans votre éditeur favori .


Cette extension bouge beaucoup depuis sa sortie et les dernières contributions sont récentes, n’hésitez pas à proposer des exemples de codes si vous en avez qui soit présentable

Nous pensons qu’il y aura de plus en plus de extensions disponibles pour l’IBMI et une amélioration de celle exitantes extensions existantes, il est donc important d’avoir un œil ce mode de développement , en sachant que les « JEUNNNNES » connaissent déjà cet interface

Vous pouvez désormais mettre des points d’exit pour savoir quand un fichier IFS est ouvert ou fermé
QIBM_QP0L_OBJ_OPEN
QIBM_QP0L_OBJ_CLOSE
le format de data utilisé est le OBOP0100

exemple de programme en CLP

/*-------------------------------------------------------------------*/
/* exit pgm QIBM_QP0L_OBJ_OPEN  FMT OBOP0100                         */
/* Contrôle ouverture de fichier                                     */
/*-------------------------------------------------------------------*/
pgm (&data &retour)                                                    
/* Paramètres                                                        */
dcl &data *char 512  /* Variable recue                               */
dcl &retour *char 4  /* Variable renvoyée                            */
                     /*   0 pour OK                                  */
                     /*   1 pour KO                                  */
/* Variables de travail                                              */
             DCL        VAR(&USER) TYPE(*CHAR) STG(*DEFINED) LEN(10) + 
                          DEFVAR(&DATA 1)                              
             DCL        VAR(&EXT) TYPE(*CHAR) STG(*DEFINED) LEN(8) +   
                          DEFVAR(&DATA 11)                             
             DCL        VAR(&TYPE) TYPE(*CHAR) STG(*DEFINED) LEN(10) + 
                           DEFVAR(&DATA 23)                            
              DCL        VAR(&FLAG) TYPE(*CHAR) STG(*DEFINED) LEN(4) + 
                           DEFVAR(&DATA 28)                            
              DCL        VAR(&IDENT) TYPE(*CHAR) STG(*DEFINED) +       
                           LEN(16) DEFVAR(&DATA 33)                    
              DCL        VAR(&PATHL) TYPE(*CHAR) STG(*DEFINED) LEN(4) +
                           DEFVAR(&DATA 49)                            
              DCL        VAR(&PATH) TYPE(*CHAR) STG(*DEFINED) +        
                           LEN(256) DEFVAR(&DATA 53)                   
              dcl &len *dec (5 0)                                      
  /* Conversion du path UTF16/UCS2 vers CCSID en cours */              
              CALL       PGM(CVTUCS2) PARM((&PATH) (&PATH))            
  /* Longueur après conversion / 2 car UCS2 = 2 caractères */          
  chgvar &len (%BIN(&PATHL) / 2)                                       
 /*--------------------------------------------*/                      
 /* Ici Votre traitement                       */                      
/*--------------------------------------------*/                 
             SNDUSRMSG  MSG('Fichier ' *BCAT %SST(&PATH 1 &LEN) +
                          *BCAT ', ouvert par ' *BCAT &USER) +   
                          MSGTYPE(*INFO)                         
/*--------------------------------------------*/                 
/* Validation de la demande         0 pour OK */                 
/*--------------------------------------------*/                 
CHGVAR VAR(%BIN(&retour)) VALUE(0)                               
endpgm     

pour l'attachement du programme au point d'exit 
                                                      
ADDEXITPGM   EXITPNT(QIBM_QP0L_OBJ_OPEN) 
             FORMAT(OBOP0100)            
             PGMNBR(1)                   
             PGM(PLB/PGMIFS)             
             THDSAFE(*YES)               
             REPLACE(*NO)                

attention à bien mettre le paramètre THDSAFE(*YES)

Remarque :
Le path du fichier est déclaré en UCS2 ci joint un petit programme de conversion en RPGLE , utile si vous avez choisi d’écrire votre programme en CLLE

**free                                                
      // Programme de conversion CVTUCS2                     
      //   utf16/UCS2 vers ccsid en cours  par défaut 
  Dcl-pi *N ;                                         
   I_zon  ucs2(256) ; // soit une chaine de 128       
   O_zon  char(256) ;                                 
  End-pi ;                                            
   O_zon = I_zon ;                                    
 *inlr = *on ;

Pour être analysé par le point d’exit vos fichiers doivent avoir l’attribut *RUNEXIT

Pour le mettre sur un fichier

CHGATR OBJ(‘/home/QSECOFR/QPJOBLOG.PDF’) ATR(RUNEXIT) VALUE(YES)

Pour le mettre sur tous les fichiers crées dans votre répertoire

CHGATR OBJ(‘/home/QSECOFR/’) ATR(CRTRUNEXIT) VALUE(YES)

Cette information n’est pas encore disponible dans la vue QSYS2.IFS_OBJECT_STATISTICS

Quand vous lancerez PRUV avant votre passage en V7R5 vous aurez ce message
qui vous indique que le logiciel 5733OPS n’est plus installable, c’était la première mouture de l’open source sur l’IBMi

SELECT PRODUCT_OPTION, TEXT_DESCRIPTION
FROM QSYS2.SOFTWARE_PRODUCT_INFO
WHERE PRODUCT_ID = ‘5733OPS’

Parmi ces produits vous avez par exemple Nodejs, Nginx, ou Git (Vous devriez déjà utiliser ceux ce de Yum)

il est possible que vous ayez encore des applications qui les utilisent

Pour les trouver, ils utilisent des exécutables différents

Pour 5733OPS

/QOpenSys/QIBM/ProdData/OPS/tools/bin/

Pour RPM YUM

/QOpenSys/usr/bin/

Ou les chercher ?


-dans les scripts sh
-dans les programmes cl utilisant du sh
-dans les paths
-dans les variables d’environnement

Astuce

Pour contrôler après l’installation de votre V7R5
SELECT *
FROM QSYS2.SOFTWARE_PRODUCT_INFO
WHERE LOAD_ERROR = ‘YES’

Vous voulez faire du 5250 sur votre IBMi et que vos informations ne circulent pas en claire sur le réseau.

La première solution est de mettre en œuvre telnets


Vous devez vous connecter sur DCM
Créer un certificat ou utiliser un déjà existant
et l’associer à l’application

.
Ensuite dans votre client, en principe ACS , indiquer que vous vous connectez en sécurisé .

.

La deuxième est de passer par SSH

vous avez un client 5250 (TN5250) installable dans les packages OPEN SOURCES
vous n’avaez rien à faire coté serveur tout va se passer sur le service ssh qui doit être démarré
d’abord vous devez vous connecter par une client SSH , putty ou celui ACS mais en principe si vous faites ca …

.
Une fois connecté il vous suffira de lancer le client 5250 par la commande tn520
par exemple
==>tn5250 env.TERM=IBM-3179-2 ssl:neptune

.

.

Conclusion :

Ce n’est pas parfait mais vous n’avez pas besoin d’installer un client sur votre poste et en principe pas d’intervention à faire coté serveur ibmi

, , , Paramétrer NGINX en SSL sur votre IBMi

Une fois que vous avez installé NGINX , vous voudrez sans doute le sécuriser

Voici comment le sécuriser

Pour notre exemple

nous générerons nous même les clés de cryptographie

Nous allons générer 2 fichiers qui vont contenir vos clés
un fichier .pem et un fichier .key
par convention on les appellera cert
on choisira un certificat de type x509 valable une année

pour cela on va utiliser OPENSSL, vous devrez donc vérifier que le produit est installé

sous QSH voici la commande à passer

openssl req -newkey rsa:2048 -nodes -keyout /home/nginx/cert.key -x509 -days 365 -out /home/nginx/cert.pem

Après avoir répondu aux questions vous obtenez vos 2 certificats

Maintenant vous allez devoir indiquer à nginx qu’il est protégé par ces clés

Vous allez devoir modifier le fichier de configuration de nginx dans notre cas celui par défaut
bien sur vous sauvegardez avant l’ancien /QOpenSys/etc/nginx/nginx.conf

Une fois que vous avez fait votre modification vous devez arrêter le serveur nginx et le redémarrer

nginx -c /QOpenSys/etc/nginx/nginx.conf -s stop
puis
nginx -c /QOpenSys/etc/nginx/nginx.conf

Pour tester vous allez indiquer https://votreserveur:1880
dans notre cas le port est 1880.

Vous allez recevoir une alerte de sécurité , c’est normal votre certificat de n’a pas de racine connue
Vous répondez une fois ou de manière définitive et vous obtenez votre première page et vous voyez le https:

On utilise de plus en plus java dans les travaux de votre IBMi et on a parfois besoin d’avoir des informations d’exécution

Voici comment connaitre la version de la JVM d’un travail ?

2 solutions simples

==> WRKJWMJOB

Puis 5 puis 1

Ou en utilisant sql services par la vue QSYS2.JVM_INFO

exemple :

select JOB_NAME, JAVA_HOME from qsys2.JVM_INFO

plus d’informations ici

https://www.ibm.com/docs/en/i/7.3?topic=usage-java-system-properties

, Extraire simplement vos références Web Services <-> Programme (de service)

Nous développons de plus en plus de web services grâce à IWS (Integrated Web Services).

L’implémentation de ces services peut être un programme, un programme de service, ou SQL. Par ailleurs, les deux dernières solutions nous permettent d’avoir des services avec plusieurs opérations (vocabulaire SOAP) ou routes (vocabulaire REST). Quoiqu’il en soit, plusieurs actions possibles au travers d’un unique service.

La question se pose désormais à plus grande échelle des impacts sur la maintenance des programmes et programmes de service sous-jacents à des services web !

Concrètement : je modifie un programme (de service) : comment savoir s’il est exposé en tant que service web ?

Scripts fournis

IWS est fourni avec des scripts, dans le répertoire /QIBM/ProdData/OS/WebServices/bin

Ces scripts permettent d’automatiser toutes les actions possibles, autrement disponibles via l’interface d’administration :

Nous vous recommandons leur usage pour déployer vos services par exemple, de façon automatique avec vos outils.

Ces scripts sont également capables d’extraire des informations des serveurs et services !

Extraction

Pour le principe ici, un script shell qui utilise ces fonctionnalités pour lister tous les services et récupérer tous les programmes (de service) référencés ! Le résultat est stocké en BD. C’est perfectible, mais démontre le fonctionnement :

#
# Extraire les références croisées web service <-> programme/programme de service
#

# Paramètres : bibliothèque de création du fichier 

export PATH=$PATH:/QIBM/ProdData/OS/WebServices/bin

# créer le fichier BD pour stocker les liens
db2 "create or replace table $1.wsxref (server varchar(10), service varchar(128), program varchar(128)) on replace delete rows"

# Lister les serveurs sans tenir compte de l'état (started/stopped)
servers=$(listWebServicesServers.sh | sed 's/(.*//' )
# Pour chaque serveur listé
for server in $servers ; do
  # Retourver les services sans tenir compte de l'état
  services=$(listWebServices.sh -server $server | sed 's/(.*//')
  # Pour chaque service
  for service in $services ; do
#   # Retrouver les propriétés. Ne garder que l'implémentation
	program=$(getWebServiceProperties.sh -server $server -service $service | grep -i 'Program object path:' | sed 's/Program object path://')
	echo $server $service $program
    db2 "insert into $1.wsxref values('$server', '$service', trim('$program'))"
  done
done

Le code est disponible ici : https://github.com/FrenchIBMi/webservices/blob/master/wsxref.sh

Une fois le script lancé (prévoyez un café le temps de l’exécution) :

Et voilà !

Vous pouvez l’appeler dans QSH, le planifier (commande QSH …), le mettre dans un CL. Et surtout intégrer le résultat dans vos outils d’analyse !