Как установить модуль Python mariadb в среде Amazon Linux - PullRequest
0 голосов
/ 06 августа 2020

Моя цель - создать AWS Lambda Layer для предоставления модуля mariadb для AWS Lambdas запущенных python 3.8.

Следуя этим инструкциям , чтобы сделать это, я необходимо установить модуль mariadb на экземпляр, совместимый с платформой AWS Lambda. Установка модуля вот так ...

python3 -m pip install mariadb --target lambda-layer/python/lib/python3.8/site-packages

... выдает сообщение об ошибке ...

mariadb_config not found.
Please make sure, that MariaDB Connector/C is installed on your system, edit the
configuration file 'site.cfg' and set the 'mariadb_config'
noption, which should point to the mariadb_config utility.

Что мне нужно исправить?

Я предполагаю, что установка «MariaDB Connector / C» является обязательным условием? Но как это сделать? и как это сделать, чтобы его можно было упаковать в zip-архив, который можно использовать для определения AWS лямбда-слоя?

Некоторый контекст

Я запустил это на Amazon экземпляр, который, как мне кажется, совпадает с хостами Lamba, а именно «Amazon Linux AMI 2018.03.0 (HVM), тип тома SSD - ami-02769748522663066». cat /etc/os-release возвращает ...

NAME="Amazon Linux AMI"
VERSION="2018.03"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2018.03"
PRETTY_NAME="Amazon Linux AMI 2018.03"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2018.03:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"

Будет ли другой экземпляр AMI лучше для упаковки python3 .8 лямбда-слоя?

И я установил python3 с этим ( Коробка не имеет в галерее python 3.8):

sudo yum install python36 -y

Обновление и самостоятельный ответ

Итак, краткий ответ заключается в том, что в настоящее время это невозможно. Коннектор MariaDb не поддерживает версию Amazon linux. Однако есть альтернативная библиотека python, Py MySQL, которая будет подключаться к серверам mariadb.

Вот содержимое python3 .8 AWS лямбда-функции, которая производит AWS Function Layers for Lambda.

The Factory (AWS Lambda) Function

import json, boto3
from pathlib import Path
import os, sys, subprocess, shutil
from zipfile import ZipFile

def run( commandLine, captures, workingDir):
  options = {}
  if workingDir is not None:
    options['cwd'] = workingDir
  if 'standard-output' in captures:
    options['stdout'] = subprocess.PIPE
  if 'error-output' in captures:
    options['stderr'] = subprocess.PIPE
  proc = subprocess.run( commandLine, **options)
  outputLines = None
  errorLines  = None
  if 'standard-output' in captures:
    outputLines = proc.stdout.decode('UTF-8').strip().split( os.linesep)
  if 'error-output' in captures:
    errorLines = proc.stderr.decode('UTF-8').strip().split( os.linesep)
  if outputLines == ['']:
    outputLines = None
  if errorLines == ['']:
    errorLines = None
  return proc.returncode, outputLines, errorLines


