Desarrollo de módulos para títeres con kit de desarrollo de títeres

Hace aproximadamente un mes, tuve una opción: si escribir el módulo para títeres "a la mesa" (es decir, para la infraestructura interna) o hacerlo universal, abrir la fuente y publicarlo en la falsificación de títeres . Por supuesto, sería más rápido y más fácil esbozar rápidamente 2-3 clases para usted y calmarse, pero la experiencia adquirida en el proceso de publicación del módulo es valiosa y quiero compartirla. En RuNet, no hay información sobre el uso del kit de desarrollo de títeres (en adelante PDK ), por lo que puede considerar esto como una especie de tutorial.


¿De qué trata el artículo?


En el proceso de desarrollo de un módulo (o más bien, dos), descubrí PDK, que facilita enormemente tanto el desarrollo como el mantenimiento de los módulos. A saber:


  • Formatee metadata.json automáticamente cuando actualice por última vez
  • Generación de configuración para varios sistemas de CI que pueden hacer lo siguiente:
    • Comprobación del código ruby ​​con rubocop linter
    • Ejecución de pruebas unitarias
    • Bajo ciertas condiciones: llenado automático del código de trabajo de falsificación de marionetas
  • Generando documentación basada en etiquetas en comentarios usando yard
  • Placa [PDK] para el módulo en forja de marionetas. Un poco, pero agradable!

Todos interesados ¡Pido un gato!


Como ejemplos


Si desea ver y sentir lo que se entiende durante el proceso de lectura, puede abrir uno de los dos (o ambos) módulos mencionados: clickhouse y xmlsimple . Ambos fueron desarrollados utilizando el PDK y otras herramientas descritas en el artículo.


Contenido



¿Qué es PDK?


De la documentación oficial:


Cree un módulo completo con clases, tipos definidos y tareas, y pruebe y valide su trabajo a medida que avanza. PDK proporciona una estructura de módulo completa, plantillas para clases, tipos definidos y tareas, y una infraestructura de prueba. Puede validar y probar su módulo contra varios sistemas operativos y múltiples versiones de Puppet.

En mi traducción libre:


Le permite crear un módulo completo con clases, tipos, tareas y pruebas para verificar el funcionamiento del módulo. PDK proporciona una estructura completa y plantillas para todo lo anterior. Con esta herramienta, puede verificar el funcionamiento del módulo con varias versiones de Puppet, así como en varios sistemas operativos.

Suena bien? Bueno, así es realmente. Hasta el momento en que comencé a trabajar en el módulo, que se decidió escribir inmediatamente para código abierto, no sospeché de esta herramienta, y ahora tengo la intención de transferir toda la infraestructura interna para usar el PDK.


Describiré cómo ponerlo, y qué herramientas y comandos contiene.


Instalación


La página oficial de instalación . Al usar este enlace, es casi seguro que encontrará la manera correcta de instalar PDK en su host. Si por alguna razón no tiene suerte y su sistema operativo no está allí, siempre hay una rotonda en el formulario:


 gem install pdk 

De hecho, PDK es solo una joya, y está configurado de esa manera.


Contenido PDK


En general, PDK no es más que un conjunto de gemas para facilitar el desarrollo del módulo. Contiene las siguientes herramientas:


UtilidadDescripción
metadata-json-lintComprueba metadata.json para buscar guías de estilo de marionetas
pdkUna herramienta para generar y probar módulos y sus contenidos (clases, tipos, etc.) desde la línea de comandos
pelusa títereComprueba el código de títeres para las guías de estilo de Puppet Language
sintaxis de marionetasVerificar la sintaxis del manifiesto
puppetlabs_spec_helperProporciona clases, métodos y tareas de Rake para pruebas específicas de código de títeres.
rspec-puppetPrueba el comportamiento de la marioneta mientras compila manifiestos en el directorio de recursos (?)
rspec-puppet-factsLe permite ejecutar rspec-puppet con hechos especificados por el usuario puppet

Crear un módulo


PDK instalado, ahora puedes jugar. El comando de pdk help más simple mostrará los comandos disponibles. Supongamos que estamos en la carpeta donde tiene todos los demás módulos. Entonces creemos uno nuevo:


 $ 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'. 

La utilidad hace preguntas para completar el archivo metadata.json, y la salida tiene exactamente lo que se indica: el módulo y los archivos auxiliares compilados a partir de plantillas del git.


