, , Moderniser vos menus IBMi

Vous pouvez désormais accèder aux fichiers des messages par SQL grace à la vue SQL QSYS2.MESSAGE_FILE_DATA.

Vos menus personnalisés utilisent des commandes qui sont stockés dans des fichiers messages

Voici une idée pour améliorer vos menus

l’idée c’est prendre la commande à éxecuter et l’afficher, vous pouver customizer l’affichage du texte

J’ai publié le code sur github l’adresse suivante : https://github.com/Plberthoin/PLB/tree/master/GTOOLS

Vous devez récupérer, un dds , un sqlrpgle et une cmd

Voila qui peut vous donner des idées pour la gestion de vos fichiers messages

, , Authentification par JWT (Json Web Token)

Pour mettre en place une authentification par JWT sur IBMi, on utilise l’API Qc3VerifySignature.

Le JWT

Il est composé de trois partie :

  • Un entête (header)
  • Une charge utile (payload)
  • Une signature numérique

Pour obtenir la signature, il faut tout d’abord encoder séparément le header et le payload avec BaseURL64, ensuite, on les concatène en les séparant d’un point.

On calcule enfin une signature d’après le header et le payload afin de garantir que le jeton n’a pas été modifié, d’après l’algorithme défini dans le header (RS256, HS256, HS512, …). Cette signature binaire est elle-même encodée ensuite en Base64URL.

On obtient ainsi le JWT : { header }.{ payload }.{ signature }

Préparation

Afin de tester cette API, il faut dans un premier temps générer une clé au format PEM en suivant les étapes ci-dessous :

  • openssl req -new -out monserveur.csr

Pour créer une demande certificate (.csr = certificat signing request)

Cela crée deux fichiers : monserveur.csr et privkey.pem

  • openssl rsa -in privkey.pem -out monserveur.key

Cela crée le fichier monserveur.key (clé privée sans le mot de passe)

  • openssl x509 -in monserveur.csr -out monserveur.cert -req -signkey monserveur.key

Cela crée le fichier monserveur.cert, qui est le certificat.

Paramètres d’appels de Qc3VerifySignature

  • Signature

La signature est fournie en BASE64, il faut la convertir en binaire pour la fournir à l’API

  • Longueur de signature

La longueur de la signature fournie après sa conversion

  • Donnée à contrôler

{ header }.{ payload } en ASCII

  • Longueur de la donnée à contrôler
  • Format de la donnée à contrôler
  • Description de l’algorithme

C’ ‘est une Data Structure qui contient les paramètres de l’algorithme.

  • Format de la description de l’algorithme
  • Description de la clé

C’ ‘est une Data Structure qui contient les paramètres de la clé.

  • Format de la description de la clé
  • Fournisseur de service cryptographique (0, 1 ou 2)
  • Nom du périphérique de cryptographie (à blanc si fournisseur 1 ou 0)
  • Code Erreur

C’est une Data Structure qui indique le code retour de l’exécution

Cinématique

Pour mettre en place l’appel à Qc3VerifySignature, nous avons défini les formats suivants :

  • Données             DATA0100 : La donnée est contrôlée sur sa valeur et sa longueur
  • Algorithme         ALGD0400 : Paramètres pour une opération de vérification de signature
  • Clé                      KEYD0600 : Certificat PEM (voir paragraphe « Préparation »)

Données

On crée la donnée à contrôler en concaténant header et payload, séparés d’un point, comme expliqué au paragraphe précédent.

Exemple :

ATTENTION : Il faut, pour être utilisable, que celle-ci soit en ASCII. Pour ce faire on utilise le programme système QDCXLATE qui permet de faire de la conversion de chaines de caractères grâce à des tables système.

Data Structure du format ALGD0400 (algorithme) :

cipher   INT(10) inz(50)                  // Code secret pour RSA , initialisé à 50

PKA      CHAR(1) inz(1)                  // PKCS bloc 01

filler   CHAR(3) inz(x’000000’)      // Réservé : ce champ doit rester NULL

hash     INT(10) inz(3)                   // Signature Algorithme de Hash 3=SHA256

