Вычислительная техника! Конечно, у него очень долгая, яркая (а иногда и неловкая) история. Некоторые ключевые вехи включают:

В соответствии со всем этим, парадигмы программных приложений также резко изменились. Начиная от чисто аппаратного программирования и заканчивая монолитами, модульностью, SOA, облаком, а теперь… бессерверным.

На данный момент бессерверный обычно означает FaaS (функции как услуга). А FaaS буквально означает AWS Lambda, как с точки зрения популярности, так и принятия.

Следовательно, не будет преувеличением сказать, что популярность бессерверной разработки может быть связана с простотой использования Lambdas. Либо это?

Ну, Lambda существует с 2015 года. Он уже интегрирован в большую часть экосистемы AWS и используется в производственной среде сотнями (если не тысячами) компаний. Итак, Lambda должна быть довольно интуитивно понятной и простой в использовании, не так ли?

Ну, в моем случае, похоже, нет.

А поскольку «мой случай» был одним из официальных примеров AWS, я не совсем уверен, что Lambda достаточно дружелюбна для новичков.

Для начала я хотел реализовать собственный пример использования создания эскизов AWS без следования их собственному руководству, чтобы посмотреть, как далеко я могу продвинуться.

Я, как программист, естественно начал с консоли управления Lambda. Код был уже написан щедрыми разработчиками AWS, так зачем изобретать велосипед? Скопируйте, вставьте, сохраните, запустите. Та-да!

Хм, похоже, мне нужно немного подрасти.

Привлекал внимание мастер Создание функции с таким количеством готовых чертежей. Жаль, что у него еще не было примера создания миниатюр S3, иначе эта история могла бы закончиться прямо здесь!

Поэтому я просто выбрал вариант «Автор с нуля», используя имя s3-thumbnail-generator.

Ой, подождите, что это за штука с «ролью»? Это тоже необходимо. К счастью, у него есть опция «Создать новую роль из шаблона (ов)», которая спасла бы меня.

Не принимайте близко к сердцу. «Название роли»: s3-thumbnail-generator-role. Но как насчет «шаблона политики»?

Возможно, мне стоит найти что-нибудь, связанное с S3, поскольку моя Lambda полностью S3.

Сюрприз! Единственное, что я получаю, когда ищу S3, - это «Разрешения только на чтение объекта S3». Не имея другого выхода, я просто схватил его. Посмотрим, как далеко я смогу пройти, прежде чем упаду лицом вниз!

Пора нажать «Создать функцию».

Вау, их конструктор Lambda выглядит действительно круто!

«Поздравляю! Ваша лямбда-функция «s3-thumbnail-generator» успешно создана. Теперь вы можете изменить его код и конфигурацию. Нажмите кнопку «Тест», чтобы ввести тестовое событие, когда вы будете готовы проверить свою функцию ».

Хорошо, время для моей миссии по копированию и вставке. Скопируйте образец исходного кода, Ctrl+A и Ctrl+V в редакторе кода лямбда. Простой!

Все зеленые (без красных). Хорошо знать.

«Сохранить» и «Проверить».

О, я должен был знать лучше. Ага, если я собираюсь «Тестировать», мне нужен «Тестовый ввод». Очевидно.

Я знал, что протестировать мою новенькую Lambda будет не так просто. Но я не ожидал, что придется собирать сериализованное событие JSON вручную.

К счастью, разработчики AWS проделали отличную работу и здесь, предоставив готовый шаблон события «S3 Put». Так что еще я бы выбрал?

Как и ожидалось, первый запуск оказался неудачным:

{
  "errorMessage": "Cannot find module 'async'",
  "errorType": "Error",
  "stackTrace": [
    "Function.Module._load (module.js:417:25)",
    "Module.require (module.js:497:17)",
    "require (internal/module.js:20:19)",
    "Object. (/var/task/index.js:2:13)",
    "Module._compile (module.js:570:32)",
    "Object.Module._extensions..js (module.js:579:10)",
    "Module.load (module.js:487:32)",
    "tryModuleLoad (module.js:446:12)",
    "Function.Module._load (module.js:438:3)"
  ]
}

Блин, я должен был заметить эти require строчки.

И, в любом случае, это у меня плохо. Страница, на которую я скопировал образец кода, имела большой жирный заголовок «Создать Lambda пакет развертывания» и четко объясняла, как объединить образец в zip-архив с возможностью развертывания Lambda.

Итак, я создал локальный каталог, содержащий мой код и package.json, и запустил npm install (хорошо, что у меня были предустановлены node и npm!).

Собрать, заархивировать и загрузить приложение было довольно легко, и, надеюсь, мне не пришлось бы проходить через миллион и один таких циклов, чтобы моя Lambda заработала.

(Кстати, я бы хотел сделать это в самом встроенном редакторе. Жаль, что я не смог придумать способ добавить зависимости.)

В любом случае, пришло время для моего второго теста.

{
  "errorMessage": "Cannot find module '/var/task/index'",
  "errorType": "Error",
  "stackTrace": [
    "Function.Module._load (module.js:417:25)",
    "Module.require (module.js:497:17)",
    "require (internal/module.js:20:19)"
  ]
}