Una pequeña observación: los temlites cambian con bastante frecuencia, incluidos algunos errores críticos que se han solucionado recientemente. Por lo tanto, es mejor usar no los valores predeterminados del PDK instalado, sino la última versión. Es cierto, hay un lado --template-url : cuando se usa el argumento --template-url , PDK agrega este parámetro al ~.pdk/cache/answers.json y, a juzgar por los retrasos en la ejecución posterior de cualquiera de los comandos pdk , intenta descargarlos. Por lo tanto, elimine este parámetro de answers.json o no lo use al crear un módulo y cámbielo en metadata.json .


Veamos los pasos adicionales que se pueden realizar con el PDK.


nueva clase


 $ 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 

Este comando crea 2 archivos: el manifiesto en sí para la clase y el archivo de especificaciones para probarlo. Me detendré en las etiquetas para la documentación más adelante con más detalle.


nuevo tipo_definido


 $ 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. 

De todos modos: manifiesto para el tipo de recurso y el archivo de especificaciones.


nuevo proveedor y tarea


PDK también puede crear un nuevo proveedor o tarea, pero no trabajé estrechamente con ellos, por lo que honestamente diré que es mejor estudiar este tema más profundamente si es necesario.


Generando documentación con títeres


Realmente no entiendo por qué las puppet strings no puppet strings parte del kit de herramientas PDK, pero esto es a la vie. Si durante el desarrollo colocó correctamente las etiquetas para el patio, entonces hay 2 formas principales de proporcionar documentación al usuario:


  • Genere como HTML / Markdown / JSON y colóquelo junto al código. Esto se hace con el comando puppet string generate [--format FORMAT] , donde el formato puede omitirse o establecerse en json / markdown .
    • Es habitual tener el archivo REFERENCE.md en la raíz del repositorio como el estándar de documentación, que es generado por las puppet strings generate --format markdown .
  • Publicar en el repositorio con código (siempre que esté en github) github-pages. Esto es bastante simple, necesita 3 comandos:
     #  Gemfile.lock,    PDK rm -f Gemfile.lock #     Gemfile   bundle bundle install --path vendor/bundle #   gh-pages   rake-task bundle exec rake strings:gh_pages:update 

Parece que no es magia, pero en la salida tenemos un módulo con instrucciones. La ventaja es que, incluso si no describe, por ejemplo, cada uno de los parámetros que utilizan la etiqueta @param , la salida seguirá siendo una clase / tipo / función con una descripción mínima de los parámetros con el tipo y el valor predeterminado. En mi humilde opinión, incluso esto es mejor que nada, y hará que el módulo sea más atractivo para su uso.


Por supuesto, todo esto puede automatizarse y agregarse como una etapa de CI. Eso sería perfecto Mis manos aún no han llegado, pero está acumulando polvo en el trabajo atrasado. Si de repente alguien tiene algo que decir sobre este tema, se lo agradeceré. Como pensamientos: al menos agregue una marca para ver si REFERENCE.md cambia después de ejecutar las cadenas de marionetas. Y si es así, considere que las pruebas fallaron.


Personalización de plantillas


La documentación de las plantillas se encuentra en el repositorio de pdk-templates . En resumen, todo se configura usando el archivo .sync.yml en el directorio raíz del módulo, y los cambios se aplican usando el comando pdk update . Cada uno de los parámetros de este archivo es el nombre de otro archivo en el directorio del módulo, que debe cambiarse de una forma u otra. La mayoría de los parámetros para cada una de las plantillas que tuve que seleccionar "al tacto", mirando el código fuente, a menudo, por prueba y error. La documentación aquí a veces va muy por detrás. Desafortunadamente, no hay casi nada más que decir, excepto dar un enlace a un ejemplo desde su propio repositorio.


Describiré muy rápidamente algunos parámetros que cambié usando .sync.yml del ejemplo anterior:


  • Gemfile : se agregaron dos Gemfile como dependencias en diferentes grupos: pdk en el grupo de desarrollo; xml-simple en el grupo de dependencias. Al iniciar las pruebas, el grupo system_tests no está instalado, por lo que agrego la dependencia a otro grupo.
  • spec/spec_helper.rb : se ha cambiado el método de simulación, se ha agregado el umbral mínimo de cobertura de prueba, por debajo del cual las pruebas se consideran fallidas.
  • .travis.yml : este archivo ha sido pulido durante mucho tiempo, ya que se usa para verificar la base del código y cargar el módulo terminado en Puppet-Forge. Cambios:
    • Usuario y contraseña encriptada para llenar el módulo en Puppet-Forge. Puede leer más sobre la implementación de la forja de marionetas con Travis aquí .
    • Se creó una secuencia de pruebas → implementación con el lanzamiento de este último solo con pruebas exitosas.
    • Se agregó la etapa de implementación del módulo a Puppet-forge, siempre que el CI se inicie desde la etiqueta que comienza con el carácter "v".
  • Rakefile : se agregaron algunas excepciones para el linter.

