Marioneta - Estilo de codificación

En Puppet, el estilo de codificación define todos los estándares que se deben seguir al intentar convertir la infraestructura en la configuración de la máquina en un código. Puppet trabaja y realiza todas sus tareas definidas utilizando recursos.

La definición del lenguaje de Puppet ayuda a especificar todos los recursos de una manera estructurada, que es necesaria para administrar cualquier máquina de destino que deba administrarse. Puppet usa Ruby como su lenguaje de codificación, que tiene múltiples características incorporadas que hacen que sea muy fácil hacer las cosas con una configuración simple en el lado del código.

Unidades fundamentales

Puppet utiliza múltiples estilos de codificación fundamentales que son fáciles de entender y administrar. A continuación se muestra una lista de algunos.

Recursos

En Puppet, los recursos se conocen como unidad de modelado fundamental que se utilizan para administrar o modificar cualquier sistema de destino. Los recursos cubren todos los aspectos de un sistema, como archivo, servicio y paquete. Puppet viene con una capacidad incorporada en la que permite a los usuarios o desarrolladores desarrollar recursos personalizados, que ayudan a administrar cualquier unidad particular de una máquina.

En Puppet, todos los recursos se agregan mediante el uso de “define” o “classes”. Estas funciones de agregación ayudan a organizar un módulo. A continuación se muestra un recurso de muestra que consta de varios tipos, un título y una lista de atributos con los que Puppet puede admitir varios atributos. Cada recurso de Puppet tiene su propio valor predeterminado, que podría anularse cuando sea necesario.

Ejemplo de recurso de marionetas para archivo

En el siguiente comando, intentamos especificar un permiso para un archivo en particular.

file {  
   '/etc/passwd': 
   owner => superuser, 
   group => superuser, 
   mode => 644, 
}

Siempre que el comando anterior se ejecute en cualquier máquina, verificará que el archivo passwd en el sistema esté configurado como se describe. El archivo antes: dos puntos es el título del recurso, al que se puede hacer referencia como recurso en otras partes de la configuración de Puppet.

Especificación del nombre local además del título

file { 'sshdconfig': 
   name => $operaSystem ? { 
      solaris => '/usr/local/etc/ssh/sshd_config', 
      default => '/etc/ssh/sshd_config', 
   }, 
   owner => superuser, 
   group => superuser, 
   mode => 644, 
}

Al usar el título, que siempre es el mismo, es muy fácil hacer referencia al recurso del archivo en la configuración sin tener que repetir la lógica relacionada con el sistema operativo.

Otro ejemplo podría ser el uso de un servicio que depende de un archivo.

service { 'sshd': 
   subscribe => File[sshdconfig], 
}

Con esta dependencia, el sshd El servicio siempre se reiniciará una vez que sshdconfigcambios de archivo. El punto a recordar aquí esFile[sshdconfig] es una declaración como Archivo como en minúsculas pero si lo cambiamos a FILE[sshdconfig] entonces habría sido una referencia.

Un punto fundamental que se debe tener en cuenta al declarar un recurso es que solo se puede declarar una vez por archivo de configuración. La repetición de la declaración del mismo recurso más de una vez provocará un error. Mediante este concepto fundamental, Puppet se asegura de que la configuración esté bien modelada.

Incluso tenemos la capacidad de administrar la dependencia de recursos, lo que ayuda a administrar múltiples relaciones.

service { 'sshd': 
   require => File['sshdconfig', 'sshconfig', 'authorized_keys']
}

Metaparámetros

Los metaparámetros se conocen como parámetros globales en Puppet. Una de las características clave del metaparámetro es que funciona con cualquier tipo de recurso en Puppet.

Recurso predeterminado

Cuando se necesita definir un valor de atributo de recurso predeterminado, Puppet proporciona un conjunto de sintaxis para archivarlo, utilizando una especificación de recurso en mayúscula que no tiene título.

Por ejemplo, si queremos establecer la ruta por defecto de todos los ejecutables lo podemos hacer con el siguiente comando.

Exec { path => '/usr/bin:/bin:/usr/sbin:/sbin' } 
exec { 'echo Testing mataparamaters.': }

