Créer une application Perl autour de MySQL : Mise en place (1/3)

Magazine
Marque
GNU/Linux Magazine
Numéro
168
Mois de parution
février 2014
Spécialité(s)


Résumé

C'est l'histoire d'un hacker à qui on a demandé de créer des pages web pour le suivi de la production logicielle de la société. Historiquement, toutes les informations étaient gérées à la main, ce qui est une solution inacceptable pour tout hacker qui se respecte.


Body

Le but de cette série d'articles est de vous montrer comment on peut utiliser Perl, MySQL, phpMyAdmin, les modules DBIx::Class, DBIx::Class::Schema::Loader et HTML::Tiny pour gérer ces informations d'une manière plus efficace. Ces articles vont donner une vision d'ensemble sur une solution mettant en jeu plusieurs technologies au lieu de se focaliser sur un domaine bien précis.

Ce premier article va expliquer les besoins de l'application, la structure de la base de données et comment créer cette structure dans une base MySQL avec phpMyAdmin. Au passage, on verra les principes de base des relations entre les tables et l'utilisation des index et des clés étrangères (foreign keys) pour que MySQL assure la cohérence des entités de l'application.

1. Introduction

Le problème à résoudre : comme toute société informatique qui se respecte, nous produisons plusieurs produits logiciels. Chaque produit évolue et cette évolution est traduite en termes de version. Et comme dans toute société, les noms de code et numéros de version utilisés pendant le développement correspondent rarement avec ceux décidés (tardivement) par le marketing. Devant cette profusion de noms de codes et de versions, il est difficile de s'y retrouver. J'ai donc été chargé d'écrire une application qui fournit des pages d'information résumant la situation.

Donc, pour générer ces pages, il faudra gérer la correspondance entre :

- un produit tel qu'il est vu par le marketing (et par le client) avec :

-- un nom de produit en général évocateur de simplicité et de performances pour appâter le client,

-- quelques informations supplémentaires (release notes) ;

- une version de produit dont le numéro est en général décidé tard dans le cycle de développement ;

- Cette version de produit est déclinée en fonction de l'environnement cible : distribution (RHEL 5 ou RHEL 6) et architecture (i386 ou x86_64) et est livrée dans un fichier tar.

- Un ensemble de paquets RPM contenus dans ces fichiers tar.

En termes de relations, on va avoir :

- un produit va contenir plusieurs versions marketing,

- chaque version marketing va contenir plusieurs fichiers tar,

- chaque fichier tar va contenir plusieurs paquets (RPM dans ce cas de figure),

- un paquet peut faire partie de plusieurs fichiers tar.

Une fois qu'on a tout ça en place, le but est de remplir les données des versions avec Perl et DBIx::Class, puis de produire des pages HTML décrivant chaque release et ses différents composants.

Pour ne pas compliquer cet article, on va ignorer le problème de suivi des bogues et des corrections associés à chaque version.

2. La base de données

2.1 Structure des données

On a vu dans l'introduction que nous avons affaire à des données structurées avec des relations entre les différentes entités :

- relation « un avec plusieurs » (one-to-many) entre les produits, versions marketing et fichiers tar ;

- relation « plusieurs avec plusieurs » (many-to-many) entre les fichiers tar et les paquets.

On verra comment mettre en place ces relations dans la base de données.

3. Installation de tout le bazar

Sous Debian, faites :

sudo aptitude install mysql-server phpmyadmin

Notez qu'un serveur web va être installé par le jeu des dépendances.

aptitude va vous proposer d'installer une base de données dédiée à phpMyAdmin. Celle-ci servira à stocker des informations relatives aux structures de vos bases de données et aux fonctions avancées de phpMyAdmin. Accepter cette option est conseillé.

Vérifiez aussi que l'extension de sécurité suhosin (paquet php5-suhosin sous Debian) n'est pas installée. Celle-ci pose des problèmes au bon fonctionnement de phpMyAdmin.

Une fois qu'aptitude a fini son boulot, votre phpMyAdmin tout neuf est accessible avec votre butineur favori à l'adresse : http://locahost/phpmyadmin.

3.1 Création de la base de données et de ses utilisateurs

Une fois dans l'interface de phpMyAdmin, cliquez sur Databases pour créer la base de données « Integ ».

Ensuite, il nous faut deux utilisateurs :

- integ_user, qui pourra lire les données et se connecter à la DB sans utiliser de mot de passe ;

- integ_mgr, qui pourra mettre à jour les données et devra utiliser un mot de passe pour se connecter.

Les utilisateurs sont ajoutés en deux étapes :

- Création avec l'onglet Privileges et Add a new user. Si nécessaire, des privilèges globaux (c'est-à-dire pour toutes les bases du serveur) peuvent être attribués.

