

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Ejemplo 4: Añadir control de flujo
<a name="cookbooks-101-basics-ruby"></a>

**importante**  
El AWS OpsWorks Stacks servicio llegó al final de su vida útil el 26 de mayo de 2024 y se ha desactivado tanto para los clientes nuevos como para los actuales. Recomendamos encarecidamente a los clientes que migren sus cargas de trabajo a otras soluciones lo antes posible. Si tienes preguntas sobre la migración, ponte en contacto con el AWS Support equipo en [AWS Re:post](https://repost.aws/) o a través de Premium [AWS Support](https://aws.amazon.com/support).

Algunas recetas son simplemente una serie de recursos de Chef. En dicho caso, al ejecutar la receta, esta se limita a ejecutar en secuencia cada uno de los proveedores de recursos. Sin embargo, a menudo es útil disponer de una ruta de ejecución más sofisticada. A continuación, mostramos dos situaciones que se producen con frecuencia:
+ Quiere que una receta ejecute el mismo recurso varias veces con diferentes valores de atributo.
+ Quiere utilizar diferentes valores de atributo en sistemas operativos distintos.

Puede abordar ambas situaciones incorporando estructuras de control de Ruby en la receta. En esta sección se muestra cómo modificar la receta del [Ejemplo 3: Creación de directorios](cookbooks-101-basics-directories.md) para encarar ambos casos.

**Topics**
+ [Iteración](#cookbooks-101-basics-ruby-iteration)
+ [Lógica condicional](#cookbooks-101-basics-ruby-conditional)

## Iteración
<a name="cookbooks-101-basics-ruby-iteration"></a>

En el [Ejemplo 3: Creación de directorios](cookbooks-101-basics-directories.md) se mostraba cómo utilizar un recurso `directory` para crear un directorio o una cadena de directorios. Sin embargo, supongamos que desee crear dos directorios diferentes, `/srv/www/config` y `/srv/www/shared`. Podría implementar un recurso de directorio diferente para cada directorio, pero este enfoque puede ser demasiado laborioso si desea crear muchos directorios. En la receta siguiente se muestra una forma más sencilla de gestionar la tarea. 

```
[ "/srv/www/config", "/srv/www/shared" ].each do |path|
  directory path do
    mode 0755
    owner 'root'
    group 'root'
    recursive true
    action :create
  end
end
```

En lugar de utilizar un recurso de directorio diferente para cada subdirectorio, la receta utiliza una recopilación de cadenas que contienen las rutas de subdirectorio. El método `each` de Ruby ejecuta el recurso una vez por cada elemento de recopilación, empezando por el primero. El valor del elemento está representado en el recurso por la variable `path`, que en este caso representa la ruta del directorio. Es fácil adaptar este ejemplo para crear cualquier cantidad de subdirectorios.

**Para ejecutar la receta**

1. Quédese en el directorio `createdir`; utilizará ese libro de recetas en los siguientes ejemplos. 

1. Si aún no lo ha hecho, ejecute `kitchen destroy` para empezar con una instancia limpia. 

1. Sustituya el código de `default.rb` por el ejemplo y ejecute `kitchen converge`.

1. Inicie sesión en la instancia, verá los directorios recién creados en `/srv`.

Puede utilizar una tabla hash para especificar dos valores para cada iteración. La receta siguiente crea `/srv/www/config` y `/srv/www/shared`, cada uno con un modo diferente.

```
{ "/srv/www/config" => 0644, "/srv/www/shared" => 0755 }.each do |path, mode_value|
  directory path do
    mode mode_value
    owner 'root'
    group 'root'
    recursive true
    action :create
  end
end
```

**Para ejecutar la receta**

1. Si aún no lo ha hecho, ejecute `kitchen destroy` para empezar con una instancia limpia. 

1. Sustituya el código de `default.rb` por el ejemplo y ejecute `kitchen converge`.

1. Inicie sesión en la instancia; verá los directorios recién creados en `/srv` con los modos especificados.

**nota**  
OpsWorks Las recetas de Stacks suelen utilizar este enfoque para extraer valores del [JSON de configuración e implementación de la pila](workingcookbook-json.md) (que básicamente es una gran tabla de hash) e insertarlos en un recurso. Para ver un ejemplo, consulta [Recetas de implementación](create-custom-deploy.md).

## Lógica condicional
<a name="cookbooks-101-basics-ruby-conditional"></a>

También puede utilizar la lógica condicional de Ruby para crear varias ramas de ejecución. La siguiente receta utiliza la lógica `if-elsif-else` para ampliar el ejemplo anterior y crear un subdirectorio denominado `/srv/www/shared`, aunque solo en sistemas Debian y Ubuntu. En cuanto al resto los de sistemas, registra un mensaje de error que se muestra en la salida de Test Kitchen.

```
if platform?("debian", "ubuntu")
  directory "/srv/www/shared" do
    mode 0755
    owner 'root'
    group 'root'
    recursive true
    action :create
  end
else
  log "Unsupported system"
end
```

**Para ejecutar la receta del ejemplo**

1. Si la instancia sigue estando activa, ejecute `kitchen destroy` para cerrarla.

1. Sustituya el código de `default.rb` por el código del ejemplo.

1. Edite `.kitchen.yml` para añadir un sistema CentOS 6.4 a la lista de plataformas. La sección `platforms` del archivo debe parecerse a lo siguiente.

   ```
   ...
   platforms:
     - name: ubuntu-12.04
     - name: centos-6.4
   ...
   ```

1. Ejecute `kitchen converge`, lo que creará una instancia y ejecutará las recetas para cada plataforma de `.kitchen.yml`, en secuencia. 
**nota**  
Si desea converger solo una instancia, añada el nombre de la instancia como parámetro. Por ejemplo, para converger la receta únicamente en la plataforma Ubuntu, ejecute `kitchen converge default-ubuntu-1204`. Si no recuerda los nombres de plataforma, ejecute `kitchen list`.

Deberá ver el mensaje de registro en la parte CentOS de la salida de Test Kitchen, que tendrá un aspecto similar al siguiente:

```
...
Converging 1 resources
Recipe: createdir::default
* log[Unsupported system] action write[2014-06-23T19:10:30+00:00] INFO: Processing log[Unsupported system] action write (createdir::default line 12)
[2014-06-23T19:10:30+00:00] INFO: Unsupported system
       
[2014-06-23T19:10:30+00:00] INFO: Chef Run complete in 0.004972162 seconds
```

Ahora puede iniciar sesión en las instancias y verificar si los directorios se han creado o no. Sin embargo, ahora no puede limitarse a ejecutar `kitchen login`. Debe especificar la instancia anexando el nombre de la plataforma; por ejemplo, `kitchen login default-ubuntu-1204`. 

**nota**  
Si un comando de Test Kitchen toma el nombre de una instancia, no es necesario escribir el nombre completo. Test Kitchen trata el nombre de una instancia como una expresión regular de Ruby, por lo que solo necesita los suficientes caracteres para proporcionar una coincidencia única. Por ejemplo, puede converger solo la instancia de Ubuntu ejecutando `kitchen converge ub` o iniciando sesión en la instancia de CentOS ejecutando `kitchen login 64`.

Probablemente se esté preguntando cómo sabe la receta en qué plataforma se está ejecutando. Chef ejecuta una herramienta llamada [Ohai](https://docs.chef.io/ohai.html) por cada ejecución que recopila datos del sistema, incluida la plataforma, y los representa como un conjunto de atributos en una estructura denominada el *objeto de nodo*. El método `platform?` de Chef compara los sistemas que están entre paréntesis con el valor de la plataforma Ohai y devuelve true si uno de ellos coincide.

Puede hacer referencia al valor de un atributo de nodo directamente en su código usando `node['attribute_name']`. El valor de la plataforma, por ejemplo, está representado por `node['platform']`. Podría, por ejemplo, haber escrito el ejemplo anterior tal y como se indica a continuación.

```
if node[:platform] == 'debian' or node[:platform] == 'ubuntu'
  directory "/srv/www/shared" do
    mode 0755
    owner 'root'
    group 'root'
    recursive true
    action :create
  end
else
  log "Unsupported system"
end
```

Por lo general, una lógica condicional se incluye en una receta para tener en cuenta el hecho de que las diferentes familias de Linux a veces utilizan denominaciones distintas para paquetes, directorios, etc. Por ejemplo, el nombre del paquete Apache es `httpd` en los sistemas CentOS y `apache2` en los sistemas Ubuntu.

Si solo necesita una cadena diferente para diferentes sistemas, el método [http://docs.chef.io/dsl_recipe.html#value-for-platform](http://docs.chef.io/dsl_recipe.html#value-for-platform) de Chef es una solución más sencilla que `if-elsif-else`. En la siguiente receta se crea un directorio `/srv/www/shared` en los sistemas CentOS, un directorio `/srv/www/data` en los sistemas Ubuntu y `/srv/www/config` en todos los demás.

```
data_dir = value_for_platform(
  "centos" => { "default" => "/srv/www/shared" },
  "ubuntu" => { "default" => "/srv/www/data" },
  "default" => "/srv/www/config"
)
directory data_dir do
  mode 0755
  owner 'root'
  group 'root'
  recursive true
  action :create
end
```

`value_for_platform` asigna la ruta apropiada a `data_dir` y el recurso `directory` utiliza dicho valor para crear el directorio.

**Para ejecutar la receta del ejemplo**

1. Si la instancia sigue estando activa, ejecute `kitchen destroy` para cerrarla.

1. Sustituya el código de `default.rb` por el código del ejemplo.

1. Ejecute `kitchen converge` y, a continuación, inicie sesión en cada instancia para verificar que contengan los directorios adecuados.