En el comando anterior, la primera instrucción Exec establecerá el valor predeterminado para el recurso exec. El recurso Exec requiere una ruta completamente calificada o una ruta que parezca un ejecutable. Con esto, se puede definir una única ruta predeterminada para toda la configuración. Los valores predeterminados funcionan con cualquier tipo de recurso en Puppet.

Los valores predeterminados no son valores globales, sin embargo, solo afectan el ámbito en el que están definidos o la variable más próxima a él. Si uno quiere definirdefault para una configuración completa, entonces definimos el default y la clase en la siguiente sección.

Colecciones de recursos

La agregación es un método para recopilar cosas juntas. Puppet apoya un concepto muy poderoso de agregación. En Puppet, la agregación se utiliza para agrupar recursos, que es la unidad fundamental de Puppet. Este concepto de agregación en Puppet se logra utilizando dos métodos poderosos conocidos comoclasses y definition.

Clases y definición

Las clases son responsables de modelar los aspectos fundamentales del nodo. Pueden decir que el nodo es un servidor web y este nodo en particular es uno de ellos. En Puppet, las clases de programación son singleton y pueden evaluarse una vez por nodo.

Por otro lado, la definición se puede usar muchas veces en un solo nodo. Funcionan de manera similar a como uno ha creado su propio tipo de títeres utilizando el lenguaje. Se crean para usarse varias veces con una entrada diferente cada vez. Esto significa que se pueden pasar valores variables a la definición.

Diferencia entre clase y definición

La única diferencia clave entre una clase y una definición es que, al definir la estructura del edificio y asignar recursos, la clase se evalúa solo una vez por nodo, mientras que, por otro lado, una definición se usa varias veces en el mismo nodo.

Clases

Las clases en Puppet se introducen utilizando la palabra clave class y el contenido de esa clase en particular se incluye entre llaves como se muestra en el siguiente ejemplo.

class unix { 
   file { 
      '/etc/passwd': 
      owner => 'superuser', 
      group => 'superuser', 
      mode => 644; 
      '/etc/shadow': 
      owner => 'vipin', 
      group => 'vipin', 
      mode => 440; 
   } 
}

En el siguiente ejemplo, hemos utilizado una mano corta que es similar a la anterior.

class unix { 
   file { 
      '/etc/passwd': 
      owner => 'superuser', 
      group => 'superuser', 
      mode => 644; 
   }  
   
   file {'/etc/shadow': 
      owner => 'vipin', 
      group => 'vipin', 
      mode => 440; 
   } 
}

Herencia en las clases de títeres

En Puppet, el concepto de herencia de OOP es compatible de forma predeterminada, donde las clases pueden extender la funcionalidad de la anterior sin copiar y pegar el bit de código completo nuevamente en la clase recién creada. La herencia permite que la subclase anule la configuración de recursos definida en la clase principal. Una cosa clave a tener en cuenta al usar la herencia es que una clase solo puede heredar características de una sola clase principal, no más de una.

class superclass inherits testsubclass { 
   File['/etc/passwd'] { group => wheel } 
   File['/etc/shadow'] { group => wheel } 
}

Si es necesario deshacer alguna lógica especificada en una clase principal, podemos usar undef command.

class superclass inherits testsubcalss { 
   File['/etc/passwd'] { group => undef } 
}

Forma alternativa de utilizar la herencia

class tomcat { 
   service { 'tomcat': require => Package['httpd'] } 
} 
class open-ssl inherits tomcat { 
   Service[tomcat] { require +> File['tomcat.pem'] } 
}

Clase anidada en títeres

Puppet apoya el concepto de anidamiento de clases en el que permite usar clases anidadas, lo que significa una clase dentro de la otra. Esto ayuda a lograr la modularidad y el alcance.

class testclass { 
   class nested { 
      file {  
         '/etc/passwd': 
         owner => 'superuser', 
         group => 'superuser', 
         mode => 644; 
      } 
   } 
} 
class anotherclass { 
   include myclass::nested 
}

Clases parametrizadas

En Puppet, las clases pueden ampliar su funcionalidad para permitir el paso de parámetros a una clase.

Para pasar un parámetro en una clase, se puede usar la siguiente construcción:

class tomcat($version) { 
   ... class contents ... 
}

Un punto clave para recordar en Puppet es que las clases con parámetros no se agregan usando la función de inclusión, sino que la clase resultante se puede agregar como una definición.

