, Générer des données avec MAPEPIRE en PYTHON

/

Nouveau venu dans les bibliothèques middleware pour IBMi, MAPEPIRE est un outil simple pour récupérer des données de votre serveur et les travailler sur de applications tierces, telles que des outils d’analyse de données, de la bureautique, etc.

Nous allons vous présenter la possibilité d’installer et d’utiliser le produit simplement

  • sur le serveur
  • sur votre client, en fonction du langage que vous souhaitez utiliser.
  • Les langages disponibles pour l’instant sont :
  • JAVA, NODE.JS, PYTHON

Ici, l’exemple détaillé sera effectué avec le langage PYTHON.

Nous n’intervenons pas dans cet article sur les différents paramétrages de l’outil. Nous y reviendrons dans un article suivant. (exit points, ports, etc.)

Serveur

Installation de MAPEPIRE sur le serveur

yum install mapepire

mapepire sera installé dans le répertoire

/qOpenSys/pkgs/bin

Démarrage

Note : dans cet article, on ne détaille ps le démarrage automatique

nohup /qopensys/pkgs/bin/mapepire &

Client

Notre exemple consiste à lister tous les travaux actifs en cours, les répertorier dans une trame PANDAS, puis de sauvegarder les données dans une feuille EXCEL

Pré requis

  • Python 3 installé et fonctionnel
  • un répertoire pour le code
  • Facultatif : un environnement virtuel
  • EXCEL
  • librairies installées :
    • pandas
    • openpyxl (factultatif)

installation MAPEPIRE

sous l’environnement virtuel (si configuré) ou sur l’environnement global

pip install mapepire-python

le code de notre exemple TEST.PY

#mapepire

#mapepire
from mapepire_python.client.sql_job import SQLJob
from mapepire_python import DaemonServer

#pandas
import pandas as pd
#--------------------------------------------------
creds = DaemonServer(
    host="serveuràcontacter",
    port=8076,
    user="utilisateur",
    password='motdepasse',
    ignoreUnauthorized=True,
)

job = SQLJob()
res = job.connect(creds)

#
# Travaux actifs
#
result = job.query_and_run("\
            SELECT \
                count(*) as totaltravaux\
            FROM TABLE (QSYS2.ACTIVE_JOB_INFO()) \
            ")
countjobs = result['data'][0]['TOTALTRAVAUX']

startT = datetime.now()
result = job.query_and_run("SELECT \
                JOB_NAME, JOB_TYPE, JOB_STATUS, \
                SUBSYSTEM, MEMORY_POOL, THREAD_COUNT \
            FROM TABLE ( \
                QSYS2.ACTIVE_JOB_INFO(\
                    RESET_STATISTICS => 'NO',\
                    SUBSYSTEM_LIST_FILTER => '',\
                    JOB_NAME_FILTER => '*ALL',\
                    CURRENT_USER_LIST_FILTER => '',\
                    DETAILED_INFO => 'NONE'\
                )\
            ) \
            ORDER BY \
                SUBSYSTEM, RUN_PRIORITY, JOB_NAME_SHORT, JOB_NUMBER\
            ",
            rows_to_fetch=countjobs)

endT = datetime.now()
delta = endT - startT
print(f"travaux actifs récupérés en {str(delta)} secondes")
#insertion des résultats dans un Frame PANDAS
dframActj = pd.DataFrame(result['data'])
#print(dframActj)

#
#récupération des utilisateurs dans une 2ème Frame (dframUsesrs)
#
startT = datetime.now()
result = job.query_and_run("""
        WITH USERS AS (
            SELECT 
               CASE GROUP_ID_NUMBER 
                   WHEN 0 THEN 'USER' 
                   ELSE 'GROUP' 
               END AS PROFILE_TYPE, 
               A.*, 
               CAST(TEXT_DESCRIPTION AS VARCHAR(50) CCSID 1147) 
                   AS TEXT_DESCRIPTION_CASTED 
            FROM ( 
                    SELECT * 
                        FROM QSYS2.USER_INFO 
                ) AS A 
        ) 
        SELECT * 
            FROM USERS 
        """,
        rows_to_fetch=500)
endT = datetime.now()
delta = endT - startT
print(f"Utilisateurs récupérés en {str(delta)} secondes")
#insertion des résultats dans un Frame PANDAS
dframUsers = pd.DataFrame(result['data'])
#print(dframUsers)


print("Sauvegarde vers Excel")
with pd.ExcelWriter('/users/ericfroehlicher/Documents/donnes_dataframe.xlsx') as writer:  
    dframActj.to_excel(writer, sheet_name='ACTjobs')
    dframUsers.to_excel(writer, sheet_name='Utilisateurs')

Un peu d’explications

1 – Import des resources dont on a besoin

#mapepire
from mapepire_python.client.sql_job import SQLJob
from mapepire_python import DaemonServer

#pandas
import pandas as pd

2 – Déclaration des données de connexion (serveur, utilisateur, mot def passe)

CONSEIL: pour l’instant, toujours laisser le port 8076

