Computação sem servidor baseada no OpenWhisk, parte 3


Este artigo continua a série de notas traduzidas sobre o OpenWhisk por Priti Desai . Hoje, veremos exemplos de implantação de funções Zip, dependências do GitHub e também descreveremos mais detalhadamente a sincronização de objetos entre o cliente e o servidor OpenWhisk.


Funções zip


O OpenWhisk suporta a criação de funções a partir de um único arquivo de origem, como foi mostrado anteriormente (). Ele também suporta a criação de uma função usando vários arquivos com código fonte e um conjunto de pacotes dos quais a função depende. Esse caso de uso para funções é chamado de função zip. Vamos tentar implantar uma função zip usando o wskdeploy .


Primeiro passo


Crie um arquivo de manifesto:


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

Acreditamos que o my-zip-action possui uma estrutura de diretório que contém o código fonte da função:


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

O conteúdo do arquivo 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; 

O conteúdo do arquivo 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 passo


Execute o npm install para instalar o formato de sequência:


 cd actions/my-action npm install --production 

Passo três


Expanda a função 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 a função zip my-zip-action com o módulo dependente string-format . Ao especificar um diretório no manifesto com a tecla de function , um arquivo compactado é criado nesse diretório e também uma função desse arquivo, portanto, você não precisa procurá-lo no sistema de arquivos. Após a implantação, você pode trabalhar com a nova função da mesma maneira que com outras funções.


Incluir e excluir arquivos em funções zip


O OpenWhisk permite criar uma função usando um arquivo zip contendo qualquer número de arquivos para a função, incluindo todos os seus vícios. A implantação suporta a especificação na function diretório com arquivos para a função funcionar. Um arquivo será criado a partir do conteúdo do diretório, a partir do qual a função já será implantada.


Inclusão de arquivo


Anteriormente, era possível especificar uma chave de include , que funciona da mesma maneira que a import em linguagens de programação, o que permitia, por exemplo, várias funções para referenciar a mesma biblioteca com 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 

Você pode ver o arquivo index.js no diretório greeting1 , bem como outro index.js no diretório greeting2 , e ambos se referem a utils.js localizado em common/ .


O conteúdo do arquivo index.js localizado em 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; 

O conteúdo do arquivo index.js localizado em 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 da chave include uma lista de arquivos ou diretórios que devem ser incluídos na função. Cada elemento desta lista deve ter source e \ ou destination , por exemplo:


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

Notas:


  • source contém o caminho relativo do diretório que contém manimanifest.yaml . destination implica o caminho relativo do diretório de funções, por exemplo, actions/greeting1 e actions/greeting2 no exemplo a seguir.
  • Se o destination não destination especificado, considera-se que será o mesmo que source .

O conteúdo do arquivo de manifesto:


 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 trabalhos com várias combinações de source e destination :


  • apenas source :

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

Com esta entrada, utils.js será copiado para actions/greeting/actions/common/utils.js , e index.js pode se referir a ela assim:


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

  • include na renomeação:

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

Com essa definição, utils.js será colocado no caminho actions/greeting/common/myUtils.js , e index.js se referirá a ela assim:


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

  • include outra maneira:

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

Nesse caso, utils.js serão copiados para actions/greeting/common/utility/utils.js , com um link de index.js :


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

  • include com o símbolo * :

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

Nesta versão, utils.js , juntamente com outros arquivos com a extensão .js , serão copiados para o diretório actions/greeting/common/ , e no index.js esses arquivos serão conectados assim:


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

Inclusão de diretório


Na include você pode especificar um diretório que será copiado recursivamente para o local especificado antes de ser incluído no arquivo morto. Por exemplo, 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 

O conteúdo de index.js no diretório 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; 

O conteúdo do arquivo de manifesto:


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

Neste exemplo, o diretório libs é copiado de forma totalmente recursiva para actions/greeting3/libs/ .


Conectando diretórios com o símbolo * :


  • exemplo 1:

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

Com isso, todos os subdiretórios que contêm utils.js serão copiados das libs . Os links do index.js ficarão assim:


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

  • exemplo 2:

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

Com essa entrada, todos os subdiretórios correspondentes à máscara e contendo utils.js serão copiados. O acesso a partir do index.js será assim:


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

  • exemplo 3:

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

Este exemplo indica explicitamente onde tudo será copiado. O acesso a partir do index.js será o mesmo do exemplo anterior.