node webserver { 
   class { tomcat: version => "1.2.12" } 
}

Valores predeterminados como parámetros en clase

class tomcat($version = "1.2.12",$home = "/var/www") { 
   ... class contents ... 
}

Ejecutar etapas

Puppet admite el concepto de etapa de ejecución, lo que significa que el usuario puede agregar una cantidad múltiple de etapas según el requisito para administrar cualquier recurso en particular o múltiples recursos. Esta característica es muy útil cuando el usuario desea desarrollar un catálogo complejo. En un catálogo complejo, uno tiene una gran cantidad de recursos que deben compilarse teniendo en cuenta que las dependencias entre los recursos definidos no deben verse afectadas.

Run Stage es muy útil para administrar las dependencias de recursos. Esto se puede hacer agregando clases en etapas definidas donde una clase particular contiene una colección de recursos. Con la etapa de ejecución, Puppet garantiza que las etapas definidas se ejecutarán en un orden predecible especificado cada vez que el catálogo se ejecute y se aplique en cualquier nodo de Puppet.

Para usar esto, es necesario declarar etapas adicionales más allá de las etapas ya presentes y luego Puppet puede configurarse para administrar cada etapa en un orden específico usando la misma sintaxis de relación de recursos antes de requerir “->” y “+>”. La relación garantizará entonces el orden de clases asociado a cada etapa.

Declarar etapas adicionales con la sintaxis declarativa Puppet

stage { "first": before => Stage[main] } 
stage { "last": require => Stage[main] }

Una vez que se han declarado las etapas, una clase puede asociarse con la etapa que no sea la principal que usa la etapa.

class { 
   "apt-keys": stage => first; 
   "sendmail": stage => main; 
   "apache": stage => last; 
}

Todos los recursos asociados con la clase apt-key se ejecutarán primero. Todos los recursos en Sendmail serán la clase principal y los recursos asociados con Apache serán la última etapa.

Definiciones

En Puppet, la recopilación de recursos en cualquier archivo de manifiesto se realiza mediante clases o definiciones. Las definiciones son muy similares a una clase en Puppet, sin embargo, se introducen con undefine keyword (not class)y apoyan el argumento, no la herencia. Pueden ejecutarse en el mismo sistema varias veces con diferentes parámetros.

Por ejemplo, si uno quiere crear una definición que controle los repositorios de código fuente donde uno está tratando de crear múltiples repositorios en el mismo sistema, entonces puede usar la definición, no la clase.

define perforce_repo($path) { 
   exec {  
      "/usr/bin/svnadmin create $path/$title": 
      unless => "/bin/test -d $path", 
   } 
} 
svn_repo { puppet_repo: path => '/var/svn_puppet' } 
svn_repo { other_repo: path => '/var/svn_other' }

El punto clave que debe tenerse en cuenta aquí es cómo se puede usar una variable con una definición. Usamos ($) variable de signo de dólar. En lo anterior, hemos utilizado $ title. Las definiciones pueden tener tanto un $ título como un $ nombre con el que se pueden representar el nombre y el título. De forma predeterminada, $ title y $ name se establecen en el mismo valor, pero se puede establecer un atributo de título y pasar un nombre diferente como parámetro. $ title y $ name solo funcionan en la definición, no en la clase u otro recurso.

Módulos

Un módulo puede definirse como una colección de todas las configuraciones que utilizaría el maestro de Puppet para aplicar cambios de configuración en cualquier nodo (agente) de Puppet en particular. También se conocen como colección portátil de diferentes tipos de configuraciones, que son necesarias para realizar una tarea específica. Por ejemplo, un módulo puede contener todos los recursos necesarios para configurar Postfix y Apache.

Nodos

Los nodos son un paso restante muy simple, que es cómo hacemos coincidir lo que definimos ("así es como se ve un servidor web") con las máquinas que se eligen para cumplir con esas instrucciones.

La definición de nodo se parece exactamente a las clases, incluida la herencia de soporte, sin embargo, son especiales, de modo que cuando un nodo (una computadora administrada que ejecuta un cliente de títeres) se conecta al demonio maestro de títeres, su nombre se buscará en la lista definida de nodos. La información definida se evaluará para el nodo y luego el nodo enviará esa configuración.

