Saltar a contenido

Ejecutar Comandos Shell

Uno de los principales objetivos de los rulebooks es hacer extremadamente fácil llamar a comandos shell.

Los comandos shell pueden ejecutarse localmente (en el servidor Clarive) o remotamente (es decir, en un nodo remoto). Necesitará decidir dónde ejecutar sus comandos.

Ejecutar Comandos Localmente

Los comandos locales se ejecutan en un shell en el servidor Clarive, siempre dentro de un contenedor Docker.

do:
     # Esta es la forma larga de ejecutar un comando shell:

    - shell:
        cmd: ls
        args:
           - "-l"
           - "-a"

Lo cual, afortunadamente, puede acortarse a algo como esto:

do:
    - shell: ls -la # oh, esto es mucho mejor

Si prefiere separar sus argumentos, también hay una versión concisa:

do:
     - shell:
         - apt
         - install
         - build-essential
         - openssl

     # que se convierte en "apt install build-essential openssl" en el shell

O en notación de array concisa:

do:
     - shell: [ 'apt', 'install', 'build-essential', 'openssl' ]

     # igual, se convierte en "apt install build-essential openssl" en el shell

O mejor aún, usando la notación directa. Desafortunadamente, la notación directa no tiene un argumento de array (args), pero definitivamente es el camino a seguir.

do:
    - ls -lart    # sí, esto es mucho mejor
    - "ls -lart"  # ídem

Si necesita ejecutar múltiples comandos a la vez, puede separarlos con nueva línea:

do:
    - shell:
        cmd: |
         echo hello >> /clarive/myfile
         echo world >> /clarive/myfile
         cat /clarive/myfile

    # o así:

    - shell: |
         echo hello >> /clarive/myfile
         echo world >> /clarive/myfile
         cat /clarive/myfile

    # o aún:

    - |
         echo hello >> /clarive/myfile
         echo world >> /clarive/myfile
         cat /clarive/myfile

Asignar la salida a una variable

Ahora, la mejor característica de los comandos shell de rulebook es que puede asignar valores de comando a variables. Necesita anteponer el comando shell: con la variable que desea usar.

do:
   - result = shell: ls -lart /clarive
   - echo: "exit code was ${result.rc}, output: ${result.output}"

Los comandos siempre devuelven un objeto hash con 2 subclaves:

{
   rc: 0,          # el código de salida del comando
   output: '...'   # la salida capturada combinando stderr y stdout
}

Puede asignar una secuencia de comandos multilínea de la misma manera, pero debe usar shell::

do:

    - ret = shell: |
         echo hello >> /clarive/myfile
         echo world >> /clarive/myfile
         cat /clarive/myfile

    - echo: "OUTPUT = {{ ret.output }}"
    - echo: "EXIT CODE OF LAST COMMAND = {{ ret.rc }}"

Note

Los comandos shell fallidos (código de salida <> 0) que no se asignan a variables lanzarán errores que interrumpirán su rulebook.

Por lo tanto, asignar comandos a variables es una buena manera de capturar errores y procesarlos usted mismo.

Aquí hay un ejemplo de variable capturada con control de errores:

do:

    # captura y control de errores combinados

    - ret = shell: |
         ls -lart /clarive/
         ls -lart /clarive/this_folder_not_here

    - echo: "OUTPUT = {{ ret.output }}"

    - if: "{{ ret.rc }}"
      then:

         # use log: para salida coloreada en el visor de logs del job

         - log:
              msg: "We failed with rc={{ ret.rc }}"
              level: error
      else:
         - echo: "Everything okay"

Eso producirá la siguiente salida:

ls: cannot access '/clarive/not_exists': No such file or directory

We failed with rc=2

Comandos con pipe

A veces puede querer canalizar varios comandos shell juntos, redirigiendo la salida de un comando al siguiente. Esto es bastante trivial y lo gestiona el ejecutor del shell (una función C open3()):

do:
    - cat /etc/hosts | wc -l

Si desea canalizar la salida de vuelta a su rulebook, entonces debe configurar un callback stdout o stderr. El proceso shell invocará el callback con fragmentos de salida.

do:
    - shell:
        cmd: find /
        pipe_out:
           - echo: "Got a stdout chunk here: ${chunk}"

O procesarlo con ClaJS directamente:

do:
    - shell:
        cmd: find /
        pipe_out: |
           print( "Got it here now: " + cla.stash('chunk') );

Seleccionar una Imagen Docker

Los comandos que se ejecutan en el servidor siempre se ejecutan en un contenedor Docker. Por defecto, los comandos se ejecutan en la imagen predeterminada de clarive. Pero puede controlar fácilmente qué imagen de contenedor se está usando con el op image:.

do:
    # descargar e instalar una imagen python desde Docker Hub
    # (si aún no la tiene instalada)

   - image: python
   - python --version

Puede alternar entre imágenes a medida que avanza:

do:
    # python primero

   - image: python
   - python --version

    # luego ruby

   - image: ruby
   - ruby --version
   - gem install json

O ejecutarlo dentro de un bloque image: con do:, lo que lo agrupa bien:

do:
    # tenga cuidado de indentar correctamente image y do

   - image: ruby
   - do:
      - gem install json
      - gem install mongo

Important

Cada comando que se ejecuta en una imagen Docker ejecutará docker run -it cada vez. Use los comandos multilínea mostrados arriba para ejecutarlos en la misma sesión de ejecución de contenedor.

Ejecutar comandos remotamente

Puede ejecutar comandos shell en servidores remotos usando las opciones host: o worker: del op shell:. Pero primero necesita tener el servidor remoto conectado al servidor Clarive usando uno de los siguientes métodos:

  • Clarive Worker - probablemente la forma más fácil, simplemente descargue un worker en la máquina remota y regístrelo con su servidor.

  • SSH - el servidor Clarive necesita tener su clave pública en las authorized_keys del servidor de destino para los usuarios con los que pretende conectarse.

  • Clarive ClaX Agent - el agente ClaX necesita estar ejecutándose como un proceso InetD o agente independiente escuchando en un puerto dado.

En este documento solo se cubre el Clarive Worker, ya que los agentes SSH y ClaX son más adecuados para reglas de Clarive y no para rulebooks.

Ejecutar un comando en el Clarive Worker

Antes de ejecutar cualquier comando, asegúrese de que el Clarive Worker esté registrado e iniciado.

Supongamos que su worker se registró con el id myworkerid.

  cla-worker run --id myworkerid --token [el token que se le dio con el comando register]

Para ejecutar un comando shell con el Clarive Worker:

do:
    - ret = shell:
        worker: myworkerid
        cmd: ls -lart /tmp/
    - echo: "OUTPUT = {{ ret.output }}"
    - echo: "EXIT CODE OF LAST COMMAND = {{ ret.rc }}"

En caso de que solo quiera elegir cualquier worker disponible para su comando, puede usar el asterisco:

do:
    - ret = shell:
        worker: '*'  # solo el primer worker disponible
        cmd: ls -lart /tmp/

En caso de que establezca algunas etiquetas para identificar su worker, use eso para encontrar el primer worker disponible que pueda manejar una o un conjunto de etiquetas:

  cla-worker run --id myworkerid --token [...] --tags node,npm

Luego ejecute el comando destinado a los workers etiquetados:

do:
    - ret = shell:
        worker: { tags: ['npm','node'] }
        cmd: |
            cd /opt/build/myproject
            npm run tests

¡Eso es todo! Asegúrese de leer también cómo enviar y recuperar archivos del worker en la documentación.