Exceção


A palavra-chave exclude pode ser usada como uma lista de arquivos e diretórios; é permitido o uso de uma máscara na forma de um caractere * . Exemplo de uso:


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

Um exemplo comum de compartilhamento include e 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"] 

Funções com dependências do GitHub


O OpenWhisk suporta dependências, para que você possa descrever os outros pacotes OpenWhisk dos quais nosso projeto depende. Com essas dependências, o OpenWhisk também implementará automaticamente pacotes dependentes. Qualquer pacote com manifest.yaml e \ ou deployment.yaml pode ser considerado como um pacote dependente, que pode ser especificado no manifesto do nosso projeto. Você pode descrever essa dependência no manifesto na seção 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 

Neste exemplo, helloworlds é um pacote externo hospedado no repositório do GitHub em https://github.com/apache/incubator-openwhisk-test . O pacote helloworlds será implantado com base em seus arquivos para implantação no packages/helloworlds - quando você implantar nosso projeto RootProject . Também é possível alterar o nome do pacote dependente, por exemplo, em vez de helloworlds defina 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 

Você pode adicionar várias dependências a vários pacotes:


 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 

Como a sincronização de projetos OpenWhisk entre cliente e servidor


Para responder, você deve iniciar a implantação no modo de managed deployment . Nesse modo, o OpenWhisk implanta todos os objetos do manifesto e também anexa uma descrição oculta a cada um deles, o chamado managed . Essa descrição é assim:


 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 

Aqui, OpenWhisk é uma seqüência constante e "\ 0" é o caractere NULL. size_of_manifest_file e contents_of_manifest_file dependem do arquivo. A sequência de implantação do mesmo projeto no modo de managed deployment calcula um novo __OW_PROJECT_HASH no cliente para cada objeto e o compara com o objeto __OW_PROJECT_HASH do mesmo projeto no servidor. Existem várias opções abaixo.


Opção 1 : se __OW_PROJECT_HASH corresponder no cliente e no servidor, ou seja, se não houver alterações no projeto no lado do cliente, o projeto no servidor permanecerá como está, exceto para implantar novos objetos do manifesto por meio do wskdeploy para receber alterações no arquivo deployment.yaml .


Opção 2 : se __OW_PROJECT_HASH não corresponder, ou seja, se houver alterações no lado do cliente, o wskdeploy implementará todos os objetos do manifesto e os atualizará __OW_PROJECT_HASH no servidor. wskdeploy também wskdeploy todos os objetos: incluindo funções, sequências e __OW_PROJECT_NAME condicionais que possuem o mesmo __OW_PROJECT_NAME , ou seja, pertencentes ao mesmo projeto, mas com um __OW_PROJECT_HASH diferente, pois eles podem ser removidos do manifesto no cliente. O nome do projeto no manifesto é necessário para sincronizar o projeto entre o cliente e o servidor:


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

Os objetos no OpenWhisk que fazem parte do projeto, mas são implantados usando outras ferramentas ou ferramentas de automação permanecem inalterados quando são removidos do projeto. Eles são considerados objetos externos e, portanto, não são substituídos. Você pode wskdeploy esse projeto usando wskdeploy , direcionando-o para o arquivo de manifesto, que contém apenas o nome do projeto:


 project: name: MyProjectName 

Vejamos um exemplo de projeto para entender a managed deployment . Neste repositório, você pode ver o projeto com vários manifestos que mostram a managed deployment .


Primeiro passo


Implemente MyFirstManagedProject usando o modo de managed deployment :


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


Lista de objetos implantados em um servidor OpenWhisk



Descrição da propriedade


Segundo passo


Sincronizamos o cliente e o servidor - excluímos ManagedPackage-2:


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


Lista de objetos após a exclusão no MyFirstManagedProject


Passo três


Sincronizamos o cliente e o servidor - excluímos a sequência ManagedSequence-2:


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


Lista de objetos após exclusão


Quarto passo


Exclua a função Helloworld-3:


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


Lista de objetos após exclusão


Quinto passo


Excluir ManagedPackage-1:


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


Outros objetos no MyFirstManagedProject


Outros artigos do ciclo


Computação sem servidor baseada no OpenWhisk, parte 1
Computação sem servidor baseada no OpenWhisk, parte 2
Computação sem servidor baseada no OpenWhisk, parte 3
Computação sem servidor baseada no OpenWhisk, parte 4

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


All Articles