El nombre de nodo puede ser un nombre de host corto o el nombre de dominio completo (FQDN).

node 'www.vipin.com' { 
   include common 
   include apache, squid 
}

La definición anterior crea un nodo llamado www.vipin.com e incluye la clase común, Apache y Squid

Podemos enviar la misma configuración a diferentes nodos separando cada uno con una coma.

node 'www.testing.com', 'www.testing2.com', 'www3.testing.com' { 
   include testing 
   include tomcat, squid 
}

Expresión regular para nodos coincidentes

node /^www\d+$/ { 
   include testing 
}

Herencia de nodo

Node admite un modelo de herencia limitado. Al igual que las clases, los nodos solo pueden heredar de otro nodo.

node 'www.testing2.com' inherits 'www.testing.com' { 
   include loadbalancer 
}

En el código anterior, www.testing2.com hereda todas las funcionalidades de www.testing.com además de una clase de equilibrador de carga adicional.

Funciones avanzadas compatibles

Quoting- En la mayoría de los casos, no necesitamos citar una cadena en Puppet. Cualquier cadena alfanumérica que comience con una letra debe dejarse sin comillas. Sin embargo, siempre es una buena práctica citar una cadena para los valores no negativos.

Interpolación variable con cotizaciones

Hasta ahora hemos mencionado la variable en términos de definición. Si necesita usar esas variables con una cadena, use comillas dobles, no comillas simples. La cadena de comillas simples no hará ninguna interpolación de variables, la cadena de comillas dobles funcionará. La variable se puede poner entre corchetes{} lo que los hace más fáciles de usar juntos y más fáciles de entender.

$value = "${one}${two}"

Como práctica recomendada, se deben utilizar comillas simples para todas las cadenas que no requieren interpolación de cadenas.

Capitalización

La capitalización es un proceso que se utiliza para hacer referencia, heredar y establecer atributos predeterminados de un recurso en particular. Básicamente, hay dos formas fundamentales de utilizarlo.

  • Referencing- Es la forma de referenciar un recurso ya creado. Se utiliza principalmente para fines de dependencia, hay que escribir con mayúscula el nombre del recurso. Ejemplo, require => file [sshdconfig]

  • Inheritance- Al anular la configuración de la clase principal de la subclase, use la versión en mayúsculas del nombre del recurso. El uso de la versión en minúsculas resultará en un error.

  • Setting Default Attribute Value - Usar el recurso en mayúsculas sin título funciona para establecer el valor predeterminado del recurso.

Matrices

Puppet permite el uso de matrices en múltiples áreas [Uno, dos, tres].

Varios miembros de tipo, como alias en la definición de host, aceptan matrices en sus valores. Un recurso de host con varios alias tendrá el siguiente aspecto.

host { 'one.vipin.com': 
   alias => [ 'satu', 'dua', 'tiga' ], 
   ip => '192.168.100.1', 
   ensure => present, 
}

El código anterior agregará un host ‘one.brcletest.com’ a la lista de hosts con tres alias ‘satu’ ‘dua’ ‘tiga’. Si uno desea agregar varios recursos a un recurso, puede hacerlo como se muestra en el siguiente ejemplo.

resource { 'baz': 
   require => [ Package['rpm'], File['testfile'] ], 
}

Variables

Puppet admite múltiples variables como la mayoría de los otros lenguajes de programación. Las variables de marionetas se denotan con$.

$content = 'some content\n' 
file { '/tmp/testing': content => $content }

Como se dijo anteriormente, Puppet es un lenguaje declarativo, lo que significa que su alcance y reglas de asignación son diferentes al lenguaje imperativo. La principal diferencia es que no se puede cambiar la variable dentro de un único ámbito, porque dependen del orden en el archivo para determinar el valor de una variable. El orden no importa en el lenguaje declarativo.

$user = root 
file {  
   '/etc/passwd': 
   owner => $user, 
} 

$user = bin 
   file {  
      '/bin': 
      owner => $user, 
      recurse => true, 
   }

Alcance variable

El alcance de la variable define si todas las variables definidas son válidas. Al igual que con las funciones más recientes, Puppet actualmente tiene un alcance dinámico, lo que en términos de Puppet significa que todas las variables que están definidas se evalúan en su alcance en lugar de en la ubicación en la que están definidas.

