В этом посте я собираюсь поработать над довольно простым вариантом использования. Во время выполнения конвейера развертывания FlexDeploy может создавать некоторые неавтоматизированные задачи, которые должны быть либо утверждены, либо отклонены. Например, кто-то должен одобрить развертывание в производственной среде. Это можно сделать либо в пользовательском интерфейсе FlexDeploy, либо с некоторыми внешними каналами связи. Сегодня я собираюсь сосредоточиться на сценарии, когда человеческая задача FlexDeploy одобрена / отклонена с помощью Slack :
Есть несколько требований и соображений, которые я хотел бы принять во внимание:
- Я не хочу учить FlexDeploy общаться со Slack
- Я не хочу предоставлять Slack подробности API FlexDeploy
- Я не хочу показывать FlexDeploy API публично
- Я хочу иметь возможность легко изменить Slack на что-то другое или добавить другие инструменты коммуникации, не касаясь FlexDeploy
По сути, я хочу отделить FlexDeploy от деталей механизма внешней связи. По этой причине я собираюсь представить дополнительный слой, API между FlexDeploy и Slack . Похоже, что серверная парадигма является очень привлекательным подходом для реализации этого API . Сегодня я собираюсь создать его с помощью функций Azure , потому что … почему бы и нет?
Таким образом, технически версия решения выглядит следующим образом:
Как только появляется новая человеческая задача, FlexDeploy уведомляет бессерверный API об этом, предоставляя внутренний идентификатор задачи и описание задачи. Существует функция SaveTask, которая сохраняет предоставленные сведения о задаче вместе с сгенерированным токеном (всего лишь uid) в хранилище Azure Table . Этот токен имеет время истечения, что означает, что его следует использовать до того времени, чтобы утвердить / отклонить задачу.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
const azure = require( 'azure-storage' ); const uuidv1 = require( 'uuid/v1' ); module.exports = async function (context, taskid) { var tableSvc = azure.createTableService( 'my_account' , 'my_key' ); var entGen = azure.TableUtilities.entityGenerator; var token = uuidv1(); var tokenEntity = { PartitionKey: entGen.String( 'tokens' ), RowKey: entGen.String(token), TaskId: entGen.String(taskid), dueDate: entGen.DateTime( new Date(Date.now() + 24 * 60 * 60 * 1000 )) }; tableSvc.insertEntity( 'tokens' ,tokenEntity, function (error, result, response) { }); return token; }; |
После сохранения токена вызывается функция PostToSlack, которая отправляет сообщение на канал Slack . Функции SaveTask и PostTo Slack объединены в долговременную функцию NotifyOnTask, которая фактически вызывается FlexDeploy:
1
2
3
4
5
6
7
|
const df = require( "durable-functions" ); module.exports = df.orchestrator(function*(context){ var task = context.df.getInput() var token = yield context.df.callActivity( "SaveTask" , task.taskid) return yield context.df.callActivity( "PostToSlack" , { "token" : token, "description" : task.description}) }); |
Сообщение в Slack содержит две кнопки для подтверждения и отклонения задачи.
Кнопки относятся к веб- зацепкам, указывающим на долговременную функцию ActionOnToken :
01
02
03
04
05
06
07
08
09
10
11
|
const df = require( "durable-functions" ); module.exports = df.orchestrator(function*(context){ var input = context.df.getInput() var taskId = yield context.df.callActivity( "GetTaskId" , input.token) if (input.action == 'approve' ) { yield context.df.callActivity( "ApproveTask" , taskId) } else if (input.action == 'reject' ) { yield context.df.callActivity( "RejectTask" , taskId) } }); |
ActionOnToken вызывает функцию GetTaskId, получая идентификатор задачи из хранилища по указанному токену:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
const azure = require( 'azure-storage' ); module.exports = async function (context, token) { var tableSvc = azure.createTableService( 'my_account' , 'my_key' ); function queryTaskID(token) { return new Promise(function (resolve, reject) { tableSvc.retrieveEntity( 'tokens' , 'tokens' , token, function (error, result, response) { if (error) { reject(error) } else { resolve(result) } }); }); } var tokenEntity = await queryTaskID(token); if (tokenEntity) { var dueDate = tokenEntity.dueDate._ if (dueDate > Date.now()) { return tokenEntity.TaskId._ } } }; |
Сделав это, он либо одобряет, либо отклоняет задачу, вызывая либо
Функции ApproveTask или RejectTask . Эти функции, в свою очередь, выполняют соответствующие вызовы FlexDeploy REST API.
01
02
03
04
05
06
07
08
09
10
|
const request = require( 'sync-request' ); module.exports = async function (context, taskid) { var taskid = taskid; var res = request( 'PUT' , fd_url+ '/flexdeploy/rest/v1/tasks/approval/approve/' +taskid,{ }); }; |
Я мог бы начать разработку своего безсерверного приложения прямо в облаке на
Портал Azure , но я решил все реализовать и поиграть с ним локально, а потом перейти к облаку. То, что я могу это делать, разрабатывать и тестировать свои функции локально, на самом деле очень круто, не каждая серверная платформа предоставляет вам такую возможность. Единственное, что я настроил в облаке, это
Учетная запись хранения Azure Table с таблицей для хранения моих токенов и сведений о задании.
Удобный способ начать работу с функциями Azure локально — использовать
Visual Studio Code как инструмент разработки. Я работаю на Mac, поэтому я скачал и установил версию для Mac OS X. VS Code посвящен расширениям, поскольку для каждой технологии, с которой вы работаете, вы устанавливаете одно или несколько расширений. То же самое относится и к функциям Azure. Для этого есть расширение:
Сделав это, вы получаете новую вкладку, где вы можете создать новое функциональное приложение и начать реализацию своих функций:
При настройке нового проекта мастер просит вас выбрать язык, на котором вы хотите реализовать функции:
Несмотря на то, что я люблю Java, я выбрал JavaScript, потому что помимо обычных функций я хотел реализовать долговременные функции, и они поддерживают C # ,
Только F # и JavaScript . На момент написания этого поста JavaScript был мне ближе всего.
Отдыхай как обычно. Вы создаете функции, пишете код, отлаживаете, тестируете, исправляете и все заново. Вы просто нажимаете F5 и VS Code запускает все приложение в режиме отладки для вас:
Когда вы запускаете приложение в первый раз, VS Code предложит вам установить исполняемые функции на ваш компьютер, если его там нет. Таким образом, в основном, предполагая, что у вас есть на вашем ноутбуке среда выполнения вашего предпочтительного языка (Node.js), вам просто нужно иметь VS Code с расширением функций, чтобы начать работать с функциями Azure . Он сделает все остальное за вас.
Итак, после запуска приложения я могу проверить его, вызвав функцию NotifyOnTask, которая запускает весь цикл:
1
|
curl -X POST --data '{"taskid":"8900","description":"DiPocket v.1.0.0.1 is about to be deployed to PROD"}' -H "Content-type: application/json" http: //localhost:7071/api/orchestrators/NotifyOnTask |
Исходный код приложения доступен на GitHub .
Что ж, общее мнение о функциях Azure до сих пор … это хорошо. Это просто работает. Я не сталкивался ни с одной раздражающей проблемой (пока) при реализации этого решения (за исключением некоторых глупых ошибок, которые я сделал, потому что я не читал руководство внимательно). Я определенно буду продолжать играть и публиковать в Azure Functions, чтобы обогатить и перенести это решение в облако и, возможно, реализовать что-то другое.
Это оно!
Опубликовано на Java Code Geeks с разрешения Евгения Федоренко, партнера нашей программы JCG . См. Оригинальную статью здесь: Бессерверный API с функциями Azure. Мнения, высказанные участниками Java Code Geeks, являются их собственными. |