Computación sin servidor basada en OpenWhisk, parte 3


Este artículo continúa la serie de notas traducidas sobre OpenWhisk por Priti Desai . Hoy veremos ejemplos de implementación de funciones Zip, dependencias de GitHub, y también describiremos con más detalle la sincronización de objetos entre el cliente y el servidor OpenWhisk.


Funciones Zip


OpenWhisk admite la creación de funciones a partir de un único archivo fuente, como se mostró anteriormente (). También admite la creación de una función utilizando varios archivos con código fuente y un conjunto de paquetes de los que depende la función. Este caso de uso para funciones se llama función zip. Intentemos implementar una función zip usando wskdeploy .


Primer paso


Crea un archivo de manifiesto:


 packages: zipaction: actions: my-zip-action: function: actions/my-zip-action runtime: nodejs:6 inputs: name: Amy 

Creemos que my-zip-action tiene una estructura de directorio que contiene el código fuente de la función:


 $ ls actions/my-zip-action index.js package.json 

El contenido del archivo index.js :


 function helloworld(params) { var format = require('string-format'); var name = params.name || 'Stranger'; payload = format('Hello, {}!', name) return { message: payload }; } exports.main = helloworld; 

El contenido del archivo package.json :


 { "name": "my-zip-action", "description": "Node OpenWhisk zip action to demo Whisk Deploy", "license": "Apache-2.0", "version": "1.0.0", "main": "index.js", "dependencies": { "string-format": "0.5.0" } } 

Segundo paso


Ejecute npm install para instalar el formato de cadena:


 cd actions/my-action npm install --production 

Paso tres


Expande la función zip:


 ./wskdeploy -i -p actions/my-zip-action/ ____ ___ _ _ _ _ _ /\ \ / _ \ _ __ ___ _ __ | | | | |__ (_)___| | __ /\ /__\ \ | | | | '_ \ / _ \ '_ \| | | | '_ \| / __| |/ / / \____ \ / | |_| | |_) | __/ | | | |/\| | | | | \__ \ < \ \ / \/ \___/| .__/ \___|_| |_|__/\__|_| |_|_|___/_|\_\ \___\/ |_| Packages: Name: zipaction bindings: * action: my-zip-action bindings: - name: name value: Amy Do you really want to deploy this? (y/N): y Deployment completed successfully. 

Implementamos la función zip my-zip-action con el string-format módulo dependiente. Al especificar un directorio en el manifiesto con la tecla de function , se crea un archivo zip a partir de este directorio, y también una función de este archivo, por lo que no necesita buscarlo en el sistema de archivos. Después de la implementación, puede trabajar con la nueva función de la misma manera que con otras funciones.


Incluir y excluir archivos en funciones zip


OpenWhisk le permite crear una función utilizando un archivo zip que contiene cualquier número de archivos para la función, incluidos todas sus adicciones La implementación permite especificar en la function directorio con archivos para que la función funcione. Se creará un archivo a partir del contenido del directorio, desde el cual ya se implementará la función.


Inclusión de archivos


Anteriormente, era posible especificar una clave de include , que funciona de manera muy similar a la import en lenguajes de programación, lo que permitió, por ejemplo, varias funciones para hacer referencia a la misma biblioteca con código:


 $ cd actions/ $ ls -1 ./ common/ greeting1/ greeting2/ manifest.yaml $ ls -1 common/ utils.js $ ls -1 greeting1/ index.js package.json $ ls -1 greeting2/ index.js package.json 

Puede ver el archivo index.js en el directorio greeting1 , así como otro index.js en el directorio greeting2 , y ambos se refieren a utils.js ubicados en common/ .


El contenido del archivo index.js ubicado en actions/greeting1/ :


 /** * Return a simple greeting message for someone. * * @param name A person's name. * @param place Where the person is from. */ var common = require('./common/utils.js') function main(params) { var name = params.name || params.payload || 'stranger'; var place = params.place || 'somewhere'; var hello = common.hello || 'Good Morning'; return {payload: hello + ', ' + name + ' from ' + place + '!'}; } exports.main = main; 