#--------------------------------------------------
creds = DaemonServer(
    host="serveuràcontacter",
    port=8076,
    user="utilisateur",
    password='motdepasse',
    ignoreUnauthorized=True,
)

P

3 – connexion au serveur

job = SQLJob()
res = job.connect(creds)

Ici, on crée un travail simple, synchrone (SQLJob)

4 – les requêtes synchrones

#comptage des travaux (pour l'exemple de l'utilisation du json)
result = job.query_and_run("\
            SELECT \
                count(*) as totaltravaux\
            FROM TABLE (QSYS2.ACTIVE_JOB_INFO()) \
            ")
# je récupère directement la valeur lue
countjobs = result['data'][0]['TOTALTRAVAUX']

result = job.query_and_run("SELECT \
                JOB_NAME, JOB_TYPE, JOB_STATUS, \
                SUBSYSTEM, MEMORY_POOL, THREAD_COUNT \
            FROM TABLE ( \
                QSYS2.ACTIVE_JOB_INFO(\
                    RESET_STATISTICS => 'NO',\
                    SUBSYSTEM_LIST_FILTER => '',\
                    JOB_NAME_FILTER => '*ALL',\
                    CURRENT_USER_LIST_FILTER => '',\
                    DETAILED_INFO => 'NONE'\
                )\
            ) \
            ORDER BY \
                SUBSYSTEM, RUN_PRIORITY, JOB_NAME_SHORT, JOB_NUMBER\
            ",
            rows_to_fetch=countjobs)

A

Les données obtenues sont au format JSON. (voir plus bas les données brutes)

5 – Insertion des données dans un frame PANDAS et sauvegarde vers EXCEL

#insertion des résultats dans un Frame PANDAS
dframe = pd.DataFrame(result['data'])
print(dframe)

print("Sauvegarde vers Excel")
dframe.to_excel(
     "/users/ericfroehlicher/Documents/travaux_actifs.xlsx",
    sheet_name="Travaux actifs", 
    index=False
)

Retour de mapepire

Le flux de données renvoyé par MAPEPIRE contient l’ensemble des données et méta données au format JSON.

Voici un extrait du flux retourné (exemple sur 5 travaux)

{
  'id': 'query4', 
  'has_results': True, 
  'update_count': -1, 
  'metadata': 
  {
     'column_count': 6, 
     'job': '488835/QUSER/QZDASOINIT', 
     'columns':[
      {
        'name': 'JOB_NAME', 
        'type': 'VARCHAR', 
        'display_size': 28, 
        'label': 'JOB_NAME'
      }, 
      {
        'name': 'JOB_TYPE', 
        'type': 'VARCHAR', 
        'display_size': 3, 
        'label': 'JOB_TYPE'
      }, 
      {
        'name': 'JOB_STATUS', 
        'type': 'VARCHAR', 
        'display_size': 4, 
        'label': 'JOB_STATUS'
      },    
      {
        'name': 'SUBSYSTEM', 
        'type': 'VARCHAR', 
        'display_size': 10, 
        'label': 'SUBSYSTEM'
      }, 
      {
        'name': 'MEMORY_POOL', 
        'type': 'VARCHAR', 
        'display_size': 9, 
        'label': 'MEMORY_POOL'
      }, 
      {
        'name': 'THREAD_COUNT', 
        'type': 'INTEGER',
        'display_size': 11, 
        'label': 'THREAD_COUNT'
      }
      ]
  }, 
  'data':[
  {
    'JOB_NAME': '216350/QSYS/ARCAD', 
    'JOB_TYPE': 'SBS', 
    'JOB_STATUS': 'DEQW', 
    'SUBSYSTEM': 'ARCAD', 
    'MEMORY_POOL': 'BASE', 
    'THREAD_COUNT': 2
  }, 
  {
    'JOB_NAME': '216369/ARCAD_NET/ARCAD', 
    'JOB_TYPE': 'ASJ', 
    'JOB_STATUS': 'MSGW', 
    'SUBSYSTEM': 'ARCAD', 
    'MEMORY_POOL': 'BASE', 
    'THREAD_COUNT': 1
  }, 
  {
    'JOB_NAME': '216349/QSYS/CONTROL4I', 
    'JOB_TYPE': 'SBS', 
    'JOB_STATUS': 'DEQW', 
    'SUBSYSTEM': 'CONTROL4I', 
    'MEMORY_POOL': 'BASE', 
    'THREAD_COUNT': 2
  }, 
  {
    'JOB_NAME': '216373/CTL4I/CTAGENTSPW', 
    'JOB_TYPE': 'PJ', 
    'JOB_STATUS': 'PSRW', 
    'SUBSYSTEM': 'CONTROL4I', 
    'MEMORY_POOL': 'BASE', 
    'THREAD_COUNT': 1
  }, 
  {
    'JOB_NAME': '216377/CTL4I/CTAGENTSPW', 
    'JOB_TYPE': 'PJ', 
    'JOB_STATUS': 'PSRW', 
    'SUBSYSTEM': 'CONTROL4I', 
    'MEMORY_POOL': 'BASE', 
    'THREAD_COUNT': 1
  }
  ], 
  'is_done': False, 
  'success': True
}

Résultats