$test = 'top' 
class Testclass { 
   exec { "/bin/echo $test": logoutput => true } 
} 

class Secondtestclass { 
   $test = 'other' 
   include myclass 
} 

include Secondtestclass

Variable calificada

Puppet admite el uso de variables calificadas dentro de una clase o una definición. Esto es muy útil cuando el usuario desea utilizar la misma variable en otras clases, que ha definido o va a definir.

class testclass { 
   $test = 'content' 
} 

class secondtestclass { 
   $other = $myclass::test 
}

En el código anterior, el valor de $ otra variable evalúa el contenido.

Condicionales

Las condiciones son situaciones en las que el usuario desea ejecutar un conjunto de instrucciones o códigos cuando se cumple la condición definida o la condición requerida. Puppet admite dos tipos de condiciones.

La condición del selector que solo se puede usar dentro de los recursos definidos para elegir el valor correcto de la máquina.

Las condiciones de declaración son condiciones más ampliamente utilizadas en el manifiesto que ayudan a incluir clases adicionales que el usuario desea incluir en el mismo archivo de manifiesto. Defina un conjunto distinto de recursos dentro de una clase o tome otras decisiones estructurales.

Selectores

Los selectores son útiles cuando el usuario desea especificar un atributo de recurso y variables que son diferentes de los valores predeterminados basados ​​en hechos u otras variables. En Puppet, el índice del selector funciona como un operador de tres vías con varios valores. Los selectores también son capaces de definir los valores predeterminados personalizados sin valores, que se definen en el manifiesto y coinciden con la condición.

$owner = $Sysoperenv ? { 
   sunos => 'adm', 
   redhat => 'bin', 
   default => undef, 
}

En versiones posteriores de Puppet 0.25.0, los selectores se pueden usar como expresiones regulares.

$owner = $Sysoperenv ? { 
   /(Linux|Ubuntu)/ => 'bin', 
   default => undef, 
}

En el ejemplo anterior, el selector $Sysoperenv El valor coincide con Linux o Ubuntu, entonces el bin será el resultado seleccionado; de lo contrario, el usuario se establecerá como indefinido.

Condición de declaración

La condición de declaración es otro tipo de declaración condicional en Puppet que es muy similar a la condición de cambio de caso en el script Shell. En esto, se define un conjunto múltiple de declaraciones de casos y los valores de entrada dados se comparan con cada condición.

Se ejecuta la declaración del caso que coincide con la condición de entrada dada. Esta condición de declaración de caso no tiene ningún valor de retorno. En Puppet, un caso de uso muy común para la declaración de condición es ejecutar un conjunto de bits de código basado en el sistema operativo subyacente.

case $ Sysoperenv { 
   sunos: { include solaris }  
   redhat: { include redhat }  
   default: { include generic}  
}

Case Statement también puede especificar varias condiciones separándolas con una coma.

case $Sysoperenv { 
   development,testing: { include development } testing,production: { include production }
   default: { include generic }  
}

Declaración If-Else

Puppet apoya el concepto de operación basada en condiciones. Para lograrlo, la declaración If / else proporciona opciones de ramificación basadas en el valor de retorno de la condición. Como se muestra en el siguiente ejemplo:

if $Filename { 
   file { '/some/file': ensure => present } 
} else { 
   file { '/some/other/file': ensure => present } 
}

La última versión de Puppet admite expresiones variables en las que la instrucción if también puede ramificarse según el valor de una expresión.

if $machine == 'production' { 
   include ssl 
} else { 
   include nginx 
}

Para lograr una mayor diversidad en el código y realizar operaciones condicionales complejas, Puppet admite la declaración anidada if / else como se muestra en el siguiente código.

if $ machine == 'production' { 
   include ssl 
} elsif $ machine == 'testing' { 
   include nginx
} else { 
   include openssl 
}

Recurso virtual

Los recursos virtuales son aquellos que no se envían al cliente a menos que se realicen.

A continuación se muestra la sintaxis del uso de recursos virtuales en Puppet.

@user { vipin: ensure => present }

En el ejemplo anterior, el usuario vipin se define virtualmente para darse cuenta de la definición que se puede usar en la colección.

User <| title == vipin |>

Comentarios