El contenido del archivo index.js ubicado en actions/greeting2/ :


 /** * Return a simple greeting message for someone. * * @param name A person's name. * @param place Where the person is from. */ var common = require('./common/utils.js') function main(params) { var name = params.name || params.payload || 'stranger'; var place = params.place || 'somewhere'; var hello = common.hello || 'Good Evening'; return {payload: hello + ', ' + name + ' from ' + place + '!'}; } exports.main = main; 

Dentro de la tecla de include contiene una lista de archivos o directorios que deben incluirse en la función. Cada elemento de esta lista debe tener source y \ o destination , por ejemplo:


 include: - [source] - [source, destination] 

Notas:


  • source contiene la ruta relativa desde el directorio que contiene manimanifest.yaml . destination implica la ruta relativa desde el directorio de funciones, por ejemplo actions/greeting1 y actions/greeting2 en el siguiente ejemplo.
  • Si no se especifica el destination , se considera que será el mismo que el source .

El contenido del archivo de manifiesto:


 packages: zipactionwithinclude: actions: greeting1: function: actions/greeting1 runtime: nodejs:6 include: - ["actions/common/utils.js", "common/utils.js"] greeting2: function: actions/greeting2 runtime: nodejs:6 include: - ["actions/common/utils.js", "common/utils.js"] 

include trabajos con varias combinaciones de source y destination :


  • solo source :

 include: - [actions/common/utils.js] 

Con esta entrada, utils.js se copiará en actions/greeting/actions/common/utils.js , e index.js puede referirse a esto de la siguiente manera:


 var utils = require('./actions/common/utils.js') 

  • include con cambio de nombre:

 include: - ["actions/common/utils.js", "./common/myUtils.js"] 

Con esta definición, utils.js se colocará a lo largo de la ruta actions/greeting/common/myUtils.js , e index.js se referirá a esto de la siguiente manera:


 var utils = require('./common/myUtils.js') 

  • include de otra manera:

 include: - ["actions/common/utils.js", "./common/utility/utils.js"] 

En este caso, utils.js se copiará en actions/greeting/common/utility/utils.js , con un enlace desde index.js :


 var utils = require('./common/utility/utils.js') 

  • include con el símbolo * :

 include: - ["actions/common/*.js", "./common/"] 

En esta versión, utils.js junto con otros archivos con la extensión .js se copiarán en el directorio actions/greeting/common/ , y en index.js estos archivos se conectarán así:


 var utils = require('./common/utils.js') 

Inclusión de directorio


En include puede especificar un directorio que se copiará recursivamente en la ubicación especificada antes de ser incluido en el archivo. Por ejemplo, libs`` , index.js greeting3 / `` '':


 $ cd actions/ $ ls -1 libs/ greeting3/ manifest.yaml $ ls -1 libs/ lib1/ lib2/ lib3/ $ ls -1 libs/lib1/ utils.js $ ls -1 libs/lib2/ utils.js $ ls -1 libs/lib3/ utils.js $ ls -1 greeting3/ index.js package.json 

El contenido de index.js en el directorio actions/greeting3/ :


 /** * Return a simple greeting message for someone. * * @param name A person's name. * @param place Where the person is from. */ var lib1 = require('./libs/lib1/utils.js') var lib2 = require('./libs/lib2/utils.js') var lib3 = require('./libs/lib3/utils.js') function main(params) { var name = params.name || params.payload || 'stranger'; var place = params.place || 'somewhere'; var hello = lib1.hello || lib2.hello || lib3.hello || 'Hello'; return {payload: hello + ', ' + name + ' from ' + place + '!'}; } exports.main = main; 

El contenido del archivo de manifiesto:


 packages: zipactionwithinclude: actions: greeting3: function: actions/greeting3 runtime: nodejs:6 include: - ["actions/libs/*", "libs/"] 

En este ejemplo, el directorio libs se copia recursivamente por completo en actions/greeting3/libs/ .


