From 525af456b81b101312fb680b3892c48fdbebd4b6 Mon Sep 17 00:00:00 2001 From: Donovan McGillen Date: Thu, 26 Jul 2018 10:18:56 +0100 Subject: [PATCH 1/3] Add task to update function configuration and run during deploy This will update the config for the $LATEST version (not the latest published version) and then, when the function code is updated, the next published version (if publish is set) will get the updated config. --- src/provisdom/boot_lambda.clj | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/provisdom/boot_lambda.clj b/src/provisdom/boot_lambda.clj index e1fec92..02a5dac 100644 --- a/src/provisdom/boot_lambda.clj +++ b/src/provisdom/boot_lambda.clj @@ -59,6 +59,32 @@ (shell cmd-string)) fileset)) +(core/deftask update-function-configuration + [f function-name VAL str "The name you want to assign to the function you are uploading" + r runtime VAL str "The runtime environment for the Lambda function you are uploading" + i role VAL str "The ARN of the IAM role that Lambda assumes when it executes your function" + e handler VAL sym "The function within your code that Lambda calls to begin execution" + d description VAL str "A short, user-defined function description" + t timeout VAL int "The function execution time at which Lambda should terminate the function" + m memory-size VAL int "The amount of memory, in MB, your Lambda function is given" + v vpc-config VAL str "Identifies the list of security group IDs and subnet IDs" + j cli-input-json VAL str "Performs service operation based on the JSON string provided" + g generate-cli-skeleton bool "Prints a sample input JSON to standard output" + _ environment VAL str "The parent object that contains your environment's configuration settings" + _ dead-letter-config VAL str "The parent object that contains the target ARN (Amazon Resource Name) of an Amazon SQS queue or Amazon SNS topic" + _ kms-key-arn VAL str "The Amazon Resource Name (ARN) of the KMS key used to encrypt your function's environment variables" + _ tracing-config VAL str "The parent object that contains your function's tracing settings" + _ revision-id VAL str "Used to ensure you are updating the latest update of the function version or alias"] + (when-not function-name + (throw (Exception. "Required function-name to update function configuration"))) + (core/with-pre-wrap fileset + (let [input-files (core/input-files fileset) + cmd-string (lambda-cmd-string input-files *opts* "update-function-configuration")] + (util/info "Updating lambda function configuration...\n") + (util/info (str cmd-string "\n")) + (shell cmd-string)) + fileset)) + (core/deftask update-function [f function-name VAL str "The name you want to assign to the function you are uploading" l local-file VAL str "The path to the local file of the code you are uploading" @@ -112,7 +138,8 @@ (try ;; throws if function does not exist (shell (format "aws lambda get-function --function-name %s" function-name)) - (apply update-function (mapcat identity (select-task-keys #'update-function opts))) + (comp (apply update-function-configuration (mapcat identity (select-task-keys #'update-function-configuration opts))) + (apply update-function (mapcat identity (select-task-keys #'update-function opts)))) (catch Exception ex (util/info (format "Function %s not found. Creating function..." function-name)) (apply create-function (mapcat identity (select-task-keys #'create-function opts))))))) @@ -135,4 +162,4 @@ out-dir (core/tmp-dir!) out-file (io/file out-dir out-file-name)] (spit out-file file-content) - (core/commit! (core/add-resource fileset out-dir))))) \ No newline at end of file + (core/commit! (core/add-resource fileset out-dir))))) From 2c0ab771bf02b35c725b952af3544e737079279a Mon Sep 17 00:00:00 2001 From: Tim Parish Date: Thu, 23 Sep 2021 17:52:33 +0200 Subject: [PATCH 2/3] Add option to specify function layers --- src/provisdom/boot_lambda.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/provisdom/boot_lambda.clj b/src/provisdom/boot_lambda.clj index 02a5dac..803d761 100644 --- a/src/provisdom/boot_lambda.clj +++ b/src/provisdom/boot_lambda.clj @@ -74,7 +74,8 @@ _ dead-letter-config VAL str "The parent object that contains the target ARN (Amazon Resource Name) of an Amazon SQS queue or Amazon SNS topic" _ kms-key-arn VAL str "The Amazon Resource Name (ARN) of the KMS key used to encrypt your function's environment variables" _ tracing-config VAL str "The parent object that contains your function's tracing settings" - _ revision-id VAL str "Used to ensure you are updating the latest update of the function version or alias"] + _ revision-id VAL str "Used to ensure you are updating the latest update of the function version or alias" + _ layers VAL str "A string containing zero or more function layers specified by their ARNs and separated by a space"] (when-not function-name (throw (Exception. "Required function-name to update function configuration"))) (core/with-pre-wrap fileset From 6e465743d9b3d499b59361fb7558a786a677e4be Mon Sep 17 00:00:00 2001 From: Tim Parish Date: Tue, 28 Sep 2021 22:02:56 +0200 Subject: [PATCH 3/3] Wait for function configuration update to complete It can take a minute according to AWS documentation, so we wait until it's succeeded before continuing and also handle failure and timeout. --- src/provisdom/boot_lambda.clj | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/provisdom/boot_lambda.clj b/src/provisdom/boot_lambda.clj index 803d761..9754dc0 100644 --- a/src/provisdom/boot_lambda.clj +++ b/src/provisdom/boot_lambda.clj @@ -3,6 +3,7 @@ (:require [clojure.string :as str] [clojure.java.io :as io] + [clojure.java.shell :as java-shell] [boot.core :as core] [boot.util :as util])) @@ -34,6 +35,30 @@ [input-files opts command & args] (-> opts (task-opts->cmd-opts input-files) (cmd-opts->string (format "aws lambda %s" command)) (str " " (str/join " " args)))) +(defn- last-lambda-update-status + [function-name] + (let [cmd-string (format "aws lambda get-function-configuration --function-name %s --query \"LastUpdateStatus\" --output text" function-name)] + (util/info (str cmd-string "\n")) + (-> (apply java-shell/sh (str/split cmd-string #" ")) + (:out) + (str/trim)))) + +(defn- await-configuration-update-success + [function-name] + (let [retry-after-seconds 10 + timeout-seconds 90] ; AWS docs say it should complete within a minute; give it a little longer (https://docs.aws.amazon.com/cli/latest/reference/lambda/update-function-configuration.html) + (loop [elapsed-seconds 0] + (when (>= elapsed-seconds timeout-seconds) + (throw (Exception. "Function configuration update did not complete in time\n"))) + (let [status (last-lambda-update-status function-name)] + (case status + "InProgress" (do (util/info "Waiting until lambda function configuration has completed successfully...\n") + (Thread/sleep (* retry-after-seconds 1000)) + (recur (+ elapsed-seconds retry-after-seconds))) + "Failed" (throw (Exception. "Function configuration update failed\n")) + "Successful" (util/info "Function configuration update was successful\n") + (throw (Exception. (str "Unexpected function configuration update status: " status)))))))) + (core/deftask create-function [f function-name VAL str "The name you want to assign to the function you are uploading" r runtime VAL str "The runtime environment for the Lambda function you are uploading" @@ -83,7 +108,8 @@ cmd-string (lambda-cmd-string input-files *opts* "update-function-configuration")] (util/info "Updating lambda function configuration...\n") (util/info (str cmd-string "\n")) - (shell cmd-string)) + (shell cmd-string) + (await-configuration-update-success function-name)) fileset)) (core/deftask update-function