- Réglage fin des privilèges base par base. Ce réglage est accessible dans le tableau User overview dans l'onglet Privileges.

Vous pouvez vérifier le résultat de la configuration des privilèges :

- Soit dans l'onglet Databases et le lien Check Privileges de la ligne integ. Dans le tableau Users having access to "Integ", integ_user doit avoir juste un privilège « SELECT ».

- Soit avec la commande :

$ mysql -u integ_user Integ

[ ... ]

mysql>

La création de l'utilisateur integ_mgr se fera avec une procédure similaire, mais en mettant un mot de passe et en attribuant les privilèges : « SELECT », « INSERT », « UPDATE » et « DELETE » pour la base « Integ ».

4. Création des tables

4.1 La table « Products »

Une fois le lien « Integ » cliqué dans le menu de gauche, phpMyAdmin va vous montrer la structure (vide) de la base « Integ » et vous inviter à créer votre première table, « Products » avec 3 colonnes :

- La colonne « id », qui va être la clef primaire de cette table. « id » est de type entier (« INT »), avec un index « PRIMARY », avec « AUTO INCREMENT » sélectionné ;

- La colonne « name », pour le nom marketing du produit. « name » est de type « VARCHAR », de 32 caractères de longueur, index « UNIQUE ». Pourquoi cet index ? Le marketing ne sortira jamais simultanément deux produits différents ayant le même nom. Cet index « UNIQUE » permet de faire respecter cette règle par la DB. Ça vous permet aussi de ne pas vérifier cette contrainte dans votre code (ou dans toute autre application qui voudrait exploiter cette base) ;

- La colonne « home_page » pour les informations internes sur le produit. « home_page » est de type « VARCHAR », de 256 caractères de longueur, et potentiellement « NULL » (des fois que le produit soit créé dans la base avant que sa home page ne soit disponible).

Derniers points importants :

- Le module DBIx::Class utilisé dans la 2e partie de cet article ne fonctionne pas si le nom de la colonne contient des espaces. C'est pourquoi un souligné («_») est utilisé.

- Le « Storage engine » doit être « InnoDB ». (On verra dans cet article pourquoi).

Enfin, n'oubliez pas de cliquer sur Save en bas de page.

4.2 Mais pourquoi 2 colonnes ?

Vu que le nom du produit doit être unique, on pourrait être tenté de s'en servir comme clef primaire et de se débarrasser de la colonne id. C'est une solution, certes fonctionnelle, mais qui présente un inconvénient majeur : le nom du produit devra aussi être utilisé dans les tables qui le référencent. Pour cet article, il devrait ainsi être utilisé dans la table qui contiendra les versions de produit. Si jamais le nom du produit change, il faudra retrouver et modifier toutes ces utilisations du nom du produit.

4.3 La table « ProductVersions »

Cette table a besoin d'une clef primaire « id », d'un champ « version » et d'un champ « date ». La création de ces colonnes est similaire aux colonnes de la table « Products ».

4.4 Relier un produit avec ses versions

On a maintenant deux jolies tables, mais elles ne sont pas reliées. Il faut créer la relation entre le produit (singulier) et ses versions (pluriel). Il s'agit d'une relation « 1 vers n ». En termes de base de données, cette relation est établie en créant dans la table « ProductVersions » une colonne « product_id » qui contiendra l'« id » du produit correspondant (« product_id » doit être de type « INT » avec Index à « INDEX »). Dans cette table, plusieurs versions pourront référencer le même « id », donc le même produit. Mais une version ne peut référencer qu'un seul produit. On a bien établi une relation « 1 vers n ».

Mais, va-t-on devoir coder de quoi vérifier la cohérence entre « product_id » et les « id » disponibles dans la table « Products » ?

4.5 Mieux relier le produit et ses versions : les clefs étrangères

J'ai pratiqué dans une vie antérieure le codage de cette vérification. Eh bien, ce n'est guère passionnant. Heureusement, les bases de données modernes fournissent maintenant un mécanisme assurant cette cohérence : les clefs étrangères (foreign keys, dans la langue de Shakespeare).

On peut déclarer à la DB que la valeur de « product_id » doit être présente dans la colonne « id » de la table « Products ». Ceci fait, la cohérence est assurée. Mais il y a encore mieux pour la maintenance des données par la suite.

Qu'advient-il si un produit est supprimé du catalogue ? Devra-t-on supprimer une par une les versions de la DB avant de pouvoir supprimer le produit ? Eh bien, non. MySQL offre aussi la possibilité de paramétrer le comportement en cas de destruction d'une ligne produit : soit interdire, soit passer à « NULL » (mettre le « product_id » à 0, rendant la version orpheline), soit propager (toutes les versions du produit sont détruites).

C'est cette dernière option qui nous intéresse.