Conectando directorios con el símbolo * :


  • ejemplo 1:

 include: - ["actions/libs/*/utils.js", "libs/"] 

Con esta escritura, todos los subdirectorios que contienen utils.js se copiarán de libs . Los enlaces de index.js se verán así:


 var lib1 = require('./libs/lib1/utils.js') var lib2 = require('./libs/lib2/utils.js') var lib3 = require('./libs/lib3/utils.js') 

  • ejemplo 2:

 include: - ["actions/*/*/utils.js"] 

Con esta entrada, se copiarán todos los subdirectorios que coincidan con la máscara y que contengan utils.js . El acceso desde index.js será así:


 var lib1 = require('./actions/libs/lib1/utils.js') var lib2 = require('./actions/libs/lib2/utils.js') var lib3 = require('./actions/libs/lib3/utils.js') 

  • ejemplo 3:

 include: - ["actions/*/*/utils.js", "actions/"] 

Este ejemplo indica explícitamente dónde se copiará todo. El acceso desde index.js será el mismo que en el ejemplo anterior.


Excepción


La palabra clave exclude se puede usar como una lista de archivos y directorios, se le permite usar una máscara en forma de carácter * . Ejemplo de uso:


 exclude: - actions/common/*.js - actions/libs/*/utils.js 

Un ejemplo común de compartir include y exclude :


 packages: zipactionwithexclude: actions: greeting1: function: actions runtime: nodejs:6 exclude: - actions/* include: - ["actions/common/utils.js", "common/utils.js"] - ["actions/index.js", "index.js"] - ["actions/package.json", "package.json"] 

Funciones con dependencias de GitHub


OpenWhisk admite dependencias, por lo que puede describir los otros paquetes de OpenWhisk de los que depende nuestro proyecto. Con estas dependencias, OpenWhisk también implementará automáticamente paquetes dependientes. Cualquier paquete con manifest.yaml y \ o deployment.yaml puede considerarse como un paquete dependiente, que puede especificarse en el manifiesto de nuestro proyecto. Puede describir dicha dependencia en el manifiesto en la sección de dependencies :


 packages: RootProject: dependencies: helloworlds: location: github.com/apache/incubator-openwhisk-test/packages/helloworlds triggers: trigger1: trigger2: rules: rule1: trigger: trigger1 action: helloworlds/hello-js rule2: trigger: trigger2 action: helloworlds/helloworld-js 

En este ejemplo, helloworlds es un paquete externo alojado en el repositorio de GitHub en https://github.com/apache/incubator-openwhisk-test . El paquete helloworlds se implementará en función de sus archivos para su implementación en el packages/helloworlds , cuando implemente nuestro proyecto RootProject . También es posible cambiar el nombre del paquete dependiente, por ejemplo, en lugar de helloworlds establezca ChildProject :


 packages: RootProject: dependencies: ChildProject: location: github.com/apache/incubator-openwhisk-test/packages/helloworlds triggers: trigger1: trigger2: rules: rule1: trigger: trigger1 action: ChildProject/hello-js rule2: trigger: trigger2 action: ChildProject/helloworld-js 

Puede agregar múltiples dependencias a múltiples paquetes:


 packages: RootProject: dependencies: ChildProject1: location: github.com/apache/incubator-openwhisk-test/packages/helloworlds ChildProject2: location: github.com/apache/incubator-openwhisk-test/packages/hellowhisk sequences: ChildProject1-series: actions: ChildProject1/hello-js, ChildProject1/helloworld-js ChildProject2-series: actions: ChildProject2/greeting, ChildProject2/httpGet triggers: trigger1: trigger2: rules: rule1: trigger: trigger1 action: ChildProject1-series rule2: trigger: trigger2 action: ChildProject2-series 

¿Cómo funciona la sincronización de proyectos OpenWhisk entre cliente y servidor?


Para responder, debe iniciar la implementación en modo de managed deployment . En este modo, OpenWhisk despliega todos los objetos del manifiesto y también adjunta una descripción oculta a cada uno de ellos, el llamado managed Esta descripción se ve así:


 managed: __OW_PROJECT_NAME: MyProjectName __OW_PROJECT_HASH: SHA1("OpenWhisk " + <size_of_manifest_file> + "\0" + <contents_of_manifest_file>) __OW_FILE: Absolute path of manifest file on file system 

Aquí, OpenWhisk es una cadena constante y "\ 0" es el carácter NULL. tamaño_de_archivo_manifiesto y contenido_de_archivo_manifiesto dependen del archivo. La secuencia de implementación del mismo proyecto en modo de managed deployment calcula un nuevo __OW_PROJECT_HASH en el cliente para cada objeto y lo compara con el objeto __OW_PROJECT_HASH del mismo proyecto en el servidor. Hay varias opciones a continuación.


Opción 1 : si __OW_PROJECT_HASH coincide en el cliente y el servidor, es decir si no hay cambios en el proyecto en el lado del cliente, entonces el proyecto en el servidor permanece como está, excepto para implementar a través de wskdeploy nuevos objetos desde el manifiesto para recibir cualquier cambio en el archivo wskdeploy .


Opción 2 : si __OW_PROJECT_HASH no coincide, es decir si hay cambios en el lado del cliente, wskdeploy implementa todos los objetos del manifiesto y luego los actualiza __OW_PROJECT_HASH en el servidor. wskdeploy también wskdeploy todos los objetos: incluyendo funciones, secuencias y __OW_PROJECT_NAME condicionales que tienen el mismo __OW_PROJECT_NAME , es decir. perteneciente al mismo proyecto pero con un __OW_PROJECT_HASH diferente, ya que podrían eliminarse del manifiesto en el cliente. El nombre del proyecto en el manifiesto es necesario para sincronizar el proyecto entre el cliente y el servidor:


 project: name: MyProjectName packages: package1: .... 

Los objetos en OpenWhisk que forman parte del proyecto pero que se implementan con otras herramientas o herramientas de automatización permanecen sin cambios cuando se eliminan del proyecto. Se consideran objetos externos y, por lo tanto, no se sobrescriben. Puede wskdeploy dicho proyecto utilizando wskdeploy , dirigiéndolo al archivo de manifiesto, que contiene solo el nombre del proyecto:


 project: name: MyProjectName 

Veamos un proyecto de muestra para comprender la managed deployment . En este repositorio, puede ver el proyecto con varios manifiestos que muestran la managed deployment .


Primer paso


Implemente MyFirstManagedProject usando el modo de managed deployment :


 $wskdeploy -m tests/src/integration/managed-deployment/manifest.yaml --managed Deployment completed successfully. 


Lista de objetos desplegados en un servidor OpenWhisk



Descripción de la propiedad


Segundo paso


Sincronizamos el cliente y el servidor; eliminamos ManagedPackage-2:


 ./wskdeploy -m tests/src/integration/managed-deployment/00-manifest-minus-second-package.yaml --managed Deployment completed successfully. 


Lista de objetos después de la eliminación en MyFirstManagedProject


Paso tres


Sincronizamos el cliente y el servidor; eliminamos la secuencia ManagedSequence-2:


 ./wskdeploy -m tests/src/integration/managed-deployment/01-manifest-minus-sequence-2.yaml --managed Deployment completed successfully. 


Lista de objetos después de la eliminación.


Cuarto paso


Eliminar la función Helloworld-3:


 ./wskdeploy -m tests/src/integration/managed-deployment/02-manifest-minus-action-3.yaml --managed Deployment completed successfully. 


Lista de objetos después de la eliminación.


Quinto paso


Eliminar ManagedPackage-1:


 ./wskdeploy -m tests/src/integration/managed-deployment/04-manifest-minus-package.yaml --managed Deployment completed successfully. 


Otros objetos en MyFirstManagedProject


Otros artículos de ciclo


Computación sin servidor basada en OpenWhisk, parte 1
Computación sin servidor basada en OpenWhisk, parte 2
Computación sin servidor basada en OpenWhisk, parte 3
Computación sin servidor basada en OpenWhisk, parte 4

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


All Articles