Descripción general
Una definición de flujo de trabajo describe el proceso automatizado que se va a ejecutar. Las definiciones de flujo de trabajo se escriben en YAML utilizando una convención de nomenclatura camelCase. Cada flujo de trabajo consta de:
- Propiedades del esquema: Información básica (nombre, descripción, entradas)
- Pasos: La secuencia de acciones a realizar
- Expresiones: Valores dinámicos utilizando la sintaxis jq
- Secretos: Referencias de credenciales seguras
Conceptos fundamentales
Antes de construir flujos de trabajo, comprenda estos conceptos básicos utilizados en las definiciones de flujo de trabajo.
Cadenas de expresión
Varias propiedades aceptan valores de cadena con expresiones integradas que se evalúan durante la ejecución del flujo de trabajo, lo que permite valores dinámicos en las definiciones del flujo de trabajo.
Las cadenas de expresión pueden contener una o más expresiones, cada una encerrada entre llaves dobles. El contenido dentro de las llaves se evalúa empleando jq, que proporciona poderosas capacidades para acceder y operar con valores.
Ejemplo:
Obtener la longitud de una cadena de entrada de flujo de trabajo:
${{ .workflowInputs.myString | length }}
Para validar y probar sus expresiones, emplee JQ Playground.
Propiedades de expresión
Se puede acceder a varias propiedades con expresiones. Estas propiedades viven en un objeto scope, por lo que las expresiones deben comenzar con un punto (.) para acceder a esas propiedades del objeto de alcance.
Las propiedades disponibles son:
workflowInputs- Objeto que contiene las entradas pasadas al flujo de trabajo al inicio.
Ejemplo:
${{ .workflowInputs.myInput }}
steps- Objeto que contiene una propiedad para cada paso del flujo de trabajosteps.<stepName>- Objeto que contiene propiedades para un paso específicosteps.<stepName>.outputs- Objeto que contiene propiedades de resultado, específicas del paso o acción.
Ejemplo: ${{ .steps.myStep.outputs.myResult }}
Resultados de la evaluación de la expresión
Una sola expresión jq puede evaluar cualquier tipo JSON. Sin embargo, el resultado final de una cadena de expresión depende de si la cadena contiene solo la expresión o contenido adicional.
Expresión única (conserva el tipo JSON):
Si una cadena de expresión consta de una sola expresión sin contenido circundante, se evalúa como el resultado de la expresión jq mientras mantiene su tipo JSON original. Por ejemplo, ${{ .workflowInputs.myArray }} se evalúa como una matriz. Esto es útil para pasar estructuras de datos complejas dentro de un flujo de trabajo.
Expresiones múltiples o contenido mixto (se convierte en cadena):
Si una cadena de expresión contiene contenido distinto a una única expresión, se evalúa como resultado una cadena. Esto ocurre cuando una expresión tiene contenido antes o luego de ella, o cuando la cadena tiene múltiples expresiones dentro de ella. Cada expresión dentro de la cadena se evalúa y se convierte en una representación de cadena.
Importante
Cuando una expresión jq se evalúa como nula, se devuelve un nodo nulo. Por ejemplo, la expresión ${{ .workflowInputs.missingInput }} devuelve nulo si no se proporciona missingInput como entrada del flujo de trabajo.
Ejemplo:
Supongamos que myArray tiene un valor de [1, 2, 3].
Cadena de expresión | Datos de resultados | Tipo de resultado |
|---|---|---|
|
| matriz de números |
| 3 | Número |
| Verdadero | Booleano |
|
| Cadena |
|
| Cadena |
Patrón seguro de expresión
Las propiedades que se pueden emplear en expresiones deben cumplir con: ^[A-Za-z_][A-Za-z0-9_]*$
Referencias secretas
Los valores secretos se pueden usar en acciones a través de cadenas de referencia que especifican el nombre de un secreto que se buscará en el Servicio de Secretos. Para hacer referencia a un secreto en una definición de flujo de trabajo, emplee la siguiente sintaxis:
${{ :secrets:<SECRET_NAME> }}para un secreto que no está en unnamespace${{ :secrets:<NAMESPACE>:<SECRET_NAME> }}para un secreto en unnamespace${{ :secrets:<SCOPE>:<NAMESPACE>:<SECRET_NAME> }}para un secreto en el alcance y namespace. El alcance solo aceptaACCOUNToORGANIZATIONpor ahora.
Una cadena de expresión puede contener una combinación de referencias secretas y expresiones JQ and/or múltiples referencias secretas.
Ejemplos:
steps: - name: mySecretStep type: action action: newrelic.instrumentation.log inputs: message: My message licenseKey: ${{ :secrets:<SECRET_NAME> }}steps: - name: bearer_auth type: action action: utils.http.post inputs: headers: Authorization: Bearer ${{ :secrets:<SECRET_NAME> }}Estructura del esquema
Propiedades del esquema
Propiedad | Obligatorio u opcional | Tipo | Formato | Restricciones | Descripción |
|---|---|---|---|---|---|
| Requerido | Cadena | Debe cumplir con las expresiones regulares
| Longitud máxima : 100 | Los valores
no distinguen entre mayúsculas y minúsculas. Por ejemplo, se considera que
,
y
representan la misma definición de flujo de trabajo. |
| Opcional | Cadena | Debe cumplir con las expresiones regulares
| Longitud máxima : 200 | Un
del flujo de trabajo que describe el propósito del flujo de trabajo. |
| Opcional | Mapa de mapas | Tamaño máximo : 100 | Un mapa de entradas de flujo de trabajo que acepta el flujo de trabajo. Vea las propiedades detalladas a continuación. |
Entradas de flujo de trabajo
Ejemplo:
workflowInputs: myInput1: type: String myInput2: type: Number defaultValue: 42workflowInputs.<inputName>(Obligatorio)- Tipo: Cadena (conforme al patrón seguro para expresiones)
- Longitud mínima: 1
- Longitud máxima: 50
- Descripción: El nombre de la entrada del flujo de trabajo.
workflowInputs.<inputName>.type(Obligatorio)- Tipo: Enumeración (
Boolean, List, Map, String, Int, Float) - Descripción: El tipo de datos de la entrada del flujo de trabajo.
- Tipo: Enumeración (
workflowInputs.<inputName>.defaultValue(Opcional)- Tipo: Cualquiera; debe ajustar a
type. - Descripción: El valor predeterminado para la entrada del flujo de trabajo.
- Tipo: Cualquiera; debe ajustar a
workflowInputs.<inputName>.required(Opcional)- Tipo: Booleano (
True,False). - Descripción: El valor predeterminado de este campo es "Verdadero".
- Tipo: Booleano (
workflowInputs.<inputName>.enumValues(Opcional)- Tipo: Lista (
String). - Descripción: El valor predeterminado de este campo es Lista vacía
{}. Esto es necesario cuando el tipo de workflowInput es Enum.
- Tipo: Lista (
workflowInputs.<inputName>.validations(Opcional)- Tipo: matriz de mapas.
- Descripción: Las validaciones que se deben realizar en las entradas del flujo de trabajo proporcionadas por el usuario. Este es un campo opcional. Las propiedades descritas aquí están presentes en todos los tipos de validación. Los tipos de validación específicos admiten propiedades adicionales como se analiza en la sección Tipos de validación.
validations[*].type(Obligatorio)- Tipo: Cadena
- Descripción: El tipo de validación que indica qué validación se realizará en este campo. Consulte Tipos de validación para obtener más información sobre cada tipo de validación.
validations[*].errorMessage(Obligatorio)- Tipo: Cadena
- Descripción: El mensaje de error que el usuario desea recibir cuando falla una validación particular.
Ejemplo de YAML para validaciones
name: calendar_demo
workflowInputs: timezone: type: String defaultValue: 'America/Los_Angeles' validations: - type: regex errorMessage: "The provided timezone is not correct" pattern: "^[A-Za-z]+\/[A-Za-z_]+(?:\/[A-Za-z_]+)?$"
- type: maxLength errorMessage: "Timezone length should be less than 100" length: 100
accountId: type: Int validations: - type: minIntValue errorMessage: "Account id should be greater than 100000" minValue: 100000 - type: maxIntValue errorMessage: "Account id should be less than 9999999" maxValue: 9999999
steps: - name: getCurrentTime type: action action: http.get version: 1 inputs: url: 'https://worldtimeapi.org/api/timezone/${{ .workflowInputs.timezone }}' selectors: - name: timezone expression: '.responseBody | fromjson.abbreviation' - name: datetime expression: '.responseBody | fromjson.datetime'Tipos de validación
Tipo de validación | Propiedad | Obligatorio u opcional | Tipo | Descripción |
|---|---|---|---|---|
|
| Requerido | Cadena | Valida el valor de entrada del flujo de trabajo contra el patrón de expresión regular proporcionado. |
|
| Requerido | Entero | Valida que el valor de entrada del flujo de trabajo debe ser menor que el valor máximo proporcionado. |
|
| Requerido | Entero | Valida que el valor de entrada del flujo de trabajo debe ser mayor que el valor mínimo proporcionado. |
|
| Requerido | Entero | Valida la longitud máxima de las cadenas de entrada del flujo de trabajo y las colecciones (
). |
Pasos
Propiedad | Obligatorio u opcional | Tipo | Restricciones | Descripción |
|---|---|---|---|---|
| Requerido | matriz de mapas | Los pasos a realizar cuando se ejecuta la definición del flujo de trabajo. Debe haber al menos un paso. Las propiedades descritas aquí están presentes en todos los tipos de pasos. Los tipos de pasos específicos admiten propiedades adicionales como se describe en la sección . |
Importante
Los pasos se ejecutan en el orden en que están definidos en la matriz steps. Si se desea un orden diferente, se puede realizar un jump estableciendo la propiedad steps[*].next en el nombre del paso deseado para saltar.
Propiedades comunes de los pasos
Propiedad | Obligatorio u opcional | Tipo | Formato | Restricciones | Descripción |
|---|---|---|---|---|---|
| Requerido | Cadena | Debe cumplir con el no puede ser
. | Longitud máxima: 100 | El nombre del paso al que hará referencia
. No pueden ser las palabras clave especiales
,
o
, ya que se emplean para indicar un paso final, una continuación de un bucle o para salir de un bucle. |
| Requerido | Cadena | El tipo de paso, que indica qué hace el paso cuando se ejecuta. Consulte los a continuación para conocer las opciones disponibles. | ||
| Opcional | Cadena | Debe cumplir con el patrón de expresión segura | El nombre del siguiente paso a ejecutar cuando este paso se complete exitosamente. La palabra clave especial end se puede emplear para indicar que este paso debe ser el último en ejecutar. Si se omite
, la siguiente entrada en la matriz de definición
se empleará como el siguiente paso implícito. Si no hay ninguna entrada siguiente, se completará el flujo de trabajo. | |
| Opcional | Booleano |
es una opción de configuración dentro de un paso de un flujo de trabajo. El valor predeterminado es falso. Al establecer
en
, el flujo de trabajo garantiza que cualquier error encontrado durante la ejecución de este paso no provocará que todo el flujo de trabajo falle. En su lugar, el flujo de trabajo continuará ejecutando los pasos siguientes. |
Tipos de pasos
Acción
Un paso que ejecuta una acción específica. Consulte el Catálogo de acciones para ver las opciones disponibles.
steps[*].action(Obligatorio)- Tipo: Cadena
- Descripción: El nombre completo de la función de acción que se va a ejecutar. Deberá seguir la siguiente convención:
<company domain>.<category of work>.<action name in camelCase>
Ejemplo:
Acción que emplea los servicios de New Relic (por ejemplo, a través de NerdGraph):
newrelic.dashboards.getDashboardAcción mediante Slack:
slack.chat.postMessagesteps[*].version(Obligatorio)- Tipo: Cadena
- Descripción: La versión de la función de acción que se va a ejecutar.
steps[*].inputs(Opcional)Tipo: Mapa de valores (incluye expresiones)
Descripción:
- Los datos de entrada que se pasarán a la función de acción. Las entradas específicas aceptadas se definen para cada acción.
- Las entradas pueden emplear expresiones. Consulte la sección Cadenas de expresión para obtener más detalles.
Importante
No se deben pasar datos sensibles (ni claves de API ni secretos, ni PII, PHI ni ningún dato de identificación personal) como argumentos.
steps[*].inputs.selectors(Opcional)Tipo: lista de mapas en formato
nameconexpression.Descripción:
- La entrada
selectorsle permite redefinir la salida para devolver solo los elementos especificados. - Se pueden emplear expresiones. Consulte la sección Cadenas de expresión para obtener más detalles.
- La entrada
Ejemplo:
- En el ejemplo dado, estamos obteniendo
timezoneydatetimecomo respuesta de la acción http.get.
name: calendar_demo
workflowInputs: timezone: type: String defaultValue: 'America/Los_Angeles' accountId: type: Int
steps: - name: getCurrentTime type: action action: http.get version: 1 inputs: url: 'https://worldtimeapi.org/api/timezone/${{ .workflowInputs.timezone }}' selectors: - name: timezone expression: '.responseBody | fromjson.abbreviation' - name: datetime expression: '.responseBody | fromjson.datetime'Bucle
Un bucle itera sobre colecciones (listas, mapas, arrays) y crea automáticamente las variables index y element para cada iteración. Estas variables de bucle son accesibles solo dentro del bucle usando ${{ .steps.<loopStepName>.loop.element }} o ${{ .steps.<loopStepName>.loop.index }}
Propiedades:
steps[*].for(Obligatorio)- Tipo: Constante
- Descripción: Señala el inicio de un bucle
steps[*].in(Obligatorio)- Tipo: Cadena (expresión)
- Descripción: Expresión que se evalúa como una colección de elementos
steps[*].steps(Obligatorio)- Descripción: Pasos ejecutados en cada iteración. Puede incluir cualquier tipo de paso, incluidos los bucles anidados.
Importante
- for: (requerido). Este es el elemento de nivel superior que indica el comienzo de un bucle for.
- in: (requerido). Para que la colección de entrada se itere, debe ser convertible a una matriz de Java.
- pasos: (requerido). En cada iteración se ejecutarán los pasos.
- elemento e índice se asignan automáticamente como parte del bucle.
indexes de base cero,elementpuede ser un tipo complejo si tiene una colección de elementos complejos.- Las variables creadas dentro del bucle (variables de bucle y salidas de paso) solo son accesibles dentro del bucle
- Estas variables se borran cuando el bucle sale y serán nulas si se accede a ellas fuera del bucle.
- Los bucles pueden acceder a variables definidas fuera del bucle.
Ejemplo: Bucle básico
name: myRangeIteratorsteps: - name: looper type: loop for: # iterate over [1..5] in: ${{ [range(1; 6)] }} steps: - name: logProgress type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "Element: ${{ .steps.looper.loop.element | tostring }}" # not exist outside of this loop attributes: # ranges over [0..4] index: ${{ .steps.looper.loop.index }}Ejemplo: Bucle en mapa
name: myMapIteratorsteps: - name: looper type: loop for: in: '${{ [ {"key1": "val1"}, {"key2": "val2"} ] }}' steps: - name: logProgress type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "Element: ${{ .steps.looper.loop.element | tostring }}"Ejemplo: Saltar dentro de un bucle
Se permite saltar entre pasos dentro del mismo bucle. No se permite saltar dentro/fuera de bucles, entre diferentes bucles o a bucles padre/hijo.
name: myLoopJumpsteps: - name: fistStep type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "the first step" - name: loopStep type: loop for: in: ${{ [range(1; 6)] }} steps: - name: loopStep1 type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "the loop first step" next: loopStep3 # Okay within the loop - name: loopStep2 type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "the loop second step, never executed" - name: loopStep3 type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "the loop third step" next: fistStep # Not okay, first step is not in the loop contextEjemplo: Break y continue
Utilice next: break o next: continue para controlar el flujo del bucle. Estas son palabras clave reservadas dentro de los bucles. Fuera de los bucles, saltan al final del flujo de trabajo. Nota: end se comporta como break dentro de los bucles.
name: myLoopContinueBreaksteps: - name: fistStep type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "the first step" - name: loopStep type: loop for: in: ${{ [range(1; 6)] }} steps: - name: loopStep1 type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "the loop first step" # continue with next iteration without executing loopStep2 next: continue - name: loopStep2 type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "the loop second step, never executed"
- name: loopAgain type: loop for: in: ${{ [range(1; 6)] }} steps: - name: loopAgainStep1 type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "the loop again first step" # stop iterating and continue with next step after the loop next: break - name: loopAgainStep2 type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "the loop again second step, never executed"
- name: lastStep type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "the last step"Cambiar
Un paso que comprueba varias condiciones y toma la primera rama que se evalúa como verdadera.
Un conmutador puede contener cualquier número de
conditionelementos en una lista. Comprobará las condiciones en orden y procesará la primera que evalúe como verdadera. Si ninguno se evalúa como verdadero, ejecutará su pasonextcomo se define ensteps[*].next.steps[*].switch(Obligatorio)- Tipo: matriz
- Descripción: Una matriz de casos switch, que especifica la lista ordenada de condiciones a evaluar.
steps[*].switch[*].condition(Obligatorio)- Tipo: Cadena (expresión)
- Descripción: El estado de la caja del interruptor. Si se evalúa como verdadero, se ejecutará el paso del caso
next. - Consulte la sección Cadenas de expresión para obtener más detalles.
steps[*].switch[*].next(Obligatorio)- Tipo: Cadena (conforme al patrón seguro para expresiones)
- Descripción: El nombre del paso a ejecutar si la condición del caso se evalúa como verdadera. La palabra clave especial
endse puede emplear para indicar que este paso debe ser el último en ejecutar.
- name: hasCompletedtype: switchswitch:- condition: ${{ .steps.waitForCompletion.outputs.automationExecutionStatus == "Failed" }}next: displayError- condition: ${{ .steps.waitForCompletion.outputs.automationExecutionStatus == "Success" }}next: displaySuccessnext: displayUnexpected
Esperar
Un paso que pausa la ejecución del flujo de trabajo durante una cantidad específica de segundos antes de continuar.
El paso de espera también puede escuchar una o más señales. Cada señal debe tener un siguiente paso correspondiente definido en una lista. Si se recibe una señal durante el periodo de espera, se procesará la primera señal recibida y el flujo de trabajo ejecutará el siguiente paso definido. Si no se recibe ninguna señal, el flujo de trabajo continúa normalmente una vez finalizado el periodo de espera.
El valor recibido de una señal se almacena en la salida del paso de espera y se puede emplear en pasos posteriores para lógica o procesamiento.
Ejemplo:
name: waitSignalExamplesteps: - name: waitStep type: wait seconds: 300 signals: [{name: 'mySignal', next: 'mySignalHandler'}] - name: endStep type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "didn't get signal" next: end - name: mySignalHandler type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: # log entry "got signal with data bar" when using signalInputs [{"foo": "bar"}] - message: "got signal with data ${{ .steps.waitStep.outputs.signalInputs.foo }}"steps[*].seconds(Obligatorio)- Tipo: Número
- Descripción: Número de segundos que se deben esperar antes de continuar con la ejecución del flujo de trabajo.
steps[*].signals- Tipo: matriz
- Descripción: Las señales que, al ser recibidas, desviarán el flujo del programa.
steps[*].signals[*].name- Tipo: Cadena
- Descripción: El nombre de la señal que se debe escuchar.
steps[*].signals[*].next- Tipo: Cadena
- Descripción: Paso a ejecutar si se recibe la señal especificada.
Asignar
Un paso que define variables para usar durante todo el flujo de trabajo. Este paso asigna valores a variables que pueden referenciar en pasos posteriores. Al definir todas las variables en un solo lugar, este tipo de paso hace que el flujo de trabajo sea más legible y optimizado.
Ejemplo de flujo de trabajo:
name: sampleWorkflowWithAssign
workflowInputs: initialValue: type: String defaultValue: "abcd" anotherValue: type: Int defaultValue: 1234
steps: - name: variableInitialization type: assign inputs: stringVar: "${{ .workflowInputs.initialValue }}" intVar: "${{ .workflowInputs.anotherValue }}" concatenationVar: "${{ .workflowInputs.initialValue }} - concatenated" booleanVar: true mapVar: key1: "value1" key2: "${{ .workflowInputs.initialValue }}" listVar: - "listItem1" - "${{ .workflowInputs.initialValue }}" - "${{ .workflowInputs.anotherValue }}"
- name: logVariables type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "stringVar: ${{ .steps.variableInitialization.outputs.stringVar }}" - message: "intVar: ${{ .steps.variableInitialization.outputs.intVar }}" - message: "concatenationVar: ${{ .steps.variableInitialization.outputs.concatenationVar }}" - message: "booleanVar: ${{ .steps.variableInitialization.outputs.booleanVar }}" - message: "mapVar: ${{ .steps.variableInitialization.outputs.mapVar | tojson }}" - message: "listVar: ${{ .steps.variableInitialization.outputs.listVar | tojson }}"steps[*].inputs(Obligatorio)- Tipo: Mapa de valores (incluye expresiones)
- Descripción:
- Las entradas son un mapa de nombres de variables y sus valores asignados. Cuando se asignan referencias secretas a variables, permanecen como referencias secretas y no se convierten a sus valores reales. Sin embargo, otras expresiones (como las entradas del flujo de trabajo) se evalúan y se convierten a sus valores reales.
- Tipos de entrada permitidos:
Integer,Double,Boolean,String,Array,Map
Ejemplo completo
Demostración del calendario
Un ejemplo completo de flujo de trabajo que demuestra múltiples funciones de flujo de trabajo, incluidas constantes de flujo de trabajo, selectores, pasos de espera, consultas NRDB e instrucciones switch.
name: calendar_demo
steps: - name: getUserCreated type: action action: newrelic.nerdgraph.execute version: 1 inputs: graphql: | { actor { user { id createdAt timeZoneName } } } selectors: - name: id expression: ".data.actor.user.id" - name: createdAt expression: ".data.actor.user.createdAt" - name: timeZoneName expression: ".data.actor.user.timeZoneName"
- name: getCreatedTime type: action action: utils.datetime.fromEpoch version: 1 inputs: timestamp: ${{ .steps.getUserCreated.outputs.createdAt }} pattern: "yyyy-MM-dd HH:mm:ss" timezoneId: ${{ .steps.getUserCreated.outputs.timeZoneName }} selectors: - name: datetime expression: ".datetime" - name: abbreviation expression: ".timezone.abbreviation"
- name: logTime type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "Demo ${{ .workflowConstants.runId }} userId ${{ .steps.getUserCreated.outputs.id }} created at ${{ .steps.getCreatedTime.outputs.datetime }} ${{ .steps.getCreatedTime.outputs.abbreviation }}"
- name: wait type: wait seconds: 1
- name: queryForLog type: action action: newrelic.nrdb.query version: 1 inputs: query: "FROM Log SELECT message, timestamp SINCE 5 minute ago WHERE message LIKE 'Demo ${{ .workflowConstants.runId }} userId ${{ .steps.getUserCreated.outputs.id }} created at%'"
- name: checkQuery type: switch switch: - condition: ${{ .steps.queryForLog.outputs.results | length > 0 }} next: postResultsMessage
- name: postWaitingMessage type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "Waiting for log message..." next: wait
- name: postResultsMessage type: action action: newrelic.ingest.sendLogs version: 1 inputs: logs: - message: "Found log message! ${{ .steps.queryForLog.outputs.results[0].message }}"Temas relacionados
Ejemplos de flujo de trabajo
Vea el esquema en acción con ejemplos de flujos de trabajo del mundo real
Crear definición de flujo de trabajo
Crea nuevas definiciones de flujos de trabajo usando la API de NerdGraph
Validar la definición del flujo de trabajo
Validar la sintaxis YAML del flujo de trabajo antes del despliegue
Catálogo de acciones
Explorar todas las acciones disponibles y sus esquemas de entrada/salida