Data Structure du format KEYD0600 (clé) :

keylen INT(10)                                       // Longueur du certificat PEM

filler CHAR(4) inz(x’00000000′)           // Réservé : ce champ doit rester NULL

key CHAR(4096) CCSID(65535)           // Certificat PEM en ASCII

Code Retour

L’appel de l’API avec les paramètres choisis , retourne un Data Structure ErrorCode décrite ci-dessous :

bytesProv  INT(10) inz( %size( ErrorCode ) ); // ou 64 pour voir MSGID

bytesAvail INT(10) inz(0);

MSGID CHAR(7);

filler CHAR (1);

data  CHAR (48);

Dans le cas où la signature est vérifiée, les valeurs retour sont les suivantes

  • BYTESPROV = 64                                          
  • BYTESAVAIL = 0                                          
  • MSGID = ‘       ‘                                       
  • FILLER = ‘ ‘                                            
  • DATA = ‘                                                ‘

Si la signature n’est pas vérifiée, les valeurs retour seront  :

  • BYTESPROV = 64                                          
  • BYTESAVAIL = 15                                         
  • MSGID = ‘CPF9DEF’                                       
  • FILLER = ‘0’                                            
  • DATA = ‘                                                ‘
, Télécharger PTF par FTPS

Téléchargement de PTF par FTP

Depuis mi-juillet , ce n’est plus un choix le mode FTP simple en anonymous ne fonctionne plus , vous le voyez quand vous allez sur fix central le mode ftps ou sftp est par défaut .

Quand vous faites votre demande sous recevez désormais 3 mails au lieu de 2
-Le premier, pour vous dire que votre demande a été prise en compte.
-Le deuxième, pour vous indiquer les instructions à passer pour votre téléchargement
-Le Troisième (nouveau) qui contiendra le mot de passe que vous devrez utiliser

Comment faire désormais pour télécharger ces PTFs, on va voir 2 méthodes ?

1) A partir de Filezilla


Le logiciel connait le certificat racine Digicert
donc si vous vous connectez en ssl sur le site delivery01-bld.dhe.ibm.com ,il vous propose la première fois de télécharger le certificat.

Et vous pouvez faire votre téléchargement .

2) A partir de votre partition IBMi

Il va vous falloir installer le certicicat racine Digicert et le certificat du site dans DCM qui gére les certificats coté IBMi.

il est conseiller pour faire ses installations d’utiliser le logiciel QMGTOOLS.

nous vous conseillons également de le mettre à jour pour éviter les problémes.

ADDLIBLE LIB(QMGTOOLS)
GO MENU(MG)

  1. Check IBM for updated QMGTOOLS

Vous pouvez donc maintenant faire vos installations

Le certificat racine est disponible ici

https://www.ibm.com/support/pages/node/1077897

Vous devez dezipper vos fichiers et les copier dans l’IFS de votre IBM i par exemple /temp

Vous allez utilisez la première commande suivante
GETSSL pour le certifcicat racine
détail ici
https://www.ibm.com/support/pages/node/683901
et pour installer le certificat vous allez à nouveau utiliser la commande GETSSL avec le paramétrage suivant
QMGTOOLS/GETSSL IP(WWW.ECUREP.IBM.COM)
PORT(443)
AUTOIMP(Y)
STOREPWD(‘votre mot de passe’)

Si vous allez dans DCM vous avez un nouveau certificat installé QMG0001

Vous pouvez désormais vous connecter au site avec la commande suivante

FTP RMTSYS(‘delivery01-bld.dhe.ibm.com’) SECCNN(*SSL)

Attention cependant vous devrez forcer le mode par la commande FTP SENDEPRT

Voila, une fois que vous avez paramétrer vous pouvez utiliser télécharger vos PTFs comme avant.

, , Comment repérer les requêtes SQL consommatrices sur votre IBMi

Comment voir à un instant donné , le requêtes les plus consommatrices de votre système ?

Vous êtes sans doute demandé comment connaitre les requêtes SQL qui consomment sur votre système voici une solution.

Nous allons utiliser un dump du plan cache , vous pouvez aussi y accéder par ACS en quelques clics