Notez que les foreign keys sont disponibles avec le « Storage engine » « InnoDB », mais pas avec « MyISAM », qui est proposé par défaut. Si vous avez oublié ce détail, ce n'est pas grave, vous pouvez le changer en allant modifier ce paramètre dans l'onglet Operations de la table restée coincée en « MyISAM » (cherchez « Storage Engine »).

Trêve de théorie, on peut ajouter cette relation dans la page « Structure » de la table « ProductVersions » avec le lien « Relation View » (si absent, voir le problème « InnoDB »). Si vous ne voyez pas de ligne « product_id », ajoutez un index sur cette colonne). Et là, mettez en place la « relation interne » (utilisé par phpMyAdmin) et la « Foreign key » (pour MySQL) avec l'option « ON DELETE: CASCADE ».

On peut aussi ajouter cette relation avec l'interface graphique « designer ». Cette interface est disponible en retournant dans la page de la base « Integ », onglet More, bouton designer.

Vous devriez voir les deux tables non reliées. Cliquez sur le bouton Create relation et suivez les instructions :

- Sélectionnez la clef référencée : « id » dans la table « Products »,

- Sélectionnez la clef étrangère : « product_id » de la table « ProductVersions »,

- Choisissez « cascade » pour l'option « on delete ».

Et devant vos yeux émerveillés, voyez ceci apparaître :

 

products-productversions

 

(L'auteur admet ne pas aimer PHP, adorer phpMyAdmin et assumer ses contradictions...).

4.6 Blinder un peu plus

MySQL peut aussi assurer l'unicité de chaque couple produit-version. Il suffit de déclarer un index de type unique pour les deux colonnes « product_id » et « version ». Ça vous évitera de créer des lignes inutiles si votre code utilise au mauvais endroit une instruction de type « créer » au lieu du type « chercher ou créer ». (L'utilisation de ces fonctions sera expliquée plus en détails dans un article ultérieur).

4.7 La table « TarBalls »

Elle est créée de la même façon que la table « ProductVersions » avec une clef primaire « id », une « url » de type « varchar/128 », index « UNIQUE » et enfin, une clef étrangère « product_version_id » pointant sur l'id de la table « ProductVersions ».

4.8 La table « Packages » et la relation m-vers-n

Elle contient la colonne « id » et le nom du paquet (triplet nom-version.arch.rpm).

Mais là, ça se complique : un fichier tar peut contenir plusieurs paquets et chaque paquet peut faire partie de plusieurs fichiers tar. C'est une relation m-vers-n. Une seule colonne tarball_id dans la table « Packages » ne suffit pas.

La technique traditionnelle est d'utiliser une table intermédiaire pour relier tarball et paquet avec deux colonnes : une pour stocker l'id du tarball et une pour stocker l'id du paquet. Par exemple, si on crée un tarball (avec un id 42) contenant deux paquets (un déjà connu avec un id à 99 et un nouveau avec un id à 1024), on ajoutera dans la base :

- une ligne avec un id 42 dans la table « TarBalls »,

- une ligne avec un id 1024 pour le nouveau paquet dans la table « Packages »,

- deux lignes (42-99 et 42-1024) pour matérialiser les deux relations paquets-tarballs dans la table intermédiaire (nommée « TarballPackages »)

Cette table intermédiaire a :

- une colonne « tarball_id » de type entier, clef étrangère sur la colonne « id » de la table « TarBalls »,

- une colonne « package_id » de type entier, clef étrangère sur la colonne « id » de la table « Packages »,

- une clef primaire constituée des deux colonnes « tarball_id » et « package_id ».

Ce dernier point est important pour la suite avec le module Perl DBIx::Class::Schema::Loader. Ce module utilise des heuristiques assez contraignantes pour essayer d'interpréter correctement les relations entre les tables. Pour générer une relation « many-to-many » entre 2 classes DBIx::Class, la table de relation doit respecter ces règles.

