Il y a environ un mois, j'avais le choix: écrire le module de marionnette "sur la table" (c'est-à-dire pour l'infrastructure interne) ou le rendre universel, ouvrir la source et le publier sur forge de marionnettes . Bien sûr, il serait plus rapide et plus facile de dessiner rapidement 2 à 3 notes pour vous-même et de vous calmer, mais l'expérience acquise lors de la publication du module est précieuse et je veux la partager. Dans RuNet, il n'y a aucune information sur l'utilisation du kit de développement de marionnettes (ci-après PDK ), vous pouvez donc considérer cela comme une sorte de tutoriel.
Quel est l'article sur
En train de développer un module (ou plutôt deux), j'ai découvert PDK, qui facilite grandement le développement et la maintenance des modules. À savoir:
- Formater automatiquement
metadata.json
lors de la dernière mise à jour - Génération de configuration pour divers systèmes CI pouvant effectuer les opérations suivantes:
- Vérification du code Ruby avec Rubocop Linter
- Exécution de tests unitaires
- Sous certaines conditions - remplissage automatique du code de travail de la forge de marionnettes
- Génération de documentation basée sur des balises dans les commentaires à l'aide de yard
- Plaque
[PDK]
pour le module sur forge de marionnettes. Une bagatelle, mais sympa!
Tous intéressés Je demande un chat!
Comme exemples
Si vous voulez regarder et ressentir ce que l'on veut dire pendant le processus de lecture, vous pouvez ouvrir l'un des deux (ou les deux) modules mentionnés: clickhouse et xmlsimple . Les deux ont été développés à l'aide du PDK et d'autres outils décrits dans l'article.
Table des matières
Qu'est-ce que PDK
De la documentation officielle:
Créez un module complet avec des classes, des types définis et des tâches, puis testez et validez votre travail au fur et à mesure. PDK fournit une structure de module complète, des modèles de classes, des types définis et des tâches, ainsi qu'une infrastructure de test. Vous pouvez valider et tester votre module sur différents systèmes d'exploitation et plusieurs versions de Puppet.
Dans ma traduction gratuite:
Vous permet de créer un module complet avec des classes, des types, des tâches et des tests pour vérifier le fonctionnement du module. PDK fournit une structure et des modèles complets pour tout ce qui précède. À l'aide de cet outil, vous pouvez vérifier le fonctionnement du module avec différentes versions de marionnettes, ainsi que dans différents systèmes d'exploitation.
Sonne bien? Eh bien, c'est vraiment comme ça. Jusqu'au moment où j'ai commencé à travailler sur le module, qu'il a été décidé d'écrire immédiatement pour l'open source, je ne soupçonnais pas cet outil, et maintenant j'ai l'intention de transférer toute l'infrastructure interne pour utiliser le PDK.
Je vais décrire comment le mettre, et quels outils et commandes il contient.
L'installation
La page d'installation officielle . En utilisant ce lien, vous êtes presque assuré de trouver la bonne façon d'installer PDK sur votre hôte. Si pour une raison quelconque, vous n'êtes pas chanceux et que votre système d'exploitation n'est pas là, il y a toujours un rond-point sous la forme:
gem install pdk
En fait, PDK n'est qu'un joyau, et il est défini de cette façon.
Contenu PDK
En général, PDK n'est rien de plus qu'un ensemble de gemmes pour faciliter le développement de modules. Il contient les outils suivants:
Utilitaire | La description |
---|
metadata-json-lint | Vérifie metadata.json pour les guides de style de marionnettes correspondants |
pdk | Un outil pour générer et tester des modules et leur contenu (classes, types, etc.) à partir de la ligne de commande |
marionnettes | Vérifie le code de marionnette pour les guides de style de langue de marionnette |
syntaxe de marionnette | Vérifiez la syntaxe du manifeste |
puppetlabs_spec_helper | Fournit des classes, des méthodes et des tâches Rake pour les tests de spécification du code de marionnettes |
rspec-puppet | Teste le comportement des marionnettes lors de la compilation des manifestes dans le répertoire des ressources (?) |
rspec-puppet-facts | Vous permet d'exécuter rspec-puppet avec des informations sur les marionnettes spécifiées par l'utilisateur |
Créer un module
PDK installé, vous pouvez maintenant jouer. La commande d' pdk help
plus simple affichera les commandes disponibles. Supposons que nous soyons dans le dossier où vous avez tous les autres modules. Créons-en un nouveau:
$ pdk new module --template-url=https://github.com/puppetlabs/pdk-templates.git *** We need to create the metadata.json file for this module, so we're going to ask you 5 questions. *** [Q 1/5] If you have a name for your module, add it here. --> dummy [Q 2/5] If you have a Puppet Forge username, add it here. --> felixoid [Q 3/5] Who wrote this module? --> Mikhail f. Shiryaev [Q 4/5] What license does this module code fall under? --> MIT [Q 5/5] What operating systems does this module support? --> RedHat based Linux, Debian based Linux, Windows Metadata will be generated based on this information, continue? Yes pdk (INFO): Module 'dummy' generated at path '/tmp/dummy', from template 'https://github.com/puppetlabs/pdk-templates.git'.
L'utilitaire pose des questions pour remplir le fichier metadata.json, et la sortie a exactement ce qui est indiqué: le module et les fichiers auxiliaires compilés à partir des modèles de git.
Une petite remarque - les temlites changent assez souvent, y compris certains bogues critiques qui ont été corrigés récemment. Par conséquent, il est préférable d'utiliser non pas les valeurs par défaut du PDK installé, mais la dernière version. Certes, il y a un revers: lors de l'utilisation de l'argument --template-url
, PDK ajoute ce paramètre au ~.pdk/cache/answers.json
et, à en juger par les retards dans l'exécution ultérieure de l'une des commandes pdk
, il essaie de les télécharger. Supprimez donc ce paramètre de answers.json
ou ne l'utilisez pas lors de la création d'un module et modifiez-le dans metadata.json
.
Passons en revue les étapes supplémentaires qui peuvent être effectuées à l'aide du PDK.
nouvelle classe
$ pdk new class dummy::class pdk (INFO): Creating '/tmp/dummy/manifests/class.pp' from template. pdk (INFO): Creating '/tmp/dummy/spec/classes/class_spec.rb' from template. $ cat manifests/class.pp # A description of what this class does # # @summary A short summary of the purpose of this class # # @example # include dummy::class class dummy::class { } $ cat spec/classes/class_spec.rb require 'spec_helper' describe 'dummy::class' do on_supported_os.each do |os, os_facts| context "on #{os}" do let(:facts) { os_facts } it { is_expected.to compile } end end end
Cette commande crée 2 fichiers: le manifeste lui-même pour la classe et le fichier spec pour le tester. Je m'attarderai plus tard sur les balises pour la documentation.
nouveau type_défini
$ pdk new defined_type type pdk (INFO): Creating '/tmp/dummy/manifests/type.pp' from template. pdk (INFO): Creating '/tmp/dummy/spec/defines/type_spec.rb' from template.
Tout de même: manifeste pour le type de ressource et le fichier de spécifications.
nouveau fournisseur et tâche
PDK peut également créer un nouveau fournisseur ou une nouvelle tâche, mais je n'ai pas travaillé en étroite collaboration avec eux, donc je dirai honnêtement qu'il est préférable d'étudier ce sujet plus en profondeur si nécessaire.
Génération de documentation avec des chaînes de marionnettes
Je ne comprends pas vraiment pourquoi les puppet strings
ne puppet strings
pas partie de la boîte à outils PDK, mais c'est à la vie. Si au cours du développement, vous avez correctement placé des balises pour la cour, il existe deux façons principales de fournir de la documentation à l'utilisateur:
- Générez-le en HTML / Markdown / JSON et placez-le à côté du code. Cela se fait avec la commande
puppet string generate [--format FORMAT]
, où le format peut être omis ou défini sur json
/ markdown
.
- Il est habituel d'avoir le fichier
REFERENCE.md
à la racine du référentiel comme standard de documentation, qui est généré par la puppet strings generate --format markdown
.
- Publiez dans le référentiel avec du code (à condition qu'il soit sur github) github-pages. C'est assez simple, vous avez besoin de 3 commandes:
Cela ne semble pas être magique, mais à la sortie, nous avons un module avec des instructions. L'avantage est que même si vous ne décrivez pas, par exemple, chacun des paramètres à l'aide de la balise @param
, la sortie sera toujours une classe / type / fonction avec une description minimale des paramètres avec le type et la valeur par défaut. À mon humble avis, même cela vaut mieux que rien et rendra le module plus attrayant à utiliser.
Bien sûr, tout cela peut être automatisé et ajouté en tant qu'étape CI. Ce serait parfait. Mes mains ne sont pas encore parvenues, mais dans l'arriéré, la poussière s'accumule. Si tout à coup quelqu'un a quelque chose à dire à ce sujet - je vous en serai reconnaissant. Comme réflexions: ajoutez au moins une vérification pour voir si REFERENCE.md change après avoir exécuté des chaînes de marionnettes. Et si oui, considérez que les tests ont échoué.
Personnalisation du modèle
La documentation des modèles se trouve dans le référentiel pdk-templates . En bref, tout est configuré à l'aide du fichier .sync.yml
dans le répertoire racine du module, et les modifications sont appliquées à l'aide de la commande pdk update
. Chacun des paramètres de ce fichier est le nom d'un autre fichier du répertoire du module, qui doit être modifié d'une manière ou d'une autre. La plupart des paramètres pour chacun des modèles que j'ai dû sélectionner "au toucher", en regardant le code source, souvent - par essais et erreurs. La documentation ici est parfois loin derrière. Malheureusement, il n'y a presque plus rien à dire, sauf pour donner un lien vers un exemple de votre propre référentiel.
Je vais décrire très rapidement quelques paramètres que j'ai modifiés en utilisant le .sync.yml
de l'exemple ci-dessus:
Gemfile
: deux Gemfile
ont été ajoutées comme dépendances dans différents groupes: pdk dans le groupe de développement; xml-simple dans le groupe de dépendances. Lors du démarrage des tests, le groupe system_tests n'est pas installé, j'ajoute donc la dépendance à un autre groupe.spec/spec_helper.rb
: la méthode de moking a été modifiée, le seuil de couverture de test minimum a été ajouté, en dessous duquel les tests sont considérés comme ayant échoué..travis.yml
: ce fichier est poli depuis longtemps, car il est utilisé pour vérifier la base de code et charger le module fini sur puppet-forge. Changements:
- Utilisateur et mot de passe crypté pour remplir le module sur marionnette-forge. Vous pouvez en savoir plus sur le déploiement de Puppet-Forge avec Travis ici .
- Une séquence de tests a été créée → déploiement avec le lancement de ce dernier uniquement avec des tests réussis.
- Ajout de l'étape de déploiement du module sur puppet-forge, à condition que le CI soit lancé à partir de la balise commençant par le caractère "v".
Rakefile
: ajout de quelques exceptions pour le linter.
Exécution de divers CI
Ici, tout est assez simple. Immédiatement après la génération du module à l'aide du PDK, la validation commence dans appveyor, travis et gitlab-ci. Pour exécuter les tests, tout est prêt dès la sortie de la boîte, pour le réglage, le même .sync.yml
. Je n'ai pas de préférences particulières, je ne recommanderai donc rien. Utilisez simplement ce qui est plus pratique.
Bonus: nous écrivons des tests unitaires pour les classes, les types et les fonctions
Ce point va bien au-delà du matériel de base que je comptais décrire, mais il me semble très utile.
Nous avons donc un module avec des manifestes et une bibliothèque, qui, à leur tour, contient des classes, des types et des fonctions (nous n'oublions pas non plus les tâches et les fournisseurs, mais je n'ai aucune expertise dans cette partie). Étant donné que tout code existe dans le but de le changer, il serait bien sûr, de le superposer avec des tests pour vous assurer de 2 choses:
- Les changements ne cassent pas le comportement actuel (ou les changements de comportement avec les tests)
- Vos manifestes font exactement ce que vous attendez et utilisent toutes les ressources que vous attendez.
Puppetlabs fournit une extension du framework rspec appelée puppet-rspec . Liens vers la documentation pour tester les classes , les types et les fonctions . Ne soyez pas trop paresseux pour regarder de près, il existe d'autres sections.
Pour commencer à l'utiliser, c'est assez simple, sans même connaître le rubis. Si des classes ou des types ont été créés, comme indiqué ci-dessus, à l'aide de pdk new <thing>
, le fichier *_spec.rb
existe également déjà. Supposons donc que nous ayons une dummy::class
. Pour le tester, un fichier spec/classes/class_spec.rb
doit être créé avec le contenu suivant:
require 'spec_helper' describe 'dummy::class' do on_supported_os.each do |os, os_facts| context "on #{os}" do let(:facts) { os_facts } it { is_expected.to compile } end end end
Vous pouvez le vérifier en exécutant pdk test unit
partir du répertoire racine du module.
C’est presque tout ce dont nous avons besoin. Il reste maintenant à compléter class_spec.rb
is_expected
nécessaire avec les conditions appropriées. Par exemple, pour vérifier que la classe contient la ressource file {'/file/path': }
avec certains paramètres, vous pouvez faire ceci:
it do is_expected.to contain_file('/file/path').with( 'ensure' => 'file', 'mode' => '0644' ) end
Vous pouvez définir des paramètres de classe à l'aide de let(:params) { {'param1' => 'value'} }
, il est possible d'effectuer des tests dans diverses conditions d'entrée en les plaçant chacun à l'intérieur des sections sélectionnées du context 'some description' {}
. Il est possible de vérifier les deux dépendances entre les ressources et entre les classes: s'il est supposé, par exemple, que la déclaration de classe contient des inherits
, vous pouvez ajouter la is_expected.to contain_class('parent_class_name')
. Besoin de vérifier le comportement dans différents OS? C'est également possible: nous indiquons simplement dans un contexte séparé les faits nécessaires:
context 'with Debian' do let(:facts) do { os: { architecture: 'amd64', distro: { codename: 'stretch', id: 'Debian', release: { full: '9.6', major: '9', minor: '6', }, }, family: 'Debian', name: 'Debian', release: { full: '9.6', major: '9', minor: '6', }, selinux: { enabled: false, }, }, osfamily: 'Debian', } end it { is_expected.to something } end
En général, pour autant que j'ai réussi à le remarquer lors de l'écriture des tests, le framework vous permet de vérifier presque tout ce qui peut être nécessaire. Et la présence de tests m'a aidé une fois lorsque certains paramètres ont été déplacés des classes enfants vers la classe supérieure du module: ils ont montré que le refactoring ne cassait rien et que le comportement de l'ensemble du module ne changeait pas.
Au lieu de la sortie
Comme cela peut déjà être compris à partir de l'intonation générale de l'article, je suis très encouragé par la façon dont Puppet a facilité le travail avec les modules et les manifestes grâce au PDK. Les actions de routine sont automatisées, des modèles sont utilisés dans la mesure du possible, des configurations pour les CI populaires sont disponibles dès la sortie de la boîte. Cela peut sembler une sorte de frais généraux, et l'utilisation peut ne pas apporter les fruits attendus, mais cela en vaut vraiment la peine. Si vous comparez comment développer des modules sans et avec PDK, cela ressemble à ceci:
Développement sans barbes PDK | Développement PDK |
---|
 |  |
Essayez, mettez, rendez la vie plus facile pour vous et vos collègues. Je me ferai un plaisir de répondre à d'éventuelles questions.
Que l'atomatisation soit avec nous!