Voici une méthode qui va vous permettre d’automatiser et de trouver plus rapidement un problème.

Commencer par supprimer le fichier qui va servir à extraire le dump

Drop table gdata.dump_cache ;

Extrayez le cache dump dans votre fichier de travail

CALL QSYS2.DUMP_PLAN_CACHE (fileschema => ‘GDATA’ ,
Filename => ‘DUMP_CACHE’) ;

Exécuter une requête sur ce fichier

Dans notre exemple, on sélectionne les jobs actifs sur le système
on sélectionne les requêtes SELECT
et on trie par consommation descendante !

With job_act (JOB_NAME_SHORT, JOB_USER, JOB_NUMBER, JOB_USER_IDENTITY)
as (SELECT JOB_NAME_SHORT, JOB_USER, JOB_NUMBER,JOB_USER_IDENTITY
FROM TABLE (QSYS2.ACTIVE_JOB_INFO(DETAILED_INFO => ‘ALL’)) X
where substr(job_user_identity, 1, 1) <> ‘Q’
)
Select qqjob, qquser, qvc102, qqjnum, qq1000, qqi6 as temps_execution
from gdata.dump_cache a join job_act b on
QQJOB = JOB_NAME_SHORT and QQUSER = JOB_USER and QQJNUM = JOB_NUMBER
where substr(QQ1000 , 1, 6) = ‘SELECT’
order by qqi6 desc

Vous pouvez changer vos critères de tri et de sélection, ici on est en mode pompier ?
Vous pouvez plannifier cette requête et la faire retourner plusieurs fois par jour sur votre système en gardant le résultat ou les dump cache

Nous avons packagé ce scripte pour faire une commande WRKSQLJOB que vous pouvez trouver ici !

https://github.com/Plberthoin/PLB/tree/master/GTOOLS


Vous retrouvez également une version un peu plus évoluée dans notre produit GODBC
https://www.gaia.fr/produits/

Les sites à connaitre, si vous voulez aller plus loin

https://www.ibm.com/docs/en/i/7.4?topic=services-dump-plan-cache-procedure
https://www.ibm.com/docs/en/i/7.4?topic=cache-creating-snapshots
https://www.ibm.com/docs/api/v1/content/ssw_ibm_i_74/pdf/rzajqpdf.pdf

, , , Renommer votre serveur LDAP Pour EIM

Vous utilisez la solution de single signon sur IBMi à base de kerberos et EIM

Votre serveur LDAP change de nom

Voici la liste des opérations à effectuer

Sur le serveur LDAP, vous n’avez rien à faire

Sur le serveur Kerberos

Vous avez 2 modifications à faire

Changer le nom du KDC sur l’onglet principal

Changer le nom du serveur de mot de passe sur l’onglet Serveur de mot de passe

Sur le serveur EIM

Sur le domaine changer le registre kerberos

Créer un nouveau registre utilisateurs de type source kerberos

et vous devrez ensuite sur chaque inscription remplacer votre source par le nouveau serveur

Ca peut être long si vous n’avez pas d’outils pour le faire

Chez nous notre produit GEIM peut vous aider dans cette tache

, , , QCMDEXC en Fonction SQL

Depuis la TR4 de la version V7R4, vous pouvez utiliser la fonction QCMDEXC

C’est l’occasion de faire un rappel sur les différents usages disponibles jusque la

1 ) C’est une api (un programme) que vous pouvez appelez depuis un programme RPG ou CLP

en RPGLE

Dcl-Pr Exec_Commande QCMDEXC ExtPgm(‘QCMDEXC’);
Cmd Char(3000) Const;
CmdLen packed(15:5) Const;
End-Pr;

Dcl-S Gbl_Cmd Char(3000);

Gbl_Cmd = ‘Votre commande’ ;

Exec_commande(Gbl_Cmd : %len(Gbl_Cmd)) ;

En CLLE

PGM
DCL &CMD *CHAR 300
DCL &LEN *DEC (15 5)

CHGVAR &CMD (‘VOTRE COMMANDE’)
CHGVAR &LEN %LEN(&CMD)
CALL QCMDEXC (&CMD &LEN)