Voici le schéma complet présenté par le « designer » de phpMyAdmin (les tables sont un peu maigres, mais c'est pour le bien de cet article) :

 

complete-schema

 

5. Suite au prochain épisode

Maintenant que la persistance des données est assurée par la base de donnée « Integ », il reste à voir dans un prochain article :

- Comment utiliser dbcidump et DBIx::Class::Schema::Loader pour mettre en place une interface entre un programme Perl et la base de données en écrivant un minimum de code ;

- Le module DBIx::Class pour effectuer des requêtes sur la base de données et exploiter les relations mises en place dans cet article.

 



Article rédigé par

Par le(s) même(s) auteur(s)

Créer une application Perl autour de MySQL : DBIx::Class (2/3)

Magazine
Marque
GNU/Linux Magazine
Numéro
168
Mois de parution
février 2014
Spécialité(s)
Résumé

Reprenons l'histoire du hacker à qui on a demandé de créer des pages web pour le suivi de la production logicielle de la société. Comme tout hacker qui se respecte, il préfère que la machine fasse son boulot à sa place. Pour ce faire, il a mis en place une base de données MySQL. Reste maintenant à utiliser Perl et DBIx::Class pour accéder aux données de cette base.

P... de proxy, le retour

Magazine
Marque
GNU/Linux Magazine
Numéro
152
Mois de parution
septembre 2012
Spécialité(s)
Résumé
L'article « P... de proxy» a expliqué comment utiliser tinyproxy pour se simplifier la vie sur un ordinateur nomade. Cette suite (c'est la mode au cinéma) va expliquer comment étendre la solution proposée pour gérer d'autres proxys (genre proxy-cache pour serveur de paquets) et surtout faire une commutation automatique de proxy pour atteindre le Saint-Graal des hackers : la machine s'occupe de tout et moi de rien :-)

Config::Model - Créer un éditeur graphique de configuration avec Perl (2e partie)

Magazine
Marque
GNU/Linux Magazine
Numéro
120
Mois de parution
octobre 2009
Résumé
Dans un article précédant [GLMF], nous avons vu comment créer la partie graphique d'un éditeur de configuration en précisant la structure et les contraintes des données du fichier /etc/ssh/sshd_config. Config::Model va utiliser cette structure (le modèle de la configuration de sshd_config) pour générer l'interface graphique. Mais il reste à pouvoir charger les données du fichier et les ré-écrire. Nous allons voir dans cette deuxième partie comment utiliser l'API de Config::Model pour lire et écrire les données de sshd_config.

Les derniers articles Premiums

Les derniers articles Premium

De la scytale au bit quantique : l’avenir de la cryptographie

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Imaginez un monde où nos données seraient aussi insaisissables que le célèbre chat de Schrödinger : à la fois sécurisées et non sécurisées jusqu'à ce qu'un cryptographe quantique décide d’y jeter un œil. Cet article nous emmène dans les méandres de la cryptographie quantique, où la physique quantique n'est pas seulement une affaire de laboratoires, mais la clé d'un futur numérique très sécurisé. Entre principes quantiques mystérieux, défis techniques, et applications pratiques, nous allons découvrir comment cette technologie s'apprête à encoder nos données dans une dimension où même les meilleurs cryptographes n’y pourraient rien faire.

Les nouvelles menaces liées à l’intelligence artificielle

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Sommes-nous proches de la singularité technologique ? Peu probable. Même si l’intelligence artificielle a fait un bond ces dernières années (elle est étudiée depuis des dizaines d’années), nous sommes loin d’en perdre le contrôle. Et pourtant, une partie de l’utilisation de l’intelligence artificielle échappe aux analystes. Eh oui ! Comme tout système, elle est utilisée par des acteurs malveillants essayant d’en tirer profit pécuniairement. Cet article met en exergue quelques-unes des applications de l’intelligence artificielle par des acteurs malveillants et décrit succinctement comment parer à leurs attaques.

Migration d’une collection Ansible à l’aide de fqcn_migration

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Distribuer du contenu Ansible réutilisable (rôle, playbooks) par l’intermédiaire d’une collection est devenu le standard dans l’écosystème de l’outil d’automatisation. Pour éviter tout conflit de noms, ces collections sont caractérisées par un nom unique, formé d’une espace de nom, qui peut-être employé par plusieurs collections (tel qu'ansible ou community) et d’un nom plus spécifique à la fonction de la collection en elle-même. Cependant, il arrive parfois qu’il faille migrer une collection d’un espace de noms à un autre, par exemple une collection personnelle ou communautaire qui passe à un espace de noms plus connus ou certifiés. De même, le nom même de la collection peut être amené à changer, si elle dépasse son périmètre d’origine ou que le produit qu’elle concerne est lui-même renommé.

Les listes de lecture

9 article(s) - ajoutée le 01/07/2020
Vous désirez apprendre le langage Python, mais ne savez pas trop par où commencer ? Cette liste de lecture vous permettra de faire vos premiers pas en découvrant l'écosystème de Python et en écrivant de petits scripts.
11 article(s) - ajoutée le 01/07/2020
La base de tout programme effectuant une tâche un tant soit peu complexe est un algorithme, une méthode permettant de manipuler des données pour obtenir un résultat attendu. Dans cette liste, vous pourrez découvrir quelques spécimens d'algorithmes.
10 article(s) - ajoutée le 01/07/2020
À quoi bon se targuer de posséder des pétaoctets de données si l'on est incapable d'analyser ces dernières ? Cette liste vous aidera à "faire parler" vos données.
Voir les 64 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous