tag:blogger.com,1999:blog-28180969950447646272024-03-12T19:24:22.541-07:00Бедросова Юлияэтот блог посвящен задачам, с которыми сталкиваюсь в своей профессиональной деятельности...Unknownnoreply@blogger.comBlogger36125tag:blogger.com,1999:blog-2818096995044764627.post-40369183263712671332021-08-02T04:01:00.003-07:002021-08-02T04:01:48.935-07:00AWS EC2 как автоматизировать реакцию на инцидент безопасности<p>Существует стандартная рекомендованная практика реакции на инцидент безопасности для AWS EC2, которая подробно описана в <a href="https://d1.awsstatic.com/whitepapers/aws_security_incident_response.pdf" rel="noopener noreferrer" style="box-sizing: border-box; color: #007eb9; font-family: AmazonEmber, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; outline: 0px; text-decoration-line: none;" target="_blank">AWS Security Incident Response Guide</a>. Если пересказать коротко: если есть подозрения, что для данного инстанса EC2 произошел какой-либо инцидент безопасности, необходимо как можно быстрее выполнить следующие действия:</p><p>1) Изолировать инстанс - поместить его в карантинную группу безопасности, для которой закрыты все входящие порты, за исключением, например, 22го порта с определенных IP-адресов, чтобы системный администратор смог подключиться по ssh. Такая карантинная группа может существовать заранее или должна быть создана в ходе реакции на инцидент.<span></span></p><a name='more'></a><p></p><p>2) Необходимо сохранить текущее состояние инстанса: снять скриншот консоли, сохранить его в соответствующем S3-бакете, снять снапшоты жестких дисков.</p><p>3) Необходимо включить для инстанса защиту от удаления, если она не включена.</p><p>4) Пометить инстанс тегами, которые в последствии дадут понять, что этот инстанс на карантине и нуждается в дальнейшем исследовании - в расследовании инцидента.</p><p>5) Необходимо отправить сообщения ответственным лицам о том, что перечисленные мероприятия были проведены.</p><p>Конечно, если инстансов не много, то проделать 5 перечисленных пунктов руками - это дело 10 минут, но когда их сотни, как у моего клиента, необходима автоматизация данных действий.</p><p>В маркетплейсе AWS есть готовое решение для <a href="https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/new?stackName=DemoSecurityResponseInfrastructure&templateURL=https://awsiammedia.s3.amazonaws.com/public/sample/181_How_to_Automate_IR/MainTemplate.yaml" target="_blank">автоматизации реакции на инцидент безопасности</a>, но оно не устроило моего клиента по нескольким причинам, главная из которых в том, что это сложное и универсальное решение не учитывает конкретную специфику инфраструктуры клиента, регламентов именования и других маленьких нюансов, например, данное решение некорректно ведет себя со spot-инстансами, не применяет шифрование при сохранении данных в бакет. Так же клиенту хотелось, чтобы решение было оформлено в виде консольного скрипта, принимающего минимум параметров: чтобы обязательным параметром был только идентификатор инстанса.</p><p>Я не буду приводить здесь полный код моего решения на python и boto3, покажу только основную часть:</p><p><script src="https://gist.github.com/BedrosovaYulia/22cb4e254a1d46e758be901df9656454.js"></script><br /></p><p>А если вам необходимо автоматизировать реакцию на инциденты безопасности в вашем аккаунте AWS, обращайтесь.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-81767702098766388662020-08-24T06:26:00.009-07:002020-08-24T06:38:41.035-07:00Кейс: перенос локальной инфраструктуры клиента в облако AWS<p> <span style="font-family: Arial; font-size: 11pt; white-space: pre-wrap;">Компания Cyber Finance LTD - это компания из Южной Африки, которая занимается юридическим и брокерским обслуживанием. </span></p><span id="docs-internal-guid-6b7cd6f5-7fff-5a27-77cd-f95ae0ee0551"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">В связи с карантином 2020 руководство компании приняло решение перевести всех сотрудников компании на удаленную работу, закрыть офис за ненадобностью и перенести развернутую локально инфраструктуру в облако. Было выбрано облако AWS.<span></span></span></p><a name='more'></a></span><p></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Так выглядела инфраструктура компании:</span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-5c4M4ODuiqQ/X0PAVVrBp4I/AAAAAAAAGG0/5GfIXF3Nn3cxPsK4LQ2Vsubm3kS6JpYRgCLcBGAsYHQ/s1329/image_2020_08_13T06_04_05_666Z.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="685" data-original-width="1329" height="206" src="https://1.bp.blogspot.com/-5c4M4ODuiqQ/X0PAVVrBp4I/AAAAAAAAGG0/5GfIXF3Nn3cxPsK4LQ2Vsubm3kS6JpYRgCLcBGAsYHQ/w400-h206/image_2020_08_13T06_04_05_666Z.png" width="400" /></a></div><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">1) Террабайт данных на файловом сервере (Clear OS)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">2) Внутренний портал для управления задачами и CRM система Битрикс24, 600Г пользовательских файлов, база данных на том же сервере, что и приложение, занимала около 25Г. К внутреннему порталу были подключены диски файлового сервера, была интегрирована офисная АТС (Астериск).</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">3) Сервер Астериск - офисная АТС. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Клиент обозначил, что мы можем ни в чем себе не отказывать в рамках 200$ в месяц. Уложиться в данный бюджет было сложно, потому что по нашим изначальным расчетам необходимо хотя бы 400$ в месяц, а лучше 500$ (датацентр в Кейптауне открыт недавно, и цены в нем намного выше, чем, в Вирджинии, для многих сервисов не доступны маленькие EC2 инстансы). В этом посте я расскажу подробно, как мне удалось решить задачи клиента и уложиться в бюджет, не в ущерб производительности системы.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Для начала необходимо было определить план переезда, потому что он должен был быть бесшовным - без простоя работы пользователей. К счастью, сотрудники в данной компании не работают на выходных, и в это время мы могли приостанавливать любые сервера. </span></p><ol style="margin-bottom: 0px; margin-top: 0px;"><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Первым этапом в ночь с пятницы на понедельник мы провели предварительный тест: развернули предполагаемые ресурсы:</span></p></li></ol><div><br /></div><a href="https://1.bp.blogspot.com/-7gnorbuKyVM/X0PBAptGAjI/AAAAAAAAGG8/Uzhxawfd1cwx_3IdlWL99RMQ5GX09gGVgCLcBGAsYHQ/s1760/AWS%2Bfor%2BBitrix24%2Bwith%2BAsterisk.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1360" data-original-width="1760" height="309" src="https://1.bp.blogspot.com/-7gnorbuKyVM/X0PBAptGAjI/AAAAAAAAGG8/Uzhxawfd1cwx_3IdlWL99RMQ5GX09gGVgCLcBGAsYHQ/w400-h309/AWS%2Bfor%2BBitrix24%2Bwith%2BAsterisk.png" width="400" /></a><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><ul style="margin-bottom: 0px; margin-top: 0px;"><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; margin-left: 36pt; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">EC2 для Битрикс24;</span></p></li><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; margin-left: 36pt; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">EC2 для Астериска;</span></p></li><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; margin-left: 36pt; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">S3 для файлов папки upload Битрикс24;</span></p></li><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; margin-left: 36pt; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RDS для БД Битрикс24;</span></p></li><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; margin-left: 36pt; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Auto Scaling групп на 1 инстанс для автоматического восстановления сервера Битрикс24 в случае падения.</span><span style="font-size: 11pt; white-space: pre-wrap;"> </span></p></li></ul><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Далее мы перенесли все в тестовом режиме (не забирая все файлы, и взяв только срез по 3000 записей из каждой таблицы БД), чтобы понять, в каком порядке нужно действовать и сколько времени потенциально может занимать каждый этап. Той же ночью все входящие на старый Астериск транки были отключены, подключены на новый Астериск - чтобы убедиться, что провайдеры телефонии не блокируют ip-адрес нового Астериска, к понедельнику транки снова были подключены на старом Астериске.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Основная проблема, которая вскрылась в ходе тестового переезда, заключалась в том, что RDS с 5м Mysql в Кейптауне никак не вписывалась в бюджет (даже в минимальной конфигурации) из-за отсутствия в регионе возможности взять маленький инстанс. Были проработаны несколько вариантов:</span></p><ul style="margin-bottom: 0px; margin-top: 0px;"><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; margin-left: 36pt; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">использовать 8й Mysql;</span></p></li><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; margin-left: 36pt; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">разместить базу данных в другом регионе (оказалось запрещено законом);</span></p></li><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; margin-left: 36pt; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">разместить базу данных на MySql совместимой БД Aurora Serverless (такой вариант оказался недоступным для региона);</span></p></li><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; margin-left: 36pt; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">разместить базу данных на одном инстансе с приложением Битрикс24, взяв инстанс помощнее и EBS-оптимизированный;</span></p></li></ul><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Было перепробовано несколько вариантов RDS инстансов с MySQL 8, которые позволяли вписаться в бюджет: t3.small, t3.medium, t3.large, но ни один из них не давал требуемой производительности (получалось 11-18 попугаев) из-за низкого IOPS на маленьком 100G SSD. Даже замена диска на Provision 1000 IOPS 100Г не дала результата, а диск большего размера, который разгонялся бы до больших IOPS уже не вписывался в бюджет.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Поэтому было принято решение разместить базу данных на одном инстансе с приложением Битрикс24, взяв EBS-оптимизированный инстанс m5d.large, отказавшись при этом от Auto Scaling Group (отказавшись от автоматического восстановления сервера после возможного сбоя) и отказавшись от возможности увеличивать размер жесткого диска автоматически. Производительность же получилась даже выше требуемой (60-70 попугаев)</span></p><br /><ol start="2" style="margin-bottom: 0px; margin-top: 0px;"><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">В понедельник, поняв, что в бюджет, в принципе, можно уложиться, мы включили синхронизацию файлов внутреннего портала Битрикс24 с S3 бакетом в облаке. Битрикс24 поддерживает хранение пользовательских файлов в S3 бакете, поэтому мы включили синхронизацию новых загружаемых файлов его средствами, а старые файлы синхронизировали через консоль ssh командой aws s3 sync. Для этого на старый сервер приложения был установлен aws cli. Средствами Битрикс файлы переносились в облако со скоростью 1G в час, из консоли получалось 4-5G в час. В последствии на таблице файлов b_file был выполнен запрос, помечающий флаг, что файлы должны тянуться из соответсвующего бакета.</span></p></li></ol><br /><ol start="3" style="margin-bottom: 0px; margin-top: 0px;"><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">В середине недели телефония старого Битрикс24 и все софтфоны были переключены на новый Астериск.</span></p></li></ol><br /><ol start="4" style="margin-bottom: 0px; margin-top: 0px;"><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">В следующую ночь с пятницы на понедельник, когда почти все файлы папки upload строго Битрикс24 уже были синхронизированы с S3 бакетом, мы закрыли доступ пользователям к старому Битрикс24, сняли бекап с базы данных и перенесли ее в облако, новый Битрикс24 был подключен к новому Астериску, общие диски для хранения файлов все еще подтягивались со старого файлового сервера, когда пользователи начали использовать Битрикс24, установленный в облаке AWS. Со старого сервера Битрикс24 еще продолжали загружаться файлы.</span></p></li></ol><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p><ol start="5" style="margin-bottom: 0px; margin-top: 0px;"><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Последним этапом были синхронизированы нужные файлы с файлового сервера.</span></p></li></ol><br /><ol start="6" style="margin-bottom: 0px; margin-top: 0px;"><li dir="ltr" style="font-family: arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Далее были настроены автоматические снапшоты серверов с использованием AWS EC2 Lifecycle Manager, межрегиональная репликация файлового хранилища S3, настроены уведомления об использовании ежемесячного запланированного бюджета и о доступности/здоровье развернутых ресурсов.</span></p></li></ol><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Первоначально в попытке вписать в бюджет базу данных на RDS, планировалось распределить 200$ следующим образом (но 200$ слишком мало для подобной архитектуры): </span><a href="https://calculator.aws/#/estimate?id=2b7e505cf75079271bbec60bf1c0a6d1a4b21e27" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">https://calculator.aws/#/estimate?id=2b7e505cf75079271bbec60bf1c0a6d1a4b21e27</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">В итоге пришлось перераспределить 200$ так, получив отличную производительность, но отказавшись от возможности автоматического восстановления и автоматического масштабирования:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://calculator.aws/#/estimate?id=d80de3b1271a238c42cc2bd428511766f717f648" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">https://calculator.aws/#/estimate?id=d80de3b1271a238c42cc2bd428511766f717f648</span></a></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">А вот такой вариант мы предложим тому клиенту, для которого великолепная производительность, высочайшая надежность, автоматическое масштабирование, автоматическое восстановление - все сразу и одновременно - важнее цены: </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://calculator.aws/#/estimate?id=891fde270ac1854a8ca0d229171fb52cb10b9f73" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">https://calculator.aws/#/estimate?id=891fde270ac1854a8ca0d229171fb52cb10b9f73</span></a></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(первичная передача данных в AWS не включена в данные калькуляции)</span></p><div class="separator" style="clear: both; text-align: center;"><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-37506913909237109022020-06-12T04:09:00.003-07:002020-06-12T04:09:26.084-07:00AWS Certified Cloud Practitioner - как я получила этот сертификатВчера я сдала экзамен и получила сертификат AWS Certified Cloud Practitioner<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-qliKO4AjedM/XuNhlXO3pWI/AAAAAAAAGDM/gTxdLAprXkMBWS_9pxUJ_3z_AYsXpWmWQCLcBGAsYHQ/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2020-06-12%2B%25D0%25B2%2B12.37.53.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1236" data-original-width="1600" height="308" src="https://1.bp.blogspot.com/-qliKO4AjedM/XuNhlXO3pWI/AAAAAAAAGDM/gTxdLAprXkMBWS_9pxUJ_3z_AYsXpWmWQCLcBGAsYHQ/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2020-06-12%2B%25D0%25B2%2B12.37.53.png" width="400" /></a></div>
<br />
<br />
<a href="https://www.certmetrics.com/amazon/public/badge.aspx?i=9&t=c&d=2020-06-11&ci=AWS01004120" target="_blank">https://www.certmetrics.com/amazon/public/badge.aspx?i=9&t=c&d=2020-06-11&ci=AWS01004120</a><br />
<br />
Это было довольно сложно, не только потому, что экзамен проводится на английском языке, но и из-за сложной процедуры сдачи экзамена, своими впечатлениями я поделилась в видео:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/02tR4HLx2vk/0.jpg" src="https://www.youtube.com/embed/02tR4HLx2vk?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Я была довольно вымотана после экзамена, и не выгляжу радостной, но все равно решила записать видео сразу - пока свежи впечатления.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-66287164787825034912020-05-31T23:08:00.002-07:002020-05-31T23:08:22.156-07:00Настройка почты через biz.mail.ru в БитриксВМНедавно настраивая отправку почты в БитриксВМ через ящик домена, который хостится на biz.mail.ru согласно официальной инструкции <a href="https://dev.1c-bitrix.ru/learning/course/?COURSE_ID=37&LESSON_ID=2946">https://dev.1c-bitrix.ru/learning/course/?COURSE_ID=37&LESSON_ID=2946</a>, я столкнулась с проблемой, что письма не уходят с сервера.<br />
<br />
Зайдя в лог по адресу: /home/bitrix/msmtp_default.log я увидела там ошибку:<br />
<br />
errormsg='the server sent an empty reply' exitcode=EX_PROTOCOL<br />
<br />
<a name='more'></a><br /><br />
Эта ошибка решилась исправлением конфига, находящегося по адресу /home/bitrix/.msmtprc<br />
<br />
host smtp.mail.ru<br />
port 465<br />
from test@bedrosova.ru<br />
keepbcc off<br />
auth on<br />
user test@bedrosova.ru<br />
password **********<br />
tls on<br />
<b>tls_starttls off</b><br />
tls_certcheck off<br />
<br />
А именно вместо tls_starttls on нужно было поставить tls_starttls off<br />
<br />
После этого в логе появилась другая ошибка:<br />
<br />
Message was not accepted -- it contains invalid headers. More specially, ?From:? header must match user you are sending mail from. See http://help.mail.ru/mail-help/mailer/popsmtp for details.' errormsg='the server did not accept the mail' exitcode=EX_UNAVAILABLE<br />
<br />
Для исправления этой ошибки в Битрикс24 в настройках главного модуля в поле E-mail администратора нужно было вставить тот же самый емейл test@bedrosova.ru, который я использовала для настройки почты в БитриксВМ.Unknownnoreply@blogger.com11tag:blogger.com,1999:blog-2818096995044764627.post-47237686082141025062020-05-03T06:52:00.004-07:002020-05-03T07:42:13.675-07:00AWS S3 - Лучшие практики<b>Производительность</b><br />
<br />
<div>
<b>Одновременная обработка нескольких PUT/GET</b><br />
<br />
S3 масштабируется для поддержки высокой интенсивности запросов. Если частота запросов постоянно растет, S3 автоматически разбивает корзины на части по мере необходимости для поддержки возрастающей интенсивности запросов.<br />
<br />
S3 может обрабатывать не менее 3500 запросов PUT / COPY / POST / DELETE и 5500 запросов GET / HEAD в секунду на каждый префикс в корзине.<br />
GET-интенсивные рабочие нагрузки<br />
<a name='more'></a><br />
Для оптимизации производительности S3 используют <b>Cloudfront</b>, он позволяет:<br />
<br />
- снижать латентность передачи данных и повышать скорость передачи данных;<br />
- кешировать контент и тем самым уменьшать количество запросов непосредственно к S3;<br />
- предоставлять несколько конечных точек доступа (периферийных местоположений) для доступности данных;<br />
- поддерживать 2 варианта дистрибьюции данных: Web и RTMP.<br />
<br />
Чтобы ускорить передачу данных на большие расстояния между клиентом и корзиной S3, используйте <b>Amazon S3 Transfer Acceleration</b>. Transfer Acceleration использует глобально распределенные периферийные местоположения в CloudFront для ускорения передачи данных на географические расстояния.</div>
<div>
<b>PUT/GET-запросы для больших объектов</b><br />
AWS позволяет распараллеливать запрос PUT/GET для повышения производительности загрузки и скачивания данных, а также для возможности восстановления данных в случае сбоя.<br />
<br />
<b>Для PUT-запроса, загрузка объекта по частям</b> (<b>Multipart upload</b>) может помочь ускорить загрузку данных за счет того, что:<br />
<br />
- несколько частей объекта могут загружаться одновременно и максимально использовать пропускную способность сети;<br />
- при сбое в загрузке части объекта, должна быть перезагружена только одна эта часть, а не весь объект;<br />
- появляется возможность приостановить и возобновить загрузку;<br />
- загрузка может быть начата еще до того, как станет известен полный размер объекта;<br />
<br />
<b>Для GET-запроса Range http header </b>помогает ускорить скачивание<b>:</b><br />
- позволяя получить объект по частям вместо всего объекта сразу;<br />
- быстро восстанавливая скачивание после сбоев, поскольку необходимо повторить попытку только той части, которую не удалось скачать.<br />
<br />
<b> Операции над списком объектов</b><br />
В индексах Amazon S3 имена ключей объектов хранятся лексикографически, что затрудняет сортировку и управление содержимым списка.<br />
<br />
S3 поддерживает только один индекс списка объектов, и он отсортирован в лексикографическом порядке.<br />
<br />
Если необходим другой индекс списка объектов S3, можно построить и поддерживать его за пределами S3, например, в DynamoDB или в RDS. Это позволит индексировать метаданные объектов и осуществлять поиск по ним, не выполняя лишних запросов непосредственно к S3. <br />
<br />
<b> Безопасность</b><br />
<br />
Использование версионности объектов:<br />
<br />
- может использоваться для защиты от непреднамеренных перезаписей и удалений объектов;<br />
- позволяет получать и восстанавливать удаленные объекты или выполнять откат к предыдущим версиям;<br />
Усильте безопасность, настроив корзину для использования MFA (мультифакторной авторизации) при удалении корзины.<br />
Включение версионности для корзины не препятствует ее удалению, поэтому необходимо осуществлять регулярное резервное копирование на случай случайного или злонамеренного удаления данных.<br />
Используйте Cross Region replication (межрегиональную репликацию) для резервного копирования данных в другой регион.<br />
<br />
При использовании S3 внутри VPC, используйте для доступа к S3 из VPS только конечные точки S3, так как они горизонтально масштабируемы, избыточны, высокодоступны и помогают установить приватное соединение между VPC и S3 - трафик никогда не покидает сеть. <br />
<br />
<b> Стоимость</b><br />
<br />
Оптимизировать стоимость хранения данных в S3 можно, выбрав соответствующий класс хранения для объектов.<br />
Сконфигурируйте соответствующие правила управления жизненным циклом, чтобы перемещать объекты в разные классы хранения на определенных этапах их жизни.<br />
<br />
<b> Отслеживание</b><br />
<br />
Используйте <b>Event Notifications</b> (уведомления о событиях), чтобы получать уведомления о любых запросах на установку или удаление объектов S3.<br />
<br />
Используйте <b>CloudTrail</b>, который позволяет записывать вызовы определенных API, обращающихся к S3 из учетной записи AWS, и сохраняет лог-файлы в корзину S3.<br />
<br />
Используйте <b>CloudWatch</b> для мониторинга корзин Amazon S3, отслеживания метрик, таких как количество хранимых объектов и их размер.<br />
<br />
<b>Задачи:</b><br />
<br />
1) Медиа-компания ежедневно создает новые видеофайлы с общим размером около 100 ГБ после сжатия. Каждый файл имееет размер 1-2ГБ. Все файлы должны загружаться в Amazon S3 каждую ночь в фиксированное временное окно между 3 и 5 часами утра. Сейчас их загрузка занимает почти 3 часа, хотя используется менее половины доступной полосы пропускания сети. Как обеспечить возможность загрузки файлов в отведенное время?<br />
<br />
Ответ: загрузить файлы на S3 параллельно, используя <b>Multipart upload.</b><br />
<b><br /></b>
2) Вы разрабатываете веб-приложение, которое хранит статические ресурсы в корзине S3. Вы ожидаете, что корзине будет поступать более 150 PUT-запросов в секунду. Что вы должны сделать, чтобы обеспечить оптимальную производительность?</div>
<div>
<br />
Ответ: необходимо добавить случайный префикс к именам ключей.<br />
<br />
3) У вас есть приложение, работающее на экземпляре Amazon Elastic Compute Cloud (AWS EC2), которое загружает 5 ГБ видеообъектов в Amazon Simple Storage Service (S3). Загрузка видео занимает больше времени, чем ожидалось, что приводит к снижению производительности приложения. Какой метод поможет улучшить производительность вашего приложения?<br />
<br />
Ответ: использовать <b>Multipart upload.</b></div>
<div>
<b><br /></b></div>
<div>
4) Как обеспечить защиту от случайной потери данных, хранящихся в Amazon S3?</div>
<div>
<br />
Ответ: Установить политики корзины, чтобы ограничить удаление, включить управление версиями, создать резервную копию своего хранилища S3 в хранилище, принадлежащем другой учетной записи AWS, для обеспечения избыточности.</div>
<div>
<br /></div>
<div>
5) Стартап-компания наняла вас, чтобы помочь им создать мобильное приложение, которое в конечном итоге будет хранить миллиарды изображений и видео в Amazon S3. Компания хочет минимизировать эксплуатационные расходы и они ожидают удвоения числа установок своего приложения каждые шесть месяцев. Из-за специфики их бизнеса они ожидают внезапного и значительного увеличения трафика к и от S3, и вы должны гарантировать, что сервис S3 может удовлетворить требования производительности их приложения. Какую другую информацию вы должны получить от этого клиента, чтобы определить, является ли S3 правильным вариантом?<br />
<br />
Ответ: Узнать общее количество запросов в секунду при пиковом использовании.<br />
<br />
6) Компания, занимающаяся хранением документов, развертывает свое приложение в AWS и меняет свою бизнес-модель для поддержки пользователей как бесплатного, так и премиум-уровня. Пользователям премиум-уровня будет разрешено хранить до 200 ГБ данных, а клиентам бесплатного уровня - только 5 ГБ. Заказчик ожидает, что миллиарды файлов будут сохранены. Все пользователи должны получать оповещения, в первый раз когда приближается к 75-процентному использованию квоты и еще раз, когда приближаются к 90-процентному использованию квоты. Каким реализовать эти оповещнения?<br />
<br />
Ответ: необходимо создать <b>Activity Worker</b> в сервисе A<b>mazon Simple Workflow.</b> Activity worker будет обновлять счетчик данных пользователей в базе данных Amazon Dynamo и использовать <b>Simple Email Service</b> для отправки электронного письма, если значение счетчика превысит соответствующие пороговые значения.<br />
<br />
7) У вашей компании есть веб-сайт с социальной сетью для хранения и обмена документами. Веб-приложение позволяет пользователям загружать большие файлы, возобновляя и приостанавливая загрузку по мере необходимости. В настоящее время файлы загружаются на ваш php-интерфейс при поддержке Elastic Load Balancing и автомасштабируемого парка экземпляров (EC2), который масштабируются в зависимости от среднего количества полученных байтов (NetworkIn). После загрузки файла он копируется в сервис Amazon Amazing Simple Storage (S3). Экземпляры Amazon EС2 используют роль AWS Identity and Access Management (AMI), которая позволяет загружать данные на Amazon S3. За последние шесть месяцев ваша пользовательская база и масштаб значительно увеличились, что заставило вас увеличить параметр Max для групп автоматического масштабирования в несколько раз. Ваш финансовый директор обеспокоен ростом затрат и попросил вас изменить архитектуру там, где это необходимо, для лучшей оптимизации затрат. Какое изменение архитектуры вы могли бы ввести, чтобы снизить стоимость, и при этом сохранить веб-приложение безопасным и масштабируемым?<br />
<br />
Ответ: Перепроектируйте свой механизм загрузки, сделайте так, чтобы приложение проходило аутентификацию у вашего провайдера идентификации как у посредника, и получало временные учетные данные AWS из службы токенов AWS Secure (GetFederation Token). Безопасно передайте учетные данные и конечную точку/префикс S3 в ваше приложение. </div>
<div>
Внедрите в приложение кастомную логику, использующую <b>Multipart upload </b>API для прямой загрузки файла в Amazon S3 с использованием указанных учетных данных и префикса.<br />
<br />
8) Если приложение хранит почасовые журнальные файлы из тысяч экземпляров с веб-сайта с высоким трафиком, какая схема именования даст оптимальную производительность на S3?<br />
<br />
Ответ: HH-DD-MM-YYYY-log_instanceID (HH даст больший разброс префиксов, чем если начинать наименование с идентификатора инстанса или с года).</div>
<div>
<br />
<br />
Данный пост - это мой адаптированный перевод, который я сделала для подготовки своей команды к серфикации по AWS. Оригинал на английском: <a href="https://jayendrapatil.com/aws-s3-best-practices/">https://jayendrapatil.com/aws-s3-best-practices/</a><br />
<br /></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-90415866304889602002019-08-26T13:06:00.000-07:002019-08-26T13:19:44.763-07:00AWS Config - кастомные правила для автоматизации работы системного администратораСервис AWS Config предназначен для оценки и аудита конфигурации ресурсов AWS. AWS Config ведет непрерывный мониторинг конфигурации ресурсов AWS и фиксирует результаты. Сервис позволяет автоматизировать сопоставление записанных и требуемых конфигураций и оценку соответствия. <br />
<br />
Что это означает на практике? Расскажу о своем недавнем кейсе. <br />
<br />
Ко мне обратился клиент, использующий сервис AWS Secrets Manager для хранения API ключей и токенов OAuth. Ключей и токенов было очень много (несколько сотен). <br />
<br />
Они были разного типа, и их ротация (обновление) осуществлялась с использованием различных AWS Lambda функций. Администраторам было сложно вручную отслеживать, все ли в системе работает корректно, нет ли ключей, которые по какой-то причине не обновлены в течение заданного промежутка времени. К примеру, если кто-то внесет изменение в функцию, отвечающую за ротацию ключа, он перестанет обновляться, и этого не будет видно.<br />
<br />
Передо мной встала задача создания 2х кастомных правил AWS Config:<br />
<a name='more'></a><br />
1) Дата последнего обновления любого ключа AWS Secrets Manager должна быть не старше, чем 90 дней назад.<br />
<br />
2) Не должно быть Secrets, для которых не задана функция ротации, и в настройках автоматического выполнения функции ротации должен стоять период ротации менее 90 дней.<br />
<br />
Для создания и проверки выполнения данных правил в системе мне понадобилось создать 2 AWS Lambda функции с доступом к AWS Config, AWS Secrets Manager и CloudWatch (для логирования).<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-vIFqNbbEYNw/XWOKijexrmI/AAAAAAAAF20/kWc9zcryF_oP4t6B-yRc9wb5iSwg6oamQCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-08-26%2B%25D0%25B2%2B10.14.09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="602" data-original-width="1600" height="150" src="https://1.bp.blogspot.com/-vIFqNbbEYNw/XWOKijexrmI/AAAAAAAAF20/kWc9zcryF_oP4t6B-yRc9wb5iSwg6oamQCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-08-26%2B%25D0%25B2%2B10.14.09.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Далее я создала сами правила AWS Config, подключив в каждом из них соответствующую Lambda-функцию для проверки и указав периодичность проверки:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-D7kAV0trpr8/XWQ-F3BD6ZI/AAAAAAAAF3c/wX5LHeEGNgonJRZjyJVpeWBzhQpl72LkQCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-08-26%2B%25D0%25B2%2B22.22.09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1077" data-original-width="1600" height="268" src="https://1.bp.blogspot.com/-D7kAV0trpr8/XWQ-F3BD6ZI/AAAAAAAAF3c/wX5LHeEGNgonJRZjyJVpeWBzhQpl72LkQCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-08-26%2B%25D0%25B2%2B22.22.09.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Чтобы запрограммировать логику проверки правила в AWS Lambda функции, нужно проработать несколько моментов:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
1) Мы ожидаем, что обращаться к функции будет только сервис AWS Config, и это нужно проверять при запуске функции. Источник обращения передается в функцию в переменной event. Для тестирования в ходе написания Lambda-обработчика конфигурационного правила можно использовать следующий шаблон:</div>
<div class="separator" style="clear: both; text-align: left;">
<script src="https://gist.github.com/BedrosovaYulia/0c63d7c74136991689af9a839ea7028c.js"></script><br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
2) После проверки источника запроса (код проверки, как и другие скучные моменты я не привожу в данном посте) необходимо получить необходимые данные - в данном кейсе это настройки Secrets. Для доступа к ресурcам AWS используется python библиотека boto3. Получить данные, необходимые для проверки - очень просто:</div>
<div class="separator" style="clear: both; text-align: left;">
<script src="https://gist.github.com/BedrosovaYulia/16e5d813b394b5e13322517dfda7b85e.js"></script><br /></div>
<div class="separator" style="clear: both; text-align: left;">
3) Анализируем полученные данные на соответствие заданным правилам и готовим ответ:</div>
<div class="separator" style="clear: both; text-align: left;">
<script src="https://gist.github.com/BedrosovaYulia/96f8662653c8fc5fe235bd5d8126df73.js"></script><br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
4) После того, как ответ подготовлен, его нужно отправить обратно запросившему его правилу AWS Config: </div>
<div class="separator" style="clear: both; text-align: left;">
<script src="https://gist.github.com/BedrosovaYulia/cc47a3118dab42f801fdbd82c226e6ea.js"></script><br /></div>
Здесь answer["type"] может принимать 2 значения: COMPLIANT, если правило выполняется или NON_COMPLIANT, если правило не выполняется.<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Если какое-то из правил не выполняется, это сразу видно в дашборде AWS Config:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-WkouB_ceZEU/XWQwz-H9JBI/AAAAAAAAF3A/T8FpRBlu1JwbFaQYeTtvVANCWVslfQyVACLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-08-26%2B%25D0%25B2%2B22.19.04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="806" data-original-width="1426" height="225" src="https://1.bp.blogspot.com/-WkouB_ceZEU/XWQwz-H9JBI/AAAAAAAAF3A/T8FpRBlu1JwbFaQYeTtvVANCWVslfQyVACLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-08-26%2B%25D0%25B2%2B22.19.04.png" width="400" /></a></div>
<br />
Можно перейти в подробности и посмотреть, для какого конкретного Secret не выполняется правило:<br />
<br />
<div style="text-align: center;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-g8iAaMSmMSA/XWQ-RV_-hbI/AAAAAAAAF3g/xSLKjMsyZrERCBEOvqDOJAVg7ph15PqEACLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-08-26%2B%25D0%25B2%2B22.20.25.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="730" data-original-width="1600" height="182" src="https://1.bp.blogspot.com/-g8iAaMSmMSA/XWQ-RV_-hbI/AAAAAAAAF3g/xSLKjMsyZrERCBEOvqDOJAVg7ph15PqEACLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-08-26%2B%25D0%25B2%2B22.20.25.png" width="400" /></a></div>
<br /></div>
<br />
Таким образом экономится рабочее время системных администраторов - им не нужно ежедневно перепроверять все секретные ключи и токены в Secrets Manager вручную - достаточно время от времени заходить в дашборд.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-10259859889658274042019-07-30T11:34:00.001-07:002019-07-30T11:41:05.260-07:00Облачный Битрикс24 и почтовый трекинг - интеграция по SOAP через AWS LambdaЧитатели моего блога уже знают, что в последнее время я полюбила использовать Serverless технологии AWS: Lambda и API Gateway, вебхуки и их обработчики на языке Python3 для кастомизации облачного Битрикс24. Это удобно, просто, изящно и очень дешево.<br />
<br />
К примеру, дергать SOAP-сервис Почты России из AWS Lambda - можно бесплатно целый год, а потом, если мои замеры и подсчеты верны, проверка 100 000 почтовых квиточков за год, что с лихвой покроет нужды любого малого бизнеса, обойдется примерно в 12$.<br />
<br />
Что же нам для этого потребуется:<br />
<br />
<a name='more'></a><br />
1) Получить логин и пароль для интеграции на сайте Почты России <a href="https://www.pochta.ru/support/business/api">https://www.pochta.ru/support/business/api</a> - мне логин и пароль прислали через 5 минут после моего запроса.<br />
<br />
2) Подготовить Lambda Layer с библиотекой для работы с SOAP. Я выбрала для себя опенсоурсную билиотеку Zeep. О том, как упаковать ее в Layer, я писала ранее в личном блоге: <a href="http://bedrosova.blogspot.com/2019/07/aws-lambda-layer-zeep.html">http://bedrosova.blogspot.com/2019/07/aws-lambda-layer-zeep.html</a><br />
<br />
3) Сделать на стороне Битрикс24 входящий вебхук с правами посылать сообщения пользователю и с доступом к универсальным спискам (в моем случае) или, может быть, к CRM - смотря куда вам нужно складывать результат проверки трекинг-номера.<br />
<br />
4) Написать бизнес-процесс в Битрикс24, который будет дергать внешний веб-хук, передавая ему номер почтового отправления, который необходимо проверять, а так же ид элемента и инфоблока, в который необходимо сохранить результат проверки.<br />
<br />
5) Написать Lambda функцию, которая примет переданные от Битрикс24 данные, запросит состояние почтового отправления по SOAP в почте России и вернет результат в Битрикс24 по входящему веб-хуку в том или ином виде.<br />
<br />
6) Настроить API Gateway для нашей Lambda функции. Подробно этот процесс я расписывала ранее: <a href="http://bedrosova.blogspot.com/2019/07/aws-lambda-api-gateway-24.html">http://bedrosova.blogspot.com/2019/07/aws-lambda-api-gateway-24.html</a> и еще планирую в будущем написать о том, как сделать все тоже самое не через консоль AWS, а через AWS CLI со своего локального компьютера, потому что, понятное дело, что какой-то небольшой проект можно автоматизировать непосредственно в консоли, но если разрабатывать что-то масштабное, что требует продолжительной итеративной интеграции, то без применения AWS CLI, Docker и SAM - не обойтись.<br />
<br />
Сейчас же я хочу рассказать о тех сценариях интеграции почтового трекинга, которые я реализовала в облачном Битрикс24 для Студии Юлии Бедросовой.<br />
<br />
Исторически так сложилось, что всю входящую и исходящую почтовую переписку я сканирую и заношу в заведенный специально для этого в Битрикс24 список - Реестр почтовых отправлений. В числе прочих данных я храню там и почтовый трекинг-номер:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-JlDNSxuCE50/XUB_YqgZ-WI/AAAAAAAAFz4/ipEFi4kDNgcGCEe1DRcYI50-Ie5OYfzjgCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B20.30.35.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="1600" height="225" src="https://1.bp.blogspot.com/-JlDNSxuCE50/XUB_YqgZ-WI/AAAAAAAAFz4/ipEFi4kDNgcGCEe1DRcYI50-Ie5OYfzjgCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B20.30.35.png" width="400" /></a></div>
<br />
<br />
На этом списке я реализовала 2 бизнес-процесса:<br />
<br />
Первый - маленький, который позволяет быстро проверить трекинг-номер вручную и получить данные по нему в личные сообщения в портале:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-dKjiUENaQyU/XUCBtjZob-I/AAAAAAAAF0E/_VcQdDBYGlUV_jYQjgMfIxS3vFfDKMYJwCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B20.42.43.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="788" data-original-width="460" height="320" src="https://1.bp.blogspot.com/-dKjiUENaQyU/XUCBtjZob-I/AAAAAAAAF0E/_VcQdDBYGlUV_jYQjgMfIxS3vFfDKMYJwCLcBGAs/s320/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B20.42.43.png" width="186" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
Единственное, что он делает - это дергает веб-хук:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-V9rR2nga8Zk/XUCCMeBZqkI/AAAAAAAAF0M/PMgX1UuPFBgD-6c8knD7RLH6ToefS63twCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B20.44.12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1216" data-original-width="1600" height="303" src="https://1.bp.blogspot.com/-V9rR2nga8Zk/XUCCMeBZqkI/AAAAAAAAF0M/PMgX1UuPFBgD-6c8knD7RLH6ToefS63twCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B20.44.12.png" width="400" /></a></div>
<br />
Обработчик данного веб-хука на стороне AWS Lambda выглядит следующим образом:<br />
<br />
<script src="https://gist.github.com/BedrosovaYulia/6e9be6cac705a5711679e0e16b93ca9d.js"></script><br />
<br />
Помню, когда я в последний раз работала с SOAP на PHP - там была простыня кода, а тут на Python3 + Zeep все просто, как 2*2<br />
<br />
Запускаю данный бизнес-процесс вручную:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-5_9oC_2LwhM/XUCEgXfEjcI/AAAAAAAAF0Y/R3EFGb4_A9sss0SljJI1RbdF9d_FP5VIQCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B20.53.30.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="951" data-original-width="1600" height="237" src="https://1.bp.blogspot.com/-5_9oC_2LwhM/XUCEgXfEjcI/AAAAAAAAF0Y/R3EFGb4_A9sss0SljJI1RbdF9d_FP5VIQCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B20.53.30.png" width="400" /></a></div>
<br />
И получаю личное сообщение от самой себя со всей историей перемещения письма и его текущим статусом:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-yCy5Ue0o5Xs/XUCFI91Is5I/AAAAAAAAF0g/gk8xhOanj9wHM2Zf1KJGfIolkdAWgaGDACLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B20.56.16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="974" data-original-width="1600" height="242" src="https://1.bp.blogspot.com/-yCy5Ue0o5Xs/XUCFI91Is5I/AAAAAAAAF0g/gk8xhOanj9wHM2Zf1KJGfIolkdAWgaGDACLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B20.56.16.png" width="400" /></a></div>
<br />
<br />
Второй - большой бизнес-процесс запускается автоматически при изменении записи Реестра:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-EOHl0CWkoFA/XUCHBoTTHzI/AAAAAAAAF0s/7ANrPr3lHoc9GM9XxZbWy3jRwXhSoA5FgCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B21.05.09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1071" data-original-width="1600" height="267" src="https://1.bp.blogspot.com/-EOHl0CWkoFA/XUCHBoTTHzI/AAAAAAAAF0s/7ANrPr3lHoc9GM9XxZbWy3jRwXhSoA5FgCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B21.05.09.png" width="400" /></a></div>
Бизнес-процесс проверяет входящий это документ или исходящий. Для входящих - ничего не делает (я и так его уже получила, раз внесла в реестр, и ничего отслеживать мне не нужно).<br />
<br />
Для исходящего трекинг-номер появляется не сразу, потому что я вношу запись в реестр, когда упаковываю документы в конверт, чтобы обозначить там содержимое конверта, а трекинг номер я заполняю уже потом - когда получаю почтовые квиточки, поэтому бизнес-процесс проверяет, есть ли уже трекинг-номер, и если пока нет - ждет 3 дня. Если трекинг-номер уже есть, дергает веб-хук.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-BicmArs5W6s/XUCIjjhF68I/AAAAAAAAF04/GZIsO1uI6Bk2SJMjxEOmEFhhvW60SfU9gCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B21.11.10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1208" data-original-width="1600" height="301" src="https://1.bp.blogspot.com/-BicmArs5W6s/XUCIjjhF68I/AAAAAAAAF04/GZIsO1uI6Bk2SJMjxEOmEFhhvW60SfU9gCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B21.11.10.png" width="400" /></a></div>
<br />
Его обработчик похож на тот, что я показывала выше по тексту, но только еще происходит запись финального статуса отправления в поле списка "Почтовый статус". Как проапдейтить список из Lambda функции я тоже уже писала ранее в блоге: <a href="http://bedrosova.blogspot.com/2019/07/24-python3-aws-lambda.html">http://bedrosova.blogspot.com/2019/07/24-python3-aws-lambda.html</a><br />
<br />
После запуска веб-хука я вставила в бизнес-процесс паузу 5 минут, чтобы дать обработчику на стороне AWS Lambda время на обработку - она занимает до 40 секунд в зависимости от того, как долго отвечает сервис Почты России.<br />
<br />
После этого бизнес-процесс проверяет, перешел ли трекинг-номер в статус "Вручение Адресату почтальоном" - если перешел, то цикл перестает крутиться - это финальный статус, к-й возвращает сервис уже после успешного вручения. Если статус не достигнут, то через 3 дня процесс повторяется.<br />
<br />
Этот процесс крутится сам по себе и освобождает меня от тупой работы.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-ZqLUO6xZaWE/XUCKT8JwndI/AAAAAAAAF1E/7eNwG7vHjZU7DnBaJGnf8JV1UhSzfbnYACLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B21.18.11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1034" data-original-width="1600" height="257" src="https://1.bp.blogspot.com/-ZqLUO6xZaWE/XUCKT8JwndI/AAAAAAAAF1E/7eNwG7vHjZU7DnBaJGnf8JV1UhSzfbnYACLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-30%2B%25D0%25B2%2B21.18.11.png" width="400" /></a></div>
<br />
<br />
Мне достаточно зайти в мой реестр и выставить нужные фильтры, чтобы увидеть состояние моих отправленных писем.<br />
<br />
Аналогичным образом можно осуществить интеграцию облачного Битрикс24 с любой внешней системой, которая умеет отдавать данные по SOAP или предоставляет API в любом виде.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-54383748964447447492019-07-28T07:35:00.002-07:002019-07-28T08:46:54.678-07:00Как собрать AWS Lambda Layer с библиотекой ZeepPython библиотека Zeep - предназначена для работы с SOAP - сервисами. Эта библиотека написана на чистом Python, но одна из ее зависимостей lxml содержит код на C, так как использует libxml2 и libxslt. Из-за этого библиотеку Zeep невозможно залить в Lambda Layer без танцев с бубном.<br />
<br />
В одном из моих Serverless проектов мне нужно было использовать эту библиотеку, и я нашла такой способ засунуть ее в Layer:<br />
<br />
<a name='more'></a><br />
Сначала как обычно создаем на компьютере директорию:<br />
<br />
<blockquote class="tr_bq">
mkdir -p python/lib/python3.6/site-packages/</blockquote>
<br />
и устанавливаем туда Zeep через pip:<br />
<br />
<blockquote class="tr_bq">
pip install zeep --target python/lib/python3.6/site-packages/</blockquote>
<br />
Библиотека установится в эту директорию вместе с зависимостями. Теперь идем туда и удаляем папки библиотеки lxml:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-u5D-z1oQgwc/XT2wFsl0jII/AAAAAAAAFzg/k-5Yg7WvOqg0GQmvht3d9GXmABkUUdY1ACLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-28%2B%25D0%25B2%2B17.22.18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1136" data-original-width="1542" height="293" src="https://1.bp.blogspot.com/-u5D-z1oQgwc/XT2wFsl0jII/AAAAAAAAFzg/k-5Yg7WvOqg0GQmvht3d9GXmABkUUdY1ACLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-28%2B%25D0%25B2%2B17.22.18.png" width="400" /></a></div>
<br />
<br />
А вместо них вставляем туда вот эту версию библиотеки lxml: <a href="https://github.com/BedrosovaYulia/aws-lambda-lxml/tree/master/3.8.0/py36/lxml">https://github.com/BedrosovaYulia/aws-lambda-lxml/tree/master/3.8.0/py36/lxml</a> (она немного порезана относительно обычной и не использует libxml2 и libxslt)<br />
<br />
Все, теперь можно паковать папку pyton в zip архив, заливать в Lambda Layer и удобно работать там с SOAP. Для примера можно получить информацию о почтовом отравлении с сервиса Почты России:<br />
<br />
<script src="https://gist.github.com/BedrosovaYulia/695576928ea89d5f4115a97049bafe94.js"></script><br />
<br />
Работает:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-RlWdsDjC0D4/XT2xwcLgQxI/AAAAAAAAFzs/UZSDumrV774ZOCtaaUgvN5n-OA0iNHhZQCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-28%2B%25D0%25B2%2B17.30.12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="874" data-original-width="1600" height="216" src="https://1.bp.blogspot.com/-RlWdsDjC0D4/XT2xwcLgQxI/AAAAAAAAFzs/UZSDumrV774ZOCtaaUgvN5n-OA0iNHhZQCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-28%2B%25D0%25B2%2B17.30.12.png" width="400" /></a></div>
<br />
<br />
<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-85138100776563920992019-07-25T01:36:00.003-07:002023-09-25T02:44:24.019-07:00AWS Lambda и API Gateway для обработки вебхуков<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-zIQhcBp5Otg/XTjKODEoeeI/AAAAAAAAFyk/2NQPm1Rp4xIFde_xeO03ii377KbxMddmwCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-25%2B%25D0%25B2%2B0.14.01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="511" data-original-width="1600" height="126" src="https://1.bp.blogspot.com/-zIQhcBp5Otg/XTjKODEoeeI/AAAAAAAAFyk/2NQPm1Rp4xIFde_xeO03ii377KbxMddmwCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-25%2B%25D0%25B2%2B0.14.01.png" width="400" /></a></div>
Многие мои клиенты выбрали в качестве CRM-системы и системы управления проектами Битрикс24 в облаке. Основное преимущество облака перед коробой состоит в том, что клиенту не нужно думать о настройке сервера, его мощностях, безопасности, амортизации железа, нанимать отдельно администратора сервера. Однако это преимущество частично теряется, когда возникает необходимость расширить функционал Битрикс24 за счет кастомных приложений.<br />
<div>
<br /></div>
<div>
Да, приложения под Битрикс24 может хостить партнер, принимая на себя эту головную боль. Но для работы простых нетиражных приложений, тех, для которых обычно используют вебхуки Битрикс24, вообще не нужен сервер. Достаточно беcсерверного (Serverless) сервиса Lambda от AWS (Amazon Web Services) <a href="https://aws.amazon.com/ru/lambda/">https://aws.amazon.com/ru/lambda/</a> и Amazon API Gateway <a href="https://aws.amazon.com/ru/api-gateway/">https://aws.amazon.com/ru/api-gateway/</a>.<br />
Об их применении для расширения функционала Битрикс24 и пойдет речь в данном посте.<br />
<br />
<a name='more'></a><br />
Все описанное ниже можно сделать в рамках бесплатного облачного тарифа Битрикс24 и стартового/ознакомительного условно-бесплатного тарифного плана AWS, доступного сразу после регистрации.<br />
<br />
Рассмотрим для примера простую интеграционную задачу: при создании нового лида в одном облачном Битрикс24 нужно создать такой же лид в другом портале Битрикс24. Эту задачу на самом деле можно решить и более простыми способами, я беру ее просто для наглядного примера.<br />
<br />
<b>1) Создаем 3 вебхука</b><br />
<br />
На первом и на втором Битрикс24 создадим по одному одинаковому входящему вебхуку с доступом к CRM. При создании вебхука в Битрикс24 формируется адрес, привязанный к конкретному порталу, обратившись к которому можно получить доступ к методам REST API Битрикс24 того или тех модулей, доступ к которым выбран при создании вебхука. Поэтому этот выписанный адрес нужно беречь как пароль или секретный ключ. Этот адрес понадобится нам дальше, когда мы будем писать AWS Lambda функцию:</div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-57XgSia1mqk/XTjZpl_oAcI/AAAAAAAAFzA/O8olbZUxiSc0ydBFxGrydv9nTXy4I3DFACLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B21.45.00.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="903" data-original-width="1600" height="225" src="https://1.bp.blogspot.com/-57XgSia1mqk/XTjZpl_oAcI/AAAAAAAAFzA/O8olbZUxiSc0ydBFxGrydv9nTXy4I3DFACLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B21.45.00.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br /></div>
<div>
На скрине выше часть адреса <b style="background-color: #f7f9f9; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; text-align: center;">https://b24-dawbtb.bitrix24.com/rest/1/</b><b>******************/</b> - это адрес самого вебхука, а часть <b>/profile/</b> - это название метода без параметров, возвращающего данные профиля пользователя, из-под которого создан вебхук. Нам нужно скопировать только сам адрес - мы будем вызывать другой метод.<br />
<br />
На первом портале кроме этого необходимо создать исходящий вебхук на событие создание лида.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-_LEfD-72uwg/XTjGkJp9K-I/AAAAAAAAFyY/q06IUVSrqqMGR4MDNrH2E6jAjVaP-nx2QCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B23.57.11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="951" data-original-width="1600" height="237" src="https://1.bp.blogspot.com/-_LEfD-72uwg/XTjGkJp9K-I/AAAAAAAAFyY/q06IUVSrqqMGR4MDNrH2E6jAjVaP-nx2QCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B23.57.11.png" width="400" /></a></div>
<br />
Что подставлять в Handler address станет ясно из пункта 3 данного поста. А Authentication code - это ключик, который генерируется в Битрикс24 при создании исходящего вебхука, и его мы будем использовать в Lambda-функции, чтобы проверить, действительно ли это наш Битрикс24 стучится в нее.<br />
<br />
<b>2) Пишем Lambda-функцию</b><br />
<br />
Заходим в <a href="https://console.aws.amazon.com/">https://console.aws.amazon.com</a> - Services - Lambda - Create function<br />
<br />
Я буду писать тело функции на языке Python 3, а вообще там поддерживаются разные языки - кому какой больше нравится.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-5bPsEC34urw/XTip7YBEZ2I/AAAAAAAAFxc/llVndmbZ5QAEKVMg6mIBISCEWUczF-j-gCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B21.54.55.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="897" data-original-width="1600" height="223" src="https://1.bp.blogspot.com/-5bPsEC34urw/XTip7YBEZ2I/AAAAAAAAFxc/llVndmbZ5QAEKVMg6mIBISCEWUczF-j-gCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B21.54.55.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
Даю своей функции пока только базовые права, необходимые для работы с логами CloudWatch. Если понадобится, потом их можно будет расширить:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-0_Cvy5K_cxI/XTiqouVA2jI/AAAAAAAAFxk/xzMwjDcr2f44bdX4emjiN4spzy1fenO4wCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B21.58.16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="1600" height="198" src="https://1.bp.blogspot.com/-0_Cvy5K_cxI/XTiqouVA2jI/AAAAAAAAFxk/xzMwjDcr2f44bdX4emjiN4spzy1fenO4wCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B21.58.16.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
В тело функции вставляю следующий код:<br />
<br />
<script src="https://gist.github.com/BedrosovaYulia/0a3e0fd5dee22c3a6e3a304edeeedf80.js"></script><br />
<br />
<br />
<b>3) Создаем метод в API Gateway</b><br />
<br />
Идем в Amazon API Gateway и нажимаем кнопку Create API<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-Z6mua68oYoM/XTg5lZYDU_I/AAAAAAAAFxE/ceyhpSC5KSYSbTZgdgE_JtetpLrfhQvWwCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B13.55.45.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="759" data-original-width="1600" height="189" src="https://1.bp.blogspot.com/-Z6mua68oYoM/XTg5lZYDU_I/AAAAAAAAFxE/ceyhpSC5KSYSbTZgdgE_JtetpLrfhQvWwCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B13.55.45.png" width="400" /></a></div>
<br />
<br />
Добавляем метод ANY - чтобы не заморачиваться:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-pEKBU7bN2jc/XTjAvARhYjI/AAAAAAAAFxw/WF6tvomUmhA0BQFIqLNmZh0DrDALUVmNgCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B23.33.20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="714" data-original-width="1600" height="176" src="https://1.bp.blogspot.com/-pEKBU7bN2jc/XTjAvARhYjI/AAAAAAAAFxw/WF6tvomUmhA0BQFIqLNmZh0DrDALUVmNgCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B23.33.20.png" width="400" /></a></div>
<br />
<br />
В настройках Integration Request выбираем нашу Lambda функцию:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-HJS1-J7IoiU/XTjEUdUlxPI/AAAAAAAAFyE/0qasQXvZ4iYhkNgfh60aATj_HUcEo5S1ACLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B23.48.47.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="968" data-original-width="1600" height="240" src="https://1.bp.blogspot.com/-HJS1-J7IoiU/XTjEUdUlxPI/AAAAAAAAFyE/0qasQXvZ4iYhkNgfh60aATj_HUcEo5S1ACLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B23.48.47.png" width="400" /></a></div>
<br />
<br />
В Mapping Templates <b>обязательно</b> нужно указать Content-Type, который будет приходить к нам из Битрикс24. Мы не будем разбирать его на уровне Gateway - передадим в Lambda функцию одной строкой - мне так будет проще отлаживать.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-dpOFgw4m9OQ/XTjBLFTQslI/AAAAAAAAFx4/0395tWlq02QNJkTp8pVNpFB3i3RW1JxqwCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B23.35.24.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="838" data-original-width="1324" height="251" src="https://1.bp.blogspot.com/-dpOFgw4m9OQ/XTjBLFTQslI/AAAAAAAAFx4/0395tWlq02QNJkTp8pVNpFB3i3RW1JxqwCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B23.35.24.png" width="400" /></a></div>
<br />
<br />
Деплоим метод и после деплоя получаем URL-адрес, который как раз и нужно подставить в первом Битрикс24 в исходящий веб-хук на создание лида:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-VUmkESDV8uA/XTjFMXxlrRI/AAAAAAAAFyM/hDh50zzviMIlD6iTxVvFSKMxechEq_8eACLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B23.50.07.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="807" data-original-width="1600" height="201" src="https://1.bp.blogspot.com/-VUmkESDV8uA/XTjFMXxlrRI/AAAAAAAAFyM/hDh50zzviMIlD6iTxVvFSKMxechEq_8eACLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-24%2B%25D0%25B2%2B23.50.07.png" width="400" /></a></div>
<br />
<br />
<br />
Готово! Теперь при создании лида в первом Битрикс24, такой же лид создается и во втором.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/--K1b5IYwpbY/XTlp0o_E8lI/AAAAAAAAFzM/AkT1V8o9kREJuoHP2ZZhWCrNmh_lB6r1wCLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-25%2B%25D0%25B2%2B11.33.21.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="363" data-original-width="1600" height="90" src="https://1.bp.blogspot.com/--K1b5IYwpbY/XTlp0o_E8lI/AAAAAAAAFzM/AkT1V8o9kREJuoHP2ZZhWCrNmh_lB6r1wCLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-25%2B%25D0%25B2%2B11.33.21.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-j51G10x-9yw/XTlp6-fSylI/AAAAAAAAFzQ/bnwYJ3YI5HIFfbpXJIACuTWyO1zscX7UACLcBGAs/s1600/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-25%2B%25D0%25B2%2B11.33.50.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="447" data-original-width="1600" height="111" src="https://1.bp.blogspot.com/-j51G10x-9yw/XTlp6-fSylI/AAAAAAAAFzQ/bnwYJ3YI5HIFfbpXJIACuTWyO1zscX7UACLcBGAs/s400/%25D0%25A1%25D0%25BD%25D0%25B8%25D0%25BC%25D0%25BE%25D0%25BA%2B%25D1%258D%25D0%25BA%25D1%2580%25D0%25B0%25D0%25BD%25D0%25B0%2B2019-07-25%2B%25D0%25B2%2B11.33.50.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
Если бы перед нами стояла задача, для которой требовалось бы работать только со входящими вебхуками (входящими относительно Битрикс24), то нам даже не нужно было бы создавать метод API Gateway.<br />
<br />
Логирование и отладка Lambda функций и API Gateway это отдельная очень интересная тема, я расскажу об этом подробнее в одном из будущих постов. А если тема беcсерверных приложений для Битрикс24 и не только интересна моим читателям, то я в будущем поделюсь своим опытом интеграции Битрикс24 c AWS DynamoDB и расскажу как создать и подключить к Битрикс24 беcсерверного чат-бота на базе Amazon Lex.</div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2818096995044764627.post-66634693885721565042015-02-15T01:12:00.000-08:002015-02-15T01:12:07.181-08:00Как настроить mbstring на хостинге Русоникс<div dir="ltr" style="text-align: left;" trbidi="on">
Как известно, на хостинге <a href="http://www.rusonyx.ru/?from=rsnx&ref=1017962" target="_blank">Русоникс</a> можно организовать отдельное web-пространство для каждого размещенного интернет-сайта.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-vs85JRYCsNw/VOBgQRFGSSI/AAAAAAAAB0g/d_WngxEhA_A/s1600/sites_rusonix.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-vs85JRYCsNw/VOBgQRFGSSI/AAAAAAAAB0g/d_WngxEhA_A/s1600/sites_rusonix.png" height="336" width="400" /></a></div>
<br />
<br />
И, соответственно, если сайты работают в разных кодировках, для каждого сайта можно задать свои параметры mbstring.<br />
Для этого в панели управления хостингом заходим в "Сайты и домены", разворачиваем параметры нужного сайта кнопочкой "Развернуть".<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-hmhZhhrxFMs/VOBhZjokKaI/AAAAAAAAB0s/UCjHjqF32I8/s1600/sites_rusonix2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-hmhZhhrxFMs/VOBhZjokKaI/AAAAAAAAB0s/UCjHjqF32I8/s1600/sites_rusonix2.png" height="328" width="400" /></a></div>
<br />
<br />
Затем выбираем "Настройки php" и вписываем нужные директивы в поле "Дополнительные директивы"<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-biMsclOFmP0/VOBh-eRIjfI/AAAAAAAAB00/381TlUX_vgc/s1600/sites_rusonix3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-biMsclOFmP0/VOBh-eRIjfI/AAAAAAAAB00/381TlUX_vgc/s1600/sites_rusonix3.png" height="335" width="400" /></a></div>
<br />
Нажимаем "ОК". Изменения вступают в силу даже без перезапуска сервера.<br />
Вообще администрировать сервера на хостинге Русоникс очень легко. Для этого не нужно знать ssh команды и разбираться в unix. Не даром у них тарифы называются "Сервер без забот..." А тем, кто регистрирует хостинг по моей <a href="http://www.rusonyx.ru/?from=rsnx&ref=1017962" target="_blank">реферальной ссылке</a>, я всегда готова оказать помощь.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-42395216640653993692013-12-04T13:33:00.002-08:002013-12-04T13:33:34.803-08:00Себе на память - редактирование пользовательского свойства заказа в событии перед изменением заказа (Битрикс)<div dir="ltr" style="text-align: left;" trbidi="on">
Запишу, чтобы не забыть, потому что долго искала:<br />
Стояла задача сохранить в отдельное пользовательское свойство заказа идентификатор того пользователя (принадлежащего группам 1 или 6), который самым первым отредактировал данный заказ (кто первый взял заказ в работу - тот до конца его и ведет).<br />
<br />
<b><span style="font-size: x-small;">public static function OnBeforeOrderUpdateHandler($ID, $arFields) {</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>global $USER;</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>$arGroups = $USER->GetUserGroupArray();</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if (in_array(6,$arGroups) || in_array(1,$arGroups)){</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>$db_vals = CSaleOrderPropsValue::GetList(array("SORT" => "ASC"), array("ORDER_ID" => $ID, "CODE"=>"F_MENEDGER")); </span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>$order_props=array();</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if ($arVals = $db_vals->Fetch()){<span class="Apple-tab-span" style="white-space: pre;"> </span></span></b><br />
<span class="Apple-tab-span" style="white-space: pre;"><b><span style="font-size: x-small;"> </span></b></span><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>$order_props=$arVals;</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>} </span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if (!$order_props['VALUE'])</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if ($arProp = CSaleOrderProps::GetByID(10)) {</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>CSaleOrderPropsValue::Add(array(</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>'ORDER_ID' => $ID,</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>'ORDER_PROPS_ID' => $arProp['ID'],</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>'NAME' => $arProp['NAME'],</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>'CODE' => $arProp['CODE'],</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>'VALUE' => $USER->GetID(),</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>));</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></b><br />
<b><span style="font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></b></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-24859934563951114802013-04-10T15:10:00.000-07:002013-04-10T15:11:42.242-07:00О лишних запросах<div dir="ltr" style="text-align: left;" trbidi="on"><div align="right"><i>Совершенство достигается не тогда, когда уже нечего прибавить, но когда уже ничего нельзя отнять</i><br />
<i>Антуан де Сент-Экзюпери</i><br><br></div><div align="justify">Оптимизация процесса интеграции 1С Предприятия и 1С Битрикс – это неисчерпаемая тема. Чего только не увидишь порой в обработчиках событий добавления и обновления элемента инфоблока. <br />
Больше всего меня убивает, когда я вижу, что разработчики тянут из базы то, что у них и так уже есть. Пример из жизни (нет, серьезно – это реальный пример):<br />
<br />
<div style="text-align: left;"><blockquote class="tr_bq">AddEventHandler("iblock", "OnAfterIBlockElementAdd", "BXMUpdateElement_FIELDS");<br />
function BXMUpdateElement_FIELDS(&$arFields)<br />
{<br />
<br />
$ibe = new CIBlockElement();<br />
<br />
$dbr = $ibe->GetList(array(), array('ID'=>$arFields['ID']) );<br />
while($oe = $dbr->GetNextElement())<br />
{<br />
$arP = $oe->GetProperty('CML2_TRAITS');<br />
<br />
<br />
}<br />
<br />
…<br />
<br />
}</blockquote></div><br />
А то, что нужно – уже передано в обработчик в $arFields['PROPERTY_VALUES'][92]<br />
Зачем так неэкономно разбрасываться запросами к базе? Одна строка – и 20 000 лишних обращений к базе при импорте 20 000 элементов.</div></div>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2818096995044764627.post-27036643855060536542013-02-19T00:29:00.000-08:002013-02-19T00:29:54.743-08:00Git обновить текущую ветку из master<div dir="ltr" style="text-align: left;" trbidi="on">
Если разработка велась в ветке, и за время этой разработки ветка master сильно изменилась, лучше не вливать ветку сразу в мастер, а сначала влить мастер в ветку – чтобы предварительно протестировать.<br />
Для этого нужно переключиться на ту ветку, в которую мы будем вливать мастер, а затем выполнить команду<br />
<blockquote class="tr_bq">
git pull origin master</blockquote>
Cкорее всего, после этого возникнут конфликты – гит скажет об этом.<br />
Чтобы просмотреть все файлы, в которых произошли конфликты, нужно выполнить команду<br />
<blockquote class="tr_bq">
git status</blockquote>
После разрешения конфликтов, нужно сделать коммит, а потом снова выполнить <br />
<blockquote class="tr_bq">
git pull origin master</blockquote>
Таким же образом можно периодически вливать в ветку новые изменения из мастера, если нужно, чтобы ветка не сильно «отошла» от основной версии проекта.</div>
Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-2818096995044764627.post-28691475349811158462013-01-29T03:07:00.000-08:002013-01-29T03:07:44.587-08:00Динамическое добавление полей формы на JQuery<div dir="ltr" style="text-align: left;" trbidi="on"><pre class="brush: php"><div id="div_inputs">
</div>
<script>
var col_inputs=1;
function AddInput(){
$('<label>Метка:</label><input id="inp'+col_inputs+'" type="text" name="name['+col_inputs+']" value="" /><br>').appendTo("#div_inputs");
col_inputs++;
return true;
}
</script>
<input type="button" value="Добавить" onclick="AddInput()">
</pre></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-28194431268886270172012-02-26T00:08:00.002-08:002012-02-26T00:10:25.399-08:00Как показать модальное окошко fancybox сразу после загрузки страницы?Вот такое простое решение нашла:<br /><blockquote><span class="tag"><script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/javascript"</span><span class="tag">></span><span class="pln"><br /> $</span><span class="pun">(</span><span class="pln">document</span><span class="pun">).</span><span class="pln">ready</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> $</span><span class="pun">(</span><span class="str">"#hidden_link"</span><span class="pun">).</span><span class="pln">fancybox</span><span class="pun">().</span><span class="pln">trigger</span><span class="pun">(</span><span class="str">'click'</span><span class="pun">);</span><span class="pln"><br /> </span><span class="pun">});</span><span class="pln"><br /></span><span class="tag"></script></span><span class="pln"></span></blockquote>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-39639749996038744152011-05-23T23:05:00.000-07:002011-10-05T03:31:27.948-07:00print_r в переменную!Век живи - век учись! Оказывается, у функции print_r в php есть второй параметр, который по умолчанию равен false. Если указать его как true, то функция print_r выведет значение не на экран, а в переменную, например так:<br /><br /><pre>$da=print_r($dt1,true);</pre>Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-2818096995044764627.post-85566665454909343752010-08-19T21:41:00.000-07:002010-08-19T21:46:59.754-07:00Приложение Hello World на Asp .Net в среде Visual Studio 2008Многие web-программисты, привыкшие работать с php и perl, мечтают научиться создавать приложения asp .net, но не знают с чего начать и как подступиться к этой технологии. Поэтому в этой статье я хотела бы коротко рассказать, как сделать самое простое asp .net приложение и как выгрузить его на виртуальный хостинг.<br /><p>Нам понадобится среда Visual Studio 2008 (я не буду здесь описывать, что такое Visual Studio, с чем ее едят и ее технические требования. Думаю, мой читатель и так уже знает все это или разберется сам).<br /></p><p>Кроме этого нам понадобится бесплатный windows хостинг с поддержкой asp .net для тестирования нашего приложения (нет, мы конечно можем протестировать наше приложение и на локалхосте, но, согласитесь, - это не одно и то же). Я предлагаю вам использовать для этого бесплатный хостинг <a href="http://www.somee.com">http://www.somee.com</a>.<br /></p><p>Как создать простейшее приложение в Visual Studio 2008 подробно описано здесь <a href="http://www.dotsite.ru/Tutorials/ASP.NET/Baby%20Steps/Creating%20application%20with%20Visual%20Studio%20.NET.aspx">http://www.dotsite.ru/Tutorials/ASP.NET/Baby%20Steps/Creating%20application%20with%20Visual%20Studio%20.NET.aspx</a> – замечательная статья, но ее автор почему-то упустил момент публикации готового asp. net приложения в интернет. Заполню этот пробел.<br /></p>После того, как вы выполните все шаги из указанного урока, выберете в среде Visual Studio пункт меню Build – Publish имя вашего приложения.<br />После этого у вас на экране появится окошечко:<br /><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://1.bp.blogspot.com/_43B5QDUBAJ8/TG4IHG70PoI/AAAAAAAAAxg/npvkl2vudzQ/s320/1.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5507348312534302338" /><br />Выберете папку у себя на компьютере и нажмите Publish<br />После этого выгрузите все файлы и папки, которые оказались в этой папке, на виртуальный хостинг по ftp или через файловый менеджер в панели управления.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-829407290528959382010-05-10T23:36:00.000-07:002010-05-10T23:45:59.910-07:00С# select запрос, возвращающий одно значение<p>С ситуацией, когда нужно получить из таблицы одно поле, зная другое встречается довольно часто. Например, при написании программы, работающей с MsSQL где запрещены подзапросы в insert запросе сплошь и рядом нужно отдельным запросом получать id по имени или имя по id, поэтому я решила упростить себе эту рутинную задачу и написала процедуру для выполнения select запроса, который заведомо должен вернуть один результат.</p><p><em> public string one_result_query(string query, SqlConnection connection)<br /> //Процедура выполнения SQL запроса, возвращающего один результат <br /> //например чтобы узнать наименование по ид или наоборот<br /> //возвращает этот результат в виде строки<br /> {<br /> SqlCommand myCommand = new SqlCommand(query, connection);<br /> myCommand.Connection.Open();<br /> object q_result = myCommand.ExecuteScalar();<br /> myCommand.Connection.Close();<br /> myCommand.Dispose();<br /> return q_result.ToString();<br /> }</em></p><p>Кстати, в одном из старых постов я уже писала подобную процедуру для <a href="http://bedrosova.blogspot.com/2008/06/sql-c.html">запроса, который не должен возвращать результата</a> (такой как delete, update, insert)<br /><br /></p>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2818096995044764627.post-1898572739854602732009-02-18T22:33:00.000-08:002009-02-18T22:40:54.908-08:00Перемещение папок на удаленном сервереСегодня столкнулась с такой проблемой: нужно было перенести большую папку с картинками из одной директории в другую на masterhost. А в панели управления этого самого мастерхоста файловый менеджер отсутствует. Положение спасли две простые ftp команды:<br />rnfr /исходная директория/имя моей папки/<br />rnto /директория куда нужно перенести/имя моей папки/<br />Для того, чтобы выполнить эти команды в FileZilla нужно выбрать в меню "Сервер" пункт "Ввести команду..." и ввести сначала первую команду, потом - вторую.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-92148873579386700512009-02-17T06:56:00.000-08:002009-02-17T07:05:59.211-08:00ShopCMS: реализуем возможность добавления в карзину дробного числа товаров<p align="justify">Движок магазина ShopCMS к сожалению предусматривает добавление в карзину только целого количества товаров. Иногда же возникает ситуация когда нужно позволить пользователю заказать, к примеру, 1.5 мешка сахора. При помощи небольших манипуляций с php кодом Shop CMS можно исправить ситуацию.</p><p align="justify">1. В корне движка находим файл cart.php. Ищем переменную $_GET["multyaddcount"] и везде где она встречается стираем перед ней конструкцию (int).<br /></p><div align="justify">2. В этом же файле находим строку <br /><em>for ($mcn=0; $mcn<$_GET["multyaddcount"]; $mcn++) cartAddToCart((int)$_GET["addproduct"], $variants);</em> заменяем ее на <em>$mac=str_replace(",",".",$_GET["multyaddcount"]); cartAddToCart((int)$_GET["addproduct"], $variants, $mac);</em> </div><p align="justify">здесь заодно позволим пользователю ввести , вместо .</p><p align="justify">3. Открываем файл /functions/cart_functions.php<br /></p><div align="justify">Находим заголовок функции<br /> function cartAddToCart( $productID, $variants )<br />и меняем его на<br />function cartAddToCart( $productID, $variants,$count_to_order)<br />далее в теле этой функции комментируем все места, где переменной <em>$count_to_order</em> присваевается значение, а так же стираем все конструкции <em>(int)</em> перед этой переменной.</div><div align="justify"><br />4. Далее открываем файл /design/user/default/ shopping_cart.tpl<br />Находим в нем заголовок формы formppl. Обработчик формы ведет на файл index.php, но он закодирован зендом. Поэтому напишем свой обработчик. Меняем заголовок формы на<br /><em><br /><form action="/update_cart.php?shopping_cart=yes" method=get name="formppl" id="formppl"></em></div><div align="justify"><br />5. Теперь осталось написать сам обработчик update_cart.php и поместить его в корень сайта. Привожу его примерный текст:<em><br /><?<br /> include ("config/connect.inc.php");<br /> include ("includes/database/mysql.php");<br /> include ("config/language_list.php");<br /> include ("functions/functions.php");<br /> include ("functions/session_functions.php");<br /> MagicQuotesRuntimeSetting();<br /><br /> <br /> db_connect(DB_HOST, DB_USER, DB_PASS) or die(db_error());<br /> db_select_db(DB_NAME) or die(db_error());<br /> <br /> settingDefineConstants();<br /><br /> define("SECURITY_EXPIRE", 60 * 60 * CONF_SECURITY_EXPIRE);<br /> session_set_save_handler("sess_open", "sess_close", "sess_read", "sess_write", "sess_destroy", "sess_gc");<br /> session_set_cookie_params(SECURITY_EXPIRE);<br /> session_start();<br /> <br />$qmin="select min(itemID) as m1 from pnte_shopping_carts";<br />$m1r=mysql_query($qmin);<br />$min=mysql_result($m1r,0);<br /><br />$qmax="select max(itemID) as m2 from pnte_shopping_carts";<br />$m2r=mysql_query($qmax);<br />$max=mysql_result($m2r,0);<br /><br />for ($i=$min; $i<=$max; $i++)<br />{<br />$nm="count_$i";<br />if ($_GET[$nm]){<br />$gnm=str_replace(",",".",$_GET[$nm]);<br /><br /> if ((int)regGetIdByLogin($_SESSION["log"])){<br /> $query="update pnte_shopping_carts set Quantity=".$gnm." where itemID=$i and customerID=".(int)regGetIdByLogin($_SESSION["log"]);<br /> print $query."<br>";<br /> $result = mysql_query($query);<br /> }<br /> else{<br /> <br /> for ($j = 0; $j < count($_SESSION["gids"]); $j++)<br /> {<br /> if ($_SESSION["gids"][$j]==$i)<br /> {<br /> <br /> $_SESSION["counts"][$j]=$gnm;<br /> <br /> }<br /> }<br /> }<br />}<br />}<br />header ("Location: /cart.html");<br />?> <br /></em><br />Вот и все – теперь ваши пользователи смогут заказывать в интернет-магазине дробное количество товаров.<br /><br /><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-88545882314760945052009-02-10T23:52:00.000-08:002009-02-10T23:56:35.797-08:00SELECT запросы к базе данных Joomla 1.5<div align="justify">При настройке Joomla 1.5 часто возникает необходимость вывести из базы данных некоторую информацию, скажем, в виде модуля. Для того чтобы это сделать совсем не обязательно заморачиваться с созданием отдельного модуля. Можно внедрить свой php-код в Joomla при помощи модуля mod_php. Запрос SELECT к базе данных и его обработка будет выглядеть например так:<br /></div><br /> <ul><br /><? <br />$db =& JFactory::getDBO(); <br />$query = "SELECT * FROM #__my_joomla_table";<br />$db->setQuery($query);<br />$result = $db->loadObjectList();<br />foreach ($result as $r) :<br />?><br /> <li><br /> <?php echo $r->my_field1; ?><br /> </li><br /><?php<br />endforeach;<br />?><br /></ul>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2818096995044764627.post-41647937211319657312009-02-10T23:21:00.000-08:002009-02-10T23:27:36.670-08:00Режим отладки Joomla<div align="justify">Когда вы занимаетесь отладкой Joomla целесообразно включить соответствующий режим, а так же вывести время генерации страницы. Режим отладки вкючается соответствующим флажком в «Глобальной конфигурации» Joomla. А для того, чтобы вывести время генерации страницы добавьте в файл index.php движка следующий код:<br />После тега <body>:<br /><?php<br />$tstart = mosProfiler::getmicrotime();<br />?><br />Перед тегом </body>:<br /><?php<br />$tend = mosProfiler::getmicrotime();<br />$totaltime = ($tend - $tstart);<br />printf ("Страница сгенерирована за %f секунд", $totaltime);<br />?><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2818096995044764627.post-87962004994483935352009-02-10T22:57:00.000-08:002023-09-24T14:40:17.649-07:00Оптимизируем Joomla для снижения нагрузки на сервер<div align="justify">Представьте ситуацию: вы приложили все возможные усилия, чтобы добиться высокой посещаемости вашего сайта на движке Joomla. Наконец-то посещаемость выросла больше 1000 уникальных посетителей в день. Вы только-только начали радоваться первой прибыли от рекламы на сайте. И вот вы получаете сообщение от своего хостера примерно такого содержания: ваш сайт создает слишком высокую нагрузку на наш сервер. Нагрузка не должна превышать столько-то процентов. Ваш аккаунт будет удален через столько-то дней… и т.д. Что же делать в такой ситуации? Не отчаивайтесь. Есть несколько простых способов, позволяющих оптимизировать работу Joomla и снизить нагрузку на сервер:<br /><span class="fullpost"><br /><strong>1. </strong>В административной панели Joomla зайдите в «Глобальная конфигурация (Общие настройки)» -> «Кеш». Если кеширование выключено – включите его. Если кеширование включено, увеличте время жизни кеша в 5-10 раз.<br /><strong>2.</strong> Если вы пользуетесь сторонними компонентами для ЧПУ (SEF) – отключите их – оставьте только встроенный SEF Joomla. Красивые URL адреса страниц – это конечно хорошо. Но ЧПУ компоненты примерно в 2 раза увеличивают нагрузку на сервер.<br /><strong>3.</strong> Если пункта 2 оказалось мало, отключите и встроенное Joomla ЧПУ (в «Глобальная конфигурация»-> Дружественные для поисковых систем URL-ы (SEF) поставьте флажок «нет»).<br /><strong>4.</strong> Установите мамбот для полного кеширования страниц Joomla. Очень хороший мамбот <a href="http://joomlaforum.ru/index.php/topic,35163">botSystemCacheJ10</a>. После установки этого мамбота не забудьте его опубликовать. У этого мамбота есть настройка «время жизни кеша в секундах» - чем большее время вы поставите – тем меньше будет нагрузка на сервер. Этот вариант хорошо подходит, если содержимое вашего сайта в основном статичное (статьи, каталог чего-нибудь и т.д.) и не подходит, если сайт по своему функционалу должен постоянно обновляться.<br /><strong>5.</strong> Перенесите содержимое статичных модулей (счетчики, блоки рекламы) в шаблон сайта. Не используйте модулей «Пользовательский модуль» и mod_php – их содержимое лучше прописать в шаблоне сайта<br />Вот и все. После проведения этих мероприятий напишите своему хостеру о том, что вы оптимизировали свой сайт, и нагрузка на сервер должна была снизиться. Включив <a href="http://bedrosova.blogspot.com/2009/02/joomla_10.html">режим отладки</a> Joomla до проведения этих мероприятий и после, вы и сами сможете в этом убедиться.<br /></span><br /></div>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2818096995044764627.post-23799551665814166892008-06-04T09:01:00.000-07:002008-06-03T22:04:03.471-07:00О горячих сочетаниях клавиш редактора Visual Studio<span>1. Для того, чтобы выделить текст в редакторе VS колонкой, удерживайте клавишу Alt.<br />2. Редактор Visual Studio предоставляет возможность сохранять в буфере обмена по несколько фрагментов. Для того, чтобы выбрать, какой фрагмент из буфера вставлять нажмите Ctrl + Shift+V.<br />3. Нажатие сочетания Ctrl+K+C позволяет закомментировать выделенный участок текста, а Ctrl+K+U – снять комментарии.<br />4. Для показа подсказчика кода (IntelliSense) нажмите Ctrl+J.<br />5. Для быстрого перехода от открытой скобки (знака /*, начала региона #region) к ее паре нажмите Ctrl + ].</span>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2818096995044764627.post-59736363062266109332008-06-04T02:36:00.000-07:002008-06-04T02:37:13.872-07:00Как получить абсолютный путь к web странице<span style="font-family:arial;">В ASP.NET получить абсолютный путь к странице достаточно легко. Для этого можно использовать метод VirtualPathUtility.ToAbsolute.<br /><blockquote>string absolutePath = VirtualPathUtility.ToAbsolute("~/test/MyWebForm.aspx");<br />Uri newUri = new Uri(Request.Url, absolutePath);</blockquote></span>Unknownnoreply@blogger.com0