2) C’est une procédure SQL

call qcmdexc(‘votre commande’)

en sql embarqué

Dcl-S Gbl_Cmd Char(3000);

call qcmdexc(:Gbl_Cmd)

3) C’est une Fonction SQL à partir de la TR4

réorganisation des fichiers BD

SELECT qcmdexc(‘RGZPFM FILE(‘ concat
trim(substr(TABLE_SCHEMA, 1 , 10))
concat ‘/’ concat
substr(TABLE_NAME, 1 , 10) concat ‘)’) as résultat
FROM systables WHERE TABLE_SCHEMA =
‘GDATA’ and FILE_TYPE = ‘D’

la fonction renvoi 1 si ok et -1 si ko

Conclusion :
Vous avez un aperçu des possibilités qcmdexc sur la machine, à vous de jouer !

, , , Surveillez vos requêtes SQL sur votre #ibmi

Il est possible que vous ayez des doutes sur les performances de vos requêtes SQL, voici comment avoir une idée rapide de ce qui tourne

On va utiliser ACS
dans Base de données choisir
SQL Performance center

Vous avez un onglet Affichage des instructions

Vous choisissez le filtre à appliquer , Ici on choisit les actives, vous pouvez être beaucoup plus pertinent en limitant votre choix.

Une fois que vous avez repéré une requête candidate, il vous suffit de faire un clique droit sur celle ci et vous pouvez lancer directement Visual Explain, qui vous expliquera le comportement de cette requête, vous pourrez alors faire les ajustements qui s’imposent

Le résultat dans V-E

PS:
Le principal critère de performance sur SQL, c’est les indexes, pensez à surveiller les suggestions faites par Index Advisor

Une des nouveautés de TR4 c’est Query Supervisor

L’idée est de limiter les requêtes selon certain critéres (de temps d’éxécution , d’espace temporaire occupé etc… )
Jusqu’à présent c’était pas toujours simple et un peu binaire

Ajout d’un seuil à contrôler

Ce fait par la procédure QSYS2.ADD_QUERY_THRESHOLD

Exemple

CALL QSYS2.ADD_QUERY_THRESHOLD(THRESHOLD_NAME => ‘Seuil’,
THRESHOLD_TYPE => ‘CPU TIME’,
THRESHOLD_VALUE => 1,
INCLUDE_USERS => ‘PLB’,
DETECTION_FREQUENCY => 60)

vous devez indiquer
un nom ici Seuil
le seuil à controler
une valeur pour ce seuil
un filtre d’inclusion ou d’exclusion ici inclusion du profil PLB
Un délai de raffraichissemnt en seconde

Vous avez une vue qui permet de voir les seuils définis sur votre partition

c’est la vue QUERY_SUPERVISOR

exemple

voir tous les seuils définis pour Query supervisor

SELECT *
FROM QSYS2.QUERY_SUPERVISOR ORDER BY THRESHOLD_TYPE, THRESHOLD_VALUE DESC;

;

Vous pouvez indiquer un programme d’exit QIBM_QQQ_QRY_SUPER

ci joint un exemple basic pour expliquer ce qui ce passe

pgm parm(&qrysupdta &returncod)
/* Paramètres */
dcl &qrysupdta *char 1024
dcl &returncod char 8

/* Variables de Travail */

DCL VAR(&SIZ_HEADER) TYPE(CHAR) LEN(4) +
STG(DEFINED) DEFVAR(&qrysupdta 1)

DCL VAR(&FMT_NAME) TYPE(CHAR) LEN(8) +
STG(DEFINED) DEFVAR(&qrysupdta 5)

DCL VAR(&JOB_NAME) TYPE(CHAR) LEN(10) +
STG(DEFINED) DEFVAR(&qrysupdta 13)

DCL VAR(&JOB_USER) TYPE(CHAR) LEN(10) +
STG(DEFINED) DEFVAR(&qrysupdta 23)

DCL VAR(&JOB_NUMBER) TYPE(CHAR) LEN(6) +
STG(DEFINED) DEFVAR(&qrysupdta 33)