Ejecutando varios CI


Aquí todo es bastante simple. Inmediatamente después de generar el módulo utilizando el PDK, la validación comienza en appveyor, travis y gitlab-ci. Para ejecutar las pruebas, todo está listo de inmediato, para el ajuste, .sync.yml el mismo .sync.yml . No tengo preferencias particulares, por lo que no recomendaré nada. Solo usa lo que sea más conveniente.


Bonificación: escribimos pruebas unitarias para clases, tipos y funciones


Este punto va un poco más allá del material básico que planeé describir, pero me parece muy útil.


Entonces, tenemos un módulo con manifiestos y una biblioteca, que, a su vez, contiene clases, tipos y funciones (tampoco nos olvidamos de las tareas y los proveedores, pero no tengo ninguna experiencia en esta parte). Dado que cualquier código existe con el propósito de cambiar, sería bueno, obviamente, superponerlo con pruebas para asegurarse de 2 cosas:


  • Los cambios no rompen el comportamiento actual (o los cambios de comportamiento con las pruebas)
  • Sus manifiestos hacen exactamente lo que espera y utilizan todos los recursos que espera.

Puppetlabs proporciona una extensión para el marco rspec llamada puppet-rspec . Enlaces a documentación para probar clases , tipos y funciones . No seas demasiado vago para mirar de cerca, hay otras secciones.


Comenzar a usarlo es bastante simple, sin siquiera saber rubí. Si se crearon clases o tipos, como se muestra arriba, usando pdk new <thing> , entonces el archivo *_spec.rb también ya existe. Entonces, supongamos que tenemos una dummy::class . Para probarlo, se debe spec/classes/class_spec.rb archivo spec/classes/class_spec.rb con el siguiente contenido:


 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 

Puede verificar ejecutando pdk test unit desde el directorio raíz del módulo.


Eso es casi todo lo que necesitamos. Ahora queda por completar class_spec.rb necesario is_expected con las condiciones apropiadas. Por ejemplo, para verificar que la clase contiene el file {'/file/path': } con ciertos parámetros, puede hacer esto:


 it do is_expected.to contain_file('/file/path').with( 'ensure' => 'file', 'mode' => '0644' ) end 

Puede establecer los parámetros de clase usando let(:params) { {'param1' => 'value'} } , es posible realizar pruebas bajo varias condiciones de entrada al colocar cada it dentro de las secciones seleccionadas del context 'some description' {} . Es posible verificar ambas dependencias entre recursos y entre clases: si se supone, por ejemplo, que la declaración de clase contiene inherits , entonces puede agregar la is_expected.to contain_class('parent_class_name') . ¿Necesita verificar el comportamiento en diferentes sistemas operativos? También es posible: simplemente indicamos en un contexto separado los hechos necesarios:


 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 general, por lo que pude notar en el proceso de redacción de pruebas, el marco le permite verificar casi todo lo que pueda necesitar. Y la presencia de pruebas una vez me ayudó cuando algunos parámetros se movieron de las clases secundarias a la clase superior del módulo: mostraron que la refactorización no rompió nada, y el comportamiento de todo el módulo no cambió.


En lugar de salida


Como ya podría entenderse por la entonación general del artículo, estoy muy animado por lo mucho que Puppet hizo que trabajar con módulos y manifiestos sea más fácil gracias a PDK. Las acciones de rutina son automáticas, las plantillas se usan siempre que sea posible, las configuraciones para CI populares están disponibles de fábrica. Puede parecer una especie de sobrecarga, y el uso puede no traer la fruta esperada, pero definitivamente vale la pena. Si compara cómo desarrollar módulos sin y con PDK, entonces para mí se ve así:


Desarrollo sin barba PDKDesarrollo PDK

Intente, ponga, haga la vida más fácil para usted y sus colegas. Estaré encantado de responder posibles preguntas.


¡Que la atomización nos acompañe!

Source: https://habr.com/ru/post/es435954/


All Articles