Похоже, проблема заключается в примере реализации функции sendResponse()
, которая используется для отправки пользовательского события завершения ресурса обратно в CloudFormation.Этот метод отвечает за установку идентификатора физического ресурса пользовательского ресурса.Насколько я понимаю, это значение представляет глобально уникальный идентификатор «внешнего ресурса», который управляется функцией Lambda, поддерживающей пользовательский ресурс CloudFormation.
Как видно из CloudFormation's Lambdaпользовательского ресурса "с поддержкой пользователя" , а также в модуле cfn-response
NPM * send()
и встроенном CloudFormation cfn-response
модуле , этоу метода есть поведение по умолчанию для расчета идентификатора физического ресурса, если он не указан в качестве 5-го параметра, и он использует поток журнала CloudWatch Logs, который обрабатывает ведение журнала для обрабатываемого запроса:
var responseBody = JSON.stringify({
...
PhysicalResourceId: context.logStreamName,
...
})
Потому что CloudFormation(или среда выполнения AWS Lambda?) иногда меняет поток журнала на новый, идентификатор физического ресурса, генерируемый sendResponse()
, время от времени неожиданно меняется и сбивает с толку CloudFormation.
Насколько я понимаю,Управляемые объекты CloudFormation иногда необходимо заменить во время обновления (хороший пример: RDS::DBInstance
которая нуждается в замене практически для любых изменений).Политика CloudFormation заключается в том, что если ресурс нуждается в замене, новый ресурс создается во время «этапа обновления», а старый ресурс удаляется во время «этапа очистки».
Поэтому используется стандартный физический идентификатор ресурса sendResponse()
.При расчете процесс выглядит следующим образом:
- Создан стек.
- Создан новый поток журналов для обработки пользовательских журналов ресурсов.
- Лямбда поддержкивызывается функция для создания ресурса, и поведение по умолчанию устанавливает его идентификатор ресурса равным идентификатору потока журнала.
- Через некоторое время
- Стек обновляется новыми параметрами для настраиваемого ресурса.
- Создается новый поток журналов для обработки пользовательских журналов ресурсов с новым идентификатором.
- Вызывается вспомогательная лямбда-функция для обновления ресурса, и поведение по умолчанию устанавливает новый идентификатор ресурса дляновый идентификатор потока журнала.
- CloudFormation понимает, что был создан новый ресурс для замены старого ресурса, и в соответствии сполитике следует удалить старый ресурс во время «этапа очистки».
- CloudFormation достигает «этапа очистки» и отправляет запрос на удаление со старым идентификатором физического ресурса.
Решение, по крайней мере, в моем случае, когда я никогда не «заменяю внешний ресурс», состоит в том, чтобы изготовить уникальный идентификатор для управляемого ресурса, предоставить его в качестве 5-го параметра для процедуры отправки ответа, а затем придерживаться его - продолжать отправлять то же самоеидентификатор физического ресурса, полученный в запросе на обновление, в ответе на обновление.CloudFormation тогда никогда не отправит запрос на удаление во время «этапа очистки».
Моя реализация (в JavaScript) выглядит примерно так:
var resID = event.ResourceProperties.PhysicalResourceId || uuid();
...
sendResponse(event, context, status, resData, resID);
Другая альтернатива - которая, вероятно, будет иметь смыслесли вам действительно необходимо заменить внешний ресурс и вы хотите придерживаться модели CloudFormation для удаления старого ресурса во время очистки - это использовать фактический идентификатор внешнего ресурса в качестве идентификатора физического ресурса, а при получении запроса на удаление - использовать предоставленныйидентификатор физического ресурса для удаления старого внешнего ресурса.Это то, что дизайнеры CloudFormation, вероятно, имели в виду в первую очередь, но их пример реализации по умолчанию вызывает много путаницы - возможно, потому что пример реализации не управляет реальным ресурсом и не имеет функциональности обновления.В CloudFormation также отсутствует документация, объясняющая дизайн и обоснование.