DCL VAR(&SUBSYSTEM) TYPE(CHAR) LEN(10) +
STG(DEFINED) DEFVAR(&qrysupdta 39)

DCL VAR(&Usr_name) TYPE(CHAR) LEN(49) +
STG(DEFINED) DEFVAR(&qrysupdta 23)

DCL VAR(&QRYPLANID) TYPE(CHAR) LEN(08) +
STG(DEFINED) DEFVAR(&qrysupdta 67)

DCL VAR(&THR_NAME) TYPE(CHAR) LEN(60) +
STG(*DEFINED) DEFVAR(&qrysupdta 75)
dcl &msg *char 2056
chgvar &msg (&JOB_NAME *cat ‘/’ *cat &JOB_USER *tcat ‘/’ *tcat +
&JOB_NUMBER *bcat ‘Arreté pour dépassement, ‘ *bcat &THR_NAME)
SNDUSRMSG MSG(&MSG)
/* on force l’arret de la requete */
CHGVAR VAR(%BIN(&returncod 1 4)) VALUE(1)
ENDPGM
Pour en savoir plus le lien ici

https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/xqrysuper.htm

Le message ne cas de débordement

Le message remonté depuis notre programme d’exit

Vous pouvez enlever vos seuils

c’est la procédure REMOVE_QUERY_THRESHOLD

CALL QSYS2.REMOVE_QUERY_THRESHOLD(THRESHOLD_NAME => ‘Seuil’);

vous indiquer le nom que vous avez donné à votre seuil

Conclusion

C’est bonne nouveauté pour les administrateurs DB2

On peut regretter l’absence du procédure de change qui permettrait de revenir sur les paramètres de définition

, , UTILISATION DES API EN SQL

Récupérer une API

Il existe un grand nombre d’API aux fonctionnalités diverses dont certaines nous permettent de récupérer des données structurées dans différents formats (XML, JSON, …).

Grace aux fonctions SQL de l’IBMi nous pouvons récupérer ces données pour les insérer dans les fichiers de la base de données.

Pour les exemples qui suivent, on se base sur trois API tirées du site https://openweathermap.org/ :

  • Une première qui récupère la météo dans une ville donnée

https://api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}&mode=xml’

  • Une qui récupère jusqu’à 50 communes autour de coordonnées choisies

https://api.openweathermap.org/data/2.5/find?lat=45.75&lon=4.5833&cnt=50&appid={API key}&mode=xml

  • Une qui récupère jusqu’à des communes dans un rectangle de coordonnées choisies

https:// api.openweathermap.org/data/2.5/box/city?bbox=4,45,8,46,50&appid={API key}

Extraire les données de l’API

Sortie API en XML

La commande SQL suivante permet d’afficher les données dans un champ DATA 

SELECT DATA FROM (values
char(SYSTOOLS.HTTPGETCLOB('https://api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}&mode=xml',''), 4096))
ws(data);

Sortie API en JSON

La commande SQL suivante permet d’afficher les données dans un champ DATA 

SELECT DATA FROM (values
char(SYSTOOLS.HTTPGETCLOB('api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}',''), 4096))
ws(data);

Sortie API en HTML

La commande SQL suivante permet d’afficher les données dans un champ DATA 

SELECT DATA FROM (values
char(SYSTOOLS.HTTPGETCLOB('https://api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}&mode=html',''), 4096))
ws(data);

Récupération des données

En XML

On crée un fichier qui contiendra les colonnes que l’on veut récupérer (Ville, Température en cours, date, …)

CREATE TABLE GG/METEODB
(VILLE_ID DECIMAL (9, 0) NOT NULL WITH DEFAULT,
VILLE_NOM CHAR (50) NOT NULL WITH DEFAULT,
TEMPERATURE DECIMAL (5, 2) NOT NULL WITH DEFAULT,
TEMP_MIN DECIMAL (5, 2) NOT NULL WITH DEFAULT,
TEMP_MAX DECIMAL (5, 2) NOT NULL WITH DEFAULT,
DATE_MAJ CHAR (20) NOT NULL WITH DEFAULT)
;

Récupérer les données de l’API dans le fichier créé :

