J'essaie de mettre à jour Redshift à partir d'une fonction Lambda en utilisant python. Pour ce faire, j'essaye de combiner 2 fragments de code. Les deux fragments sont fonctionnels lorsque je les exécute séparément.
Mise à jour de Redshift depuis PyDev pour Eclipse
import psycopg2
conn_string = "dbname='name' port='0000' user='name' password='pwd' Host='url'"
conn = psycopg2.connect(conn_string)
cursor = conn.cursor()
cursor.execute("UPDATE table SET attribute='new'")
conn.commit()
cursor.close()
Réception de contenu téléchargé dans le compartiment S3 (modèle prédéfini disponible sur Lambda)
from __future__ import print_function
import json
import urllib
import boto3
print('Loading function')
s3 = boto3.client('s3')
def lambda_handler(event, context):
#print("Received event: " + json.dumps(event, indent=2))
# Get the object from the event and show its content type
bucket = event['Records'][0]['s3']['bucket']['name']
key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')
try:
response = s3.get_object(Bucket=bucket, Key=key)
print("CONTENT TYPE: " + response['ContentType'])
return response['ContentType']
except Exception as e:
print(e)
print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
raise e
Puisque ces deux segments fonctionnaient, j'ai essayé de les combiner afin de pouvoir mettre à jour Redshift lors du téléchargement d'un fichier vers s3:
from __future__ import print_function
import json
import urllib
import boto3
import psycopg2
print('Loading function')
s3 = boto3.client('s3')
def lambda_handler(event, context):
#print("Received event: " + json.dumps(event, indent=2))
# Get the object from the event and show its content type
bucket = event['Records'][0]['s3']['bucket']['name']
key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')
conn_string = "dbname='name' port='0000' user='name' password='pwd' Host='url'"
conn = psycopg2.connect(conn_string)
cursor = conn.cursor()
cursor.execute("UPDATE table SET attribute='new'")
conn.commit()
cursor.close()
try:
response = s3.get_object(Bucket=bucket, Key=key)
print("CONTENT TYPE: " + response['Body'].read())
return response['Body'].read()
except Exception as e:
print(e)
print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
raise e
Étant donné que j'utilise une bibliothèque externe, je dois créer un package de déploiement. J'ai créé un nouveau dossier (lambda_function1) et déplacé mon fichier .py (lambda_function1.py) dans ce dossier. J'ai exécuté la commande suivante pour installer psycopg2 dans ce dossier:
pip install psycopg2 -t \lambda_function1
Je reçois les commentaires suivants:
Collecting psycopg2
Using cached psycopg2-2.6.1-cp34-none-win_AMD64.whl
Installing collected packages: psycopg2
Successfully installed psycopg2-2.6.1
J'ai ensuite zippé le contenu du répertoire. Et téléchargé ce Zip sur ma fonction lambda. Lorsque je télécharge un document dans le compartiment surveillé par la fonction, je reçois l'erreur suivante dans mon journal cloudwatch:
Unable to import module 'lambda_function1': No module named _psycopg
Quand je regarde dans la bibliothèque, la seule chose nommée "_psycopg" est "_psycopg.pyd".
Quelle est la cause de ce problème? Est-il important que Lambda utilise Python 2.7 lorsque j'utilise 3.4? Est-il important que j'ai compressé le contenu de mon fichier sur une machine Windows? Quelqu'un a-t-il réussi à se connecter à Redshift à partir de lambda?
Pour que cela fonctionne, vous devez créer psycopg2
Avec la bibliothèque libpq.so
Liée statiquement. Découvrez ce dépôt https://github.com/jkehler/awslambda-psycopg2 . Il a déjà construit le paquet psycopg2 et des instructions pour le construire vous-même.
Retour à vos questions:
Quelle est la cause de ce problème?
psycopg2
Doit être compilé et compilé avec des bibliothèques liées statiquement pour Linux.
Est-il important que Lambda utilise Python 2.7 lorsque j'utilise 3.4?
Oui, lambda ne prend en charge que la version 2.7. Créez simplement un environnement virtuel et installez-y tous les packages nécessaires.
Est-il important que j'ai compressé le contenu de mon fichier sur une machine Windows?
Tant que toutes les bibliothèques que vous avez compressées peuvent fonctionner sous Linux, cela ne fonctionne pas
Quelqu'un a-t-il réussi à se connecter à Redshift à partir de lambda?
oui.
Je viens de rencontrer ce même problème. Je suis tombé sur le même projet github qui a été noté dans l'autre réponse qui expliquait le problème comme suit:
En raison d'AWS Lambda manquant les bibliothèques PostgreSQL requises dans l'image AMI, nous avions besoin de compiler psycopg2 avec la bibliothèque libpq.so de PostgreSQL libpq liée statiquement à la place du lien dynamique par défaut.
Cela a été noté dans la réponse précédente, et j'ai commencé à suivre les instructions pour créer moi-même une version de psycopg2 avec une bibliothèque PostgreSQL liée statiquement. J'ai trouvé une option beaucoup plus simple. J'ai remarqué sur la page github psycopg2 ce qui suit:
Vous pouvez également obtenir un package autonome, ne nécessitant pas de compilateur ou de bibliothèques externes, en installant le package psycopg2-binary de PyPI:
$ pip install psycopg2-binary
Le package binaire est un choix pratique pour le développement et les tests mais en production, il est conseillé d'utiliser le package construit à partir des sources.
Lorsque j'ai installé le paquet psycopg2-binary et l'ai inclus dans mon fichier requirements.txt, j'ai pu me connecter sans problème à ma base de données postgresql à partir d'une fonction lambda. J'utilise calice que je recommande fortement. Je me rends compte que psycopg2 recommande de ne pas utiliser la version binaire pour la production, mais je ne vois pas de différence énorme entre l'utilisation de la version binaire ou la compilation et la liaison statique vous-même. Quelqu'un, s'il vous plaît, corrigez-moi si je me trompe.
Pour utiliser psycopg2 avec aws lambda, utilisez import aws-psycopg2
Comme aws prend en charge psycopg2, mais la façon d'importer psycopg2 est un peu différente car aws a lui-même une bibliothèque compilée pour psycopg2, nous devons donc importer en utilisant aws-psycopg2
Une autre façon d'utiliser psycopg2 sur lambda (si vous programmez sur windows et utilisez python 3.6 sur lambda)
oh mec! alors que certaines des réponses peuvent être vraiment géniales et fonctionnent! Je suis juste tombé sur cela https://pypi.org/project/aws-psycopg2/ et cela a fonctionné comme un charme pour moi. pas :
mkdir aws-psycopg2
cd aws-psycopg2
vi get_layer_packages.sh
export PKG_DIR="python"
rm -rf ${PKG_DIR} && mkdir -p ${PKG_DIR}
docker run --rm -v $(pwd):/foo -w /foo lambci/lambda:build-python3.6 \
pip install -r requirements.txt --no-deps -t ${PKG_DIR}
vi requirements.txt
aws-psycopg2
puis faites: chmod + x get_layer_packages.sh
./get_layer_packages.sh
Zip -r aws-psycopg2.Zip.
téléchargez ce Zip sur la couche AWS Lambda!
En supposant que votre emballage est correct, le no module named psycopg2
L'erreur indique généralement que le ou les fichiers binaires de votre déploiement psycopg2 sont incorrects pour votre système d'exploitation cible ou Python.
Pour Lambdas, nous avons trouvé que le binaire psycopg2 fonctionne (en utilisant manylinux_x86_64). Il existe un risque signalé de segfault en raison de la présence de binaires libssl bien que nous ne les ayons pas encore. (il s'agit essentiellement d'un +1 pour la réponse de jshammon ci-dessus)
La "bonne solution" est probablement jkehlers recompiler spécifiquement pour Lambda manquant seulement lib_pq.so
, mais il ne supporte pas actuellement ssl + py3.7 et nous sommes trop Windows pour le recompiler nous-mêmes.