index? Откуда это пришло?

Подожди ... у меня плохо, у меня плохо.

Похоже, что параметр Handler по-прежнему имеет значение по умолчанию index.handler. В моем случае это должно быть CreateThumbnail.handler (filename.method).

Давай попробуем еще раз.

Шутки в сторону? Ни за что!

О да. Журналы не врут.

2018-02-04T17:00:37.060Z	ea9f8010-09cc-11e8-b91c-53f9f669b596
  Unable to resize sourcebucket/HappyFace.jpg and upload to
  sourcebucketresized/resized-HappyFace.jpg due to an error:
  AccessDenied: Access Denied
END RequestId: ea9f8010-09cc-11e8-b91c-53f9f669b596

Справедливо. У меня нет sourcebucket или sourcebucketresized, но, вероятно, у кого-то есть. Отсюда отказ в доступе. Имеет смысл.

Поэтому я создал свои собственные сегменты s3-thumb-input и s3-thumb-inputresized, отредактировал ввод событий (благодаря раскрывающемуся списку «Настроить тестовое событие») и повторил попытку.

2018-02-04T17:06:26.698Z	bbf940c2-09cd-11e8-b0c7-f750301eb569
  Unable to resize s3-thumb-input/HappyFace.jpg and upload to
  s3-thumb-inputresized/resized-HappyFace.jpg due to an error:
  AccessDenied: Access Denied

В доступе отказано? Опять таки?

К счастью, на основе ввода события я выяснил, что 403 на самом деле может указывать на ошибку 404 (не найдено), поскольку в моем ведре на самом деле не было файла HappyFace.jpg.

Подожди, дорогой читатель, а я кинулся к консоли S3 и загрузил свое счастливое лицо в свое новое ведро. Минуточку!

Хорошо, готов к следующему тесту.

2018-02-04T17:12:53.028Z	a2420a1c-09ce-11e8-9506-d10b864e6462
  Unable to resize s3-thumb-input/HappyFace.jpg and upload to
  s3-thumb-inputresized/resized-HappyFace.jpg due to an error:
  AccessDenied: Access Denied

Точно такая же ошибка? Опять таки? Ну давай же!

Для меня это не имело смысла. Почему моя собственная Lambda, запущенная в моем собственном аккаунте AWS, не будет иметь доступа к моей собственной корзине S3?

Подождите, это может быть связано с этой ролью исполнения? В той части, где я слепо назначил S3 права только для чтения?

Небольшой поиск в Google привел меня к чрезвычайно исчерпывающим документам AWS IAM для Lambda. Там я узнал, что Lambda выполняет свою собственную роль IAM. Мне пришлось бы вручную настроить роль в зависимости от того, какие сервисы AWS я буду использовать.

Что еще хуже, чтобы настроить роль, мне нужно пройти весь путь до консоли управления IAM. К счастью, это уже связано с раскрывающимся меню роли выполнения. Что еще более важно, он открывается в новой вкладке.

Скрестим пальцы, пока не загрузится страница пользовательской роли.

О нет ... Больше редактирования JSON?

В исходном руководстве разработчики AWS, похоже, прибили также и роль исполнения. Но было странно, что там не было упоминания о S3 (кроме названия). Они что-то упустили?

Хорошо, впервые в истории я собираюсь создать свою собственную роль IAM!

Благослови этих инженеров AWS, беглый поиск в Google показал их жемчужину генератора политик. Как раз то, что мне нужно.

Но избавление от синтаксиса JSON решает лишь небольшую часть проблемы. Как я могу узнать, какие разрешения мне нужны?

Гугл, приятель? Что-нибудь?

Ох… Вернемся к документации AWS? Большой…

Что ж, все было не так уж плохо, спасибо Руководству по разрешениям S3.

Хотя это было несколько ошеломляюще, я догадался, что мне нужны некоторые разрешения для «операций с объектами». К счастью, в документе была хорошая таблица, предполагающая, что мне нужны s3:GetObject и s3:PutObject (в соответствии с вызовами s3.getObject(...) и s3.putObject(...) в коде).

Поразмыслив, я получил «Политику IAM» с указанными выше разрешениями в моем сегменте (названный с утомительным синтаксисом arn:aws:s3:::s3-thumb-input):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1517766308321",
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::s3-thumb-inputresized"
    },
    {
      "Sid": "Stmt1517766328849",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::s3-thumb-input"
    }
  ]
}

Я вставил и сохранил его в редакторе ролей IAM (который автоматически вернул меня на страницу консоли Lambda - как хорошо!)

Попробуйте снова…

Та же ошибка ?!