Los comentarios se utilizan en cualquier bit de código para crear un nodo adicional sobre un conjunto de líneas de código y su funcionalidad. En Puppet, actualmente hay dos tipos de comentarios compatibles.

  • Comentarios de estilo shell de Unix. Pueden estar en su propia línea o en la siguiente.
  • Comentarios estilo C de varias líneas.

A continuación se muestra un ejemplo de comentario de estilo shell.

# this is a comment

A continuación se muestra un ejemplo de comentario de varias líneas.

/* 
This is a comment 
*/

Prioridad del operador

La precedencia del operador Puppet se ajusta a la precedencia estándar en la mayoría de los sistemas, desde el más alto al más bajo.

A continuación se muestra la lista de expresiones

  • ! = no
  • / = tiempos y dividir
  • - + = menos, más
  • << >> = desplazamiento a la izquierda y desplazamiento a la derecha
  • ==! = = no igual, igual
  • > = <=> <= mayor igual, menor o igual, mayor que, menor que

Expresión de comparación

Las expresiones de comparación se utilizan cuando el usuario desea ejecutar un conjunto de declaraciones cuando se cumple la condición dada. Las expresiones de comparación incluyen pruebas de igualdad mediante la expresión ==.

if $environment == 'development' { 
   include openssl 
} else { 
   include ssl 
}

Ejemplo no igual

if $environment != 'development' { 
   $otherenvironment = 'testing' 
} else { 
   $otherenvironment = 'production' 
}

Expresión aritmética

$one = 1 
$one_thirty = 1.30 
$two = 2.034e-2 $result = ((( $two + 2) / $one_thirty) + 4 * 5.45) - 
   (6 << ($two + 4)) + (0×800 + -9)

Expresión booleana

Las expresiones booleanas son posibles usando or, y, & not.

$one = 1 
$two = 2 
$var = ( $one < $two ) and ( $one + 1 == $two )

Expresión regular

Puppet admite la coincidencia de expresiones regulares usando = ~ (coincidencia) y! ~ (No coincidencia).

if $website =~ /^www(\d+)\./ { 
   notice('Welcome web server #$1') 
}

La coincidencia de regex de caso y selector crea una variable de alcance limitado para cada expresión regular.

exec { "Test": 
   command => "/bin/echo now we don’t have openssl installed on machine > /tmp/test.txt", 
   unless => "/bin/which php" 
}

De manera similar, podemos usar a menos, a menos que ejecute el comando todo el tiempo, excepto el comando debajo a menos que salga con éxito.

exec { "Test": 
   command => "/bin/echo now we don’t have openssl installed on machine > /tmp/test.txt", 
   unless => "/bin/which php" 
}

Trabajar con plantillas

Las plantillas se utilizan cuando se desea tener una estructura predefinida que se utilizará en varios módulos en Puppet y esos módulos se distribuirán en varias máquinas. El primer paso para utilizar la plantilla es crear una que represente el contenido de la plantilla con métodos de plantilla.

file { "/etc/tomcat/sites-available/default.conf": 
   ensure => "present", 
   content => template("tomcat/vhost.erb")  
}

Puppet hace pocas suposiciones cuando se trata de archivos locales para reforzar la organización y la modularidad. Puppet busca la plantilla vhost.erb dentro de la carpeta apache / templates, dentro del directorio de módulos.

Definición y activación de servicios

En Puppet, tiene un recurso llamado servicio que es capaz de administrar el ciclo de vida de todos los servicios que se ejecutan en cualquier máquina o entorno en particular. Los recursos del servicio se utilizan para asegurarse de que los servicios se inicialicen y habiliten. También se utilizan para reiniciar el servicio.

Por ejemplo, en la plantilla anterior de tomcat que tenemos donde configuramos el host virtual apache. Si uno quiere asegurarse de que apache se reinicie después de un cambio de host virtual, necesitamos crear un recurso de servicio para el servicio de apache usando el siguiente comando.

service { 'tomcat': 
   ensure => running, 
   enable => true 
}

Al definir los recursos, debemos incluir la opción de notificación para activar el reinicio.

file { "/etc/tomcat/sites-available/default.conf": 
   ensure => "present", 
   content => template("vhost.erb"), 
   notify => Service['tomcat']  
}