You did a zappa deploy and it failed with
InvalidParameterValueException: An error occurred (InvalidParameterValueException) when calling the CreateFunction operation: The role defined for the function cannot be assumed by Lambda?
You tried to create a lambda with a new handmade role only to be greeted by this cryptic error message. Or you tried to use an already existing role with lambda.
Translating the message: it means you haven’t authorized the lambda service to assume the role, so lambdas can’t use it. So, how do we add that authorization?
- Go to https://console.aws.amazon.com/iam/
- Click roles on the left.
- Click the role you want to use for lambda.
- Click the tab
- Click the button
Edit trust relationship.
- If this lambda is only to be used by lambda, you can just replace the policy by:
- If not, just make sure you add to the
Statement list the statement:
Update trust policy.
In the end you should see something like this:
Want to know when something goes wrong in a lambda? Tired of replicating all your alarm setup for each lambda?
If you just want a simple setup on each lambda that guarantees that you get alerts with enough information to be actionable, zappa-sentry is for you.
You’ll need a sentry project DSN. If you don’t have one or don’t even have an account you can create one for free at https://sentry.io/
How to use?
First, install the zappa-sentry in your lambda’s virtual environment with:
pip install zappa-sentry (if you’re using a
requirements.txt to manage dependencies don’t forget to add
zappa-sentry to it).
Next, setup your sentry DSN as the value of environment variable SENTRY_DSN, either on the zappa_setting.json file or in any of the other methods on https://github.com/miserlou/zappa/#setting-environment-variables
Then you can setup the zappa_sentry.unhandled_exceptions handler.
And that’s all. Deploy your zappa function and you should see any errors appearing on sentry.
Looking to delete old entries from a table because they’ve expired? Want to do it in an elegant way?
I usually like to split this kind of functionality into two different parts: the method that does the deleting and a static method that can be invoked from cron, a celery scheduled task or a django command.
As an example, let’s say we want to delete all the log entries on a system that are over 181 days (6 months) old.
Assuming a model like:
__tablename__ = 'log_entries'
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.String(80))
timestamp = db.Column(db.DateTime, default=datetime.datetime.utcnow)
First we add a method on the model that deletes expired log entries.
expiration_days = 181
limit = datetime.datetime.now() - datetime.timedelta(days=expiration_days)
cls.query.filter(cls.timestamp <= limit).delete()
You’ll notice the use of
@classmethod, that’s needed so we can invoke from the class and not from an object, as I’m doing in the next function (the one that can be called from a celery scheduled task, for instance):
And with this you keep it elegant: all the relevant model relevant information in the model class, so if someone changes the timestamp field to another name, they will only have to change it in the delete_expired method, but you can easily call from somewhere else like a task or command.