Оглядываясь назад на документ о разрешениях S3, я заметил, что права доступа к объектам содержат звездочку (суффикс /*, вероятно, обозначающий файлы) под именем ресурса. Так что давайте попробуем и это с новой настраиваемой политикой:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1517766308321",
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::s3-thumb-inputresized/*"
    },
    {
      "Sid": "Stmt1517766328849",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::s3-thumb-input/*"
    }
  ]
}

Опять таки! (это начинает звучать как Whiplash):

2018-02-04T17:53:45.484Z	57ce3a71-09d4-11e8-a2c5-a30ce229e8b7
  Successfully resized s3-thumb-input/HappyFace.jpg and uploaded to
  s3-thumb-inputresized/resized-HappyFace.jpg

У-У-У !!!

Вы не поверите, но в моем s3-thumb-inputresized ведре только что появился resized-HappyFace.jpg файл! Ах, да!

Теперь, как я могу настроить мою Lambda для автоматического запуска, когда я помещаю файл в свою корзину?

К счастью, консоль Lambda (с ее интуитивно понятным макетом «триггерные функции-разрешения») дала кристально ясно, что мне нужен триггер S3. Поэтому я добавил один, с «Object Created (All)» в качестве «Тип события» и «jpg» в качестве суффикса, сохранил все и сразу же поместил файл JPG в свою корзину.

Ага, работает как шарм.

Чтобы увидеть, сколько времени занял весь процесс (в реальном исполнении, в отличие от «тестов»), я щелкнул ссылку «журналы» на (предыдущей) панели результатов выполнения и вошел в последний «поток журнала», показанный там. Ничего такого!

И что еще более подозрительно, последний журнал в новейшем потоке журнала был журналом «отказано в доступе», хотя я уже прошел эту точку и даже добился успешного изменения размера.

Может быть, мое последнее изменение нарушило способность Lambda вести журнал?

Благодаря Google и StackOverflow я обнаружил, что моя исполнительная роль также должна содержать некоторые разрешения, связанные с ведением журнала.

Теперь я помню, что в текстовом поле редактора разрешений были некоторые разрешения, когда я начал создавать свою настраиваемую роль. И снова я был достаточно невежественен, чтобы наклеить свои политики S3 прямо на них.

Еще один раунд редактирования политики:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1517766308321",
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::s3-thumb-inputresized/*"
    },
    {
      "Sid": "Stmt1517766328849",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::s3-thumb-input/*"
    },
    {
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}

Еще одно падение файла, и на этот раз и изменение размера, и журналы работали безупречно… Наконец-то!

Теперь, когда все улажено, и мой эскиз ожидает в моем целевом сегменте, я запустил свой браузер, набрал http://s3-thumb-inputresized.s3.amazonaws.com/resized-HappyFace.jpg (в соответствии с документацией виртуального хостинга S3). Я нажимаю Enter, ожидая взамен красивого эскиза.

<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>C8BAC3D4EADFF577</RequestId>
  <HostId>PRnGbZ2olpLi2eJ5cYCy0Wqliqq5j1OHGYvj/
          HPmWqnBBWn5EMrfwSIrf2Y1LGfDT/7fgRjl5Io=</HostId>
</Error>

Уже надоело это сообщение «Доступ запрещен»!

Очевидно, хотя мой код и генерирует файл, он не делает его общедоступным (но что хорошего в частном миниатюре, а?)

Покопавшись в документации AWS, я вскоре обнаружил параметр ACL операции putObject, который позволяет опубликовать загруженный файл S3. Надеясь, что это решит все проблемы на планете, я быстро обновил свой код, установив ACL файла на public-read:

                s3.putObject({
                  Bucket: dstBucket,
                  Key: dstKey,
                  Body: data,
                  ContentType: contentType,
                  ACL: 'public-read'
                },
                next);
              }

Сохраните функцию и нажмите Test:

2018-02-04T18:06:40.271Z	12e44f61-19fe-11e8-92e1-3f4fff4227fa
  Unable to resize s3-thumb-input/HappyFace.jpg and upload to
  s3-thumb-inputresized/resized-HappyFace.jpg due to an error:
  AccessDenied: Access Denied

Опять таки?? Ты шутишь, что ли?!

К счастью, на этот раз я знал достаточно, чтобы сразу перейти к Руководству по разрешениям S3, которое сразу же показало, что мне также необходимо иметь разрешение s3:PutObjectAcl в моей политике, чтобы использовать параметр ACL в моем вызове putObject.

Итак, еще один путь к редактору политик, к панели управления IAM и обратно к консоли Lambda.

2018-02-04T18:15:09.670Z	1d8dd7b0-19ff-11e8-afc0-138b93af2c40
  Successfully resized s3-thumb-input/HappyFace.jpg and uploaded to
  s3-thumb-inputresized/resized-HappyFace.jpg

И на этот раз, к моему большому удовлетворению, браузер с радостью показал мне миниатюру моего счастливого лица, когда я ввел в него URL-адрес хостинга http://s3-thumb-inputresized.s3.amazonaws.com/resized-HappyFace.jpg.

В общем, я удовлетворен тем, что наконец смог решить головоломку самостоятельно, сложив все разрозненные части вместе.

Но я не могу не представить, как было бы круто, если бы я мог построить свою Lambda в стиле фристайл, когда AWS самостоятельно позаботится о ролях, разрешениях и многом другом, не заставляя меня бегать вокруг блокировать.

Может, мне стоило с самого начала последовать этому официальному руководству…

… Но, опять же, где в этом веселье ?! :)