def lambda_handler(event, context):
    request = json.loads( event['body'])
    sitePackages = '/tmp/aws-lambda-layer/lambda-layer/python/lib/python3.8/site-packages'
    Path( sitePackages).mkdir(parents=True, exist_ok=True)
    lines = request['requirements']
    print( lines)
    bucket      = request['bucket']
    packageKey  = request['key']
    ExtraArgs   = request.get('ExtraArgs')
    layerName   = request['layer-name']
    licenceInfo = request.get('license-info')
    requiresFN  = '/tmp/aws-lambda-layer/requirements.txt'
    origin      = os.environ.get( 'ORIGIN', '*')
    with open( requiresFN, 'w') as file: 
      file.writelines( lines)
    returncode, outputLines, errorLines = run(
      [sys.executable, '-m', 'pip', 'install', '-r', requiresFN, '--target',  sitePackages],
      ['standard-output','error-output'], '/tmp/aws-lambda-layer')
    base  = '/tmp/aws-lambda-layer/lambda-layer'
    zipFN = '/tmp/aws-lambda-layer/package.zip'
    l = len( base) + 1
    with ZipFile( zipFN, 'w') as package:
      for folderName, subfolders, filenames in os.walk( base):
        for filename in filenames:
          filePath = os.path.join( folderName, filename)
          path = filePath[l:]
          if os.path.basename( filePath) != 'yum.log':
            package.write( filePath, path)
    if ExtraArgs is None:
      ExtraArgs = {}
    ExtraArgs['ContentType'] = 'application/zip'
    runtime_region = os.environ.get('AWS_REGION')
    parms = {}
    if runtime_region is not None:
      parms['region_name'] = runtime_region
    s3Client     = boto3.client( 's3'    , **parms)
    lambdaClient = boto3.client( 'lambda', **parms)
    s3Client.upload_file( zipFN, bucket, packageKey, ExtraArgs)
    try:
      shutil.rmtree( '/tmp/aws-lambda-layer', ignore_errors=True) 
    except:
      print( 'Errors in cleaning up /tmp/aws-lambda-layer')
    description = 'python 3.8 requirements:' + '\n'.join( lines)
    parms = {'LayerName'  : layerName,
             'Description': description,
             'Content': { 'S3Bucket': bucket, 'S3Key': packageKey},
             'CompatibleRuntimes': ['python3.8']}
    if licenceInfo is not None:
      parms['LicenseInfo'] = licenceInfo
    try:
      response = lambdaClient.publish_layer_version( **parms)
      response = response['layer']['LayerVersionArn']
    except:
      print('Error in publishing.')
      response = None
    try:
      lambdaClient.delete_object( Bucket=bucket, Key=packageKey)
    except:
      print( 'Failure to delete s3 staging package.')
    statusCode = 200
    response = {'pip-return-code': returncode, 'out': outputLines,
                'err': errorLines, 'layer': response}
    ret = {'statusCode': statusCode,
           'body': json.dumps( response),
           'headers': {
             'Content-Type': 'application/json',
             'Access-Control-Allow-Credentials': 'true',
             'Access-Control-Allow-Origin': origin}}
    return ret

На стороне клиента это может быть вызвано (снова python скрипт) следующим образом ... Заводская функция выполняет требования python pip freeze и производит слой, который обслуживает указанные модули. В моем случае файл requirements.txt будет включать Py MySQL.

import json
import boto3

# Config section. Adapt as required.
lambdaRegion = 'ap-southeast-2'
bucket = 'some-bucket'
key    = 'provisioning-workspace/layer-package.zip'
layerName = 'someLayerName'
filenm = 'some-path\\requirements.txt'
functionName = 'layer-factory-p38'
# End config section. 

parms = {}
if lambdaRegion is not None:
  parms['region_name'] = lambdaRegion

client = boto3.client( 'lambda', **parms)

def invoke( functionName, qualifier, inData):
  parms = {'FunctionName'  : functionName,
           'InvocationType': 'RequestResponse',
           'LogType'       : 'None',
           'Payload'       : str.encode( json.dumps( {'body': json.dumps( inData)}))}
  if qualifier is not None:
    parms['Qualifier'] = str( qualifier)
  response = client.invoke( **parms)
  response = json.loads( response['Payload'].read().decode('utf-8'))
  try:
    statusCode = int( response['statusCode'])
  except:
    statusCode = 0
  try:
    response = json.loads( response['body'])
  except:
    print( response)
    response = {}
  return statusCode, response

def buildLayer( factoryFunctionName, requirementsFN, layerName, bucket, key):
  with open( requirementsFN, 'r') as file: 
    lines = file.readlines()
  statusCode, response = invoke( factoryFunctionName, None, {
    'requirements': lines, 'bucket': bucket, 'key': key, 'layer-name': layerName})
  return response['layer']

layerArn = buildLayer( functionName, filenm, layerName, bucket, key)
print( layerArn)
...