INSERT INTO GG.METEODB
select xdata.* FROM xmltable('$doc/cities/list/item'
PASSING XMLPARSE(document SYSTOOLS.HTTPGETCLOB('https://api.openweathermap.org/data/2.5/find?lat=45.75&lon=4.5833&cnt=10&appid={API key}&mode=xml','')) AS "doc"
COLUMNS
ville_id decimal(9, 0) PATH 'city/@id',
ville_nom varchar(50) PATH 'city/@name',
temperature decimal(5, 2) PATH 'temperature/@value',
temp_min decimal(5, 2) PATH 'temperature/@min',
temp_max decimal(5, 2) PATH 'temperature/@max',
date_maj varchar(20) PATH 'lastupdate/@value' ) as xdata;

En JSON

Contrairement à XML, on peut créer tout de suite un fichier qui contiendra les colonnes que l’on veut récupérer.

CREATE TABLE GG.METEOBD
(VILLE_ID DECIMAL (9, 0) NOT NULL WITH DEFAULT,
VILLE_NOM CHAR (50) NOT NULL WITH DEFAULT,
TEMPERATURE DECIMAL (5, 2) NOT NULL WITH DEFAULT,
TEMP_MIN DECIMAL (5, 2) NOT NULL WITH DEFAULT,
TEMP_MAX DECIMAL (5, 2) NOT NULL WITH DEFAULT,
DATE_UX_MAJ DECIMAL (12, 0) NOT NULL WITH DEFAULT)

Récupérer les données de l’API dans le fichier créé :

INSERT INTO GG.METEOBD
select * from JSON_TABLE(SYSTOOLS.HTTPGETCLOB('https://api.openweathermap.org/data/2.5/box/city?bbox=4,45,8,46,50&appid={API key}','') ,
'$.list[*]'
COLUMNS
(ville_id decimal(9, 0) PATH '$.id',
ville_nom varchar(50) PATH '$.name',
temperature decimal(5, 2) PATH '$.main.temp',
temp_min decimal(5, 2) PATH '$.main.temp_min',
temp_max decimal(5, 2) PATH '$.main.temp_max',
date_ux_maj decimal(12, 0) PATH '$.dt'));

Pour aller plus loin

En utilisant une API de LA POSTE qui ne nécessite pas d’inscription au préalable, ni d’identification. Nous pouvons réaliser un programme qui nous aide à retrouver une commune à partir d’un code postal, dans l’optique d’aider au remplissage de certains formulaires.
On crée un fichier temporaire en interrogeant directement l’API.

, , Variables SQL utilisables dans vos scriptes ?

Voici quelques variables que vous pouvez utiliser dans vos requêtes SQL

par exemple Client_Ipaddr qui est arrivée avec la TR4

Quelques registres et variables d’environnement

select
current time as heure_en_cours,
current date as date_en_cours,
current user as utilisateur_courant,
current timestamp as timestamp_en_cours,
CURRENT CLIENT_ACCTNG as Client_connexion,
CURRENT CLIENT_APPLNAME as Client_Application,
Current timezone as Fuseau_Horaire,
Current server as Current_Server ,
current path as Current_path,
CURRENT CLIENT_APPLNAME as Programme_client,
CURRENT CLIENT_USERID as Utilisateur_client,
CURRENT CLIENT_PROGRAMID as Programme_client
from sysibm.sysdummy1

Quelques Variables globales dans SYSIBM

select
SYSIBM.Client_Host as Client_Host,
SYSIBM.Client_Ipaddr as Client_Ipaddr,
SYSIBM.Client_Port as Client_Port,
SYSIBM.Package_Name as Package_Name,
SYSIBM.Package_Schema as Package_Schema,
SYSIBM.Package_Version as Package_Version,
SYSIBM.Routine_Schema as Routine_Schema,
SYSIBM.Routine_Specific_Name as Routine_Specific_Name,
SYSIBM.Routine_Type as Routine_Type
from sysibm.sysdummy1

Comme dans nos exemples, ces variables sont utilisable dans vos requêtes

exemple

les travaux actifs de l’utilisateurs en cous