#!/usr/bin/env python3 """ Simplified AWS Lambda Deployment Script Uses existing IAM role or creates function without role creation """ import boto3 import zipfile import os import json from botocore.exceptions import ClientError, NoCredentialsError import click class SimpleLambdaDeployer: """Simplified AWS Lambda deployment manager""" def __init__(self, region='us-east-1'): """Initialize the Lambda deployer""" try: self.lambda_client = boto3.client('lambda', region_name=region) self.region = region click.echo(click.style("✓ AWS Lambda Deployer initialized", fg="green")) except NoCredentialsError: click.echo(click.style("✗ AWS credentials not found. Please configure AWS credentials.", fg="red")) exit(1) except Exception as e: click.echo(click.style(f"✗ Error initializing Lambda deployer: {str(e)}", fg="red")) exit(1) def create_deployment_package(self, function_name): """Create deployment package for Lambda function""" try: # Create a temporary directory for the package package_dir = f"lambda_packages/{function_name}" os.makedirs(package_dir, exist_ok=True) # Copy the lambda function lambda_code = """ import json def lambda_handler(event, context): ''' Basic AWS Lambda function example. ''' name = event.get("name", "World") message = f"Hello, {name}! Welcome to AWS Lambda." # Log something print(f"Greeting generated for: {name}") return { "statusCode": 200, "body": message } """ with open(f"{package_dir}/lambda_function.py", "w") as f: f.write(lambda_code) # Create zip file zip_path = f"{package_dir}.zip" with zipfile.ZipFile(zip_path, 'w') as zip_file: zip_file.write(f"{package_dir}/lambda_function.py", "lambda_function.py") click.echo(click.style(f"✓ Created deployment package: {zip_path}", fg="green")) return zip_path except Exception as e: click.echo(click.style(f"✗ Error creating deployment package: {str(e)}", fg="red")) return None def find_existing_role(self): """Try to find an existing Lambda execution role""" try: iam_client = boto3.client('iam') # Try to find common Lambda roles common_roles = [ 'Lambda_Service', # Found in your account 'lambda-execution-role', 'AWSLambdaBasicExecutionRole', 'lambda-role', 'devops-lambda-role' ] for role_name in common_roles: try: response = iam_client.get_role(RoleName=role_name) role_arn = response['Role']['Arn'] click.echo(click.style(f"✓ Found existing role: {role_name}", fg="green")) return role_arn except ClientError: continue # If no common roles found, try to list roles and find one with Lambda permissions try: response = iam_client.list_roles(MaxItems=50) for role in response['Roles']: if 'lambda' in role['RoleName'].lower() or 'execution' in role['RoleName'].lower(): click.echo(click.style(f"✓ Found potential role: {role['RoleName']}", fg="yellow")) return role['Arn'] except ClientError: pass return None except Exception as e: click.echo(click.style(f"⚠ Could not search for existing roles: {str(e)}", fg="yellow")) return None def deploy_lambda_function(self, function_name, zip_path, role_arn=None): """Deploy Lambda function with existing role or default""" try: # Read the zip file with open(zip_path, 'rb') as f: zip_content = f.read() # If no role provided, try to find one if not role_arn: role_arn = self.find_existing_role() # If still no role, use a basic execution role ARN if not role_arn: # Get account ID sts_client = boto3.client('sts') account_id = sts_client.get_caller_identity()['Account'] role_arn = f"arn:aws:iam::{account_id}:role/lambda-execution-role" click.echo(click.style(f"⚠ Using default role ARN: {role_arn}", fg="yellow")) click.echo(click.style("Note: You may need to create this role manually in AWS Console", fg="yellow")) # Check if function exists try: self.lambda_client.get_function(FunctionName=function_name) # Function exists, update it response = self.lambda_client.update_function_code( FunctionName=function_name, ZipFile=zip_content ) click.echo(click.style(f"✓ Updated Lambda function: {function_name}", fg="green")) except ClientError as e: if e.response['Error']['Code'] != 'ResourceNotFoundException': raise # Function doesn't exist, create it try: response = self.lambda_client.create_function( FunctionName=function_name, Runtime='python3.9', Role=role_arn, Handler='lambda_function.lambda_handler', Code={'ZipFile': zip_content}, Description='Python DevOps Lambda function' ) click.echo(click.style(f"✓ Created Lambda function: {function_name}", fg="green")) except ClientError as create_error: if 'InvalidParameterValueException' in str(create_error): click.echo(click.style("✗ Role ARN is invalid. Please create a Lambda execution role manually:", fg="red")) click.echo(click.style("1. Go to AWS IAM Console", fg="blue")) click.echo(click.style("2. Create role with 'Lambda' service", fg="blue")) click.echo(click.style("3. Attach 'AWSLambdaBasicExecutionRole' policy", fg="blue")) click.echo(click.style("4. Use the role ARN in deployment", fg="blue")) return None else: raise return response['FunctionArn'] except ClientError as e: click.echo(click.style(f"✗ Error deploying Lambda function: {str(e)}", fg="red")) return None def test_lambda_function(self, function_name): """Test the deployed Lambda function""" try: test_event = { "name": "Python DevOps" } response = self.lambda_client.invoke( FunctionName=function_name, InvocationType='RequestResponse', Payload=json.dumps(test_event) ) result = json.loads(response['Payload'].read()) click.echo(click.style(f"✓ Lambda test successful: {result['body']}", fg="green")) return True except ClientError as e: click.echo(click.style(f"✗ Error testing Lambda function: {str(e)}", fg="red")) return False @click.command() @click.option('--function-name', default='python-devops-lambda', help='Lambda function name') @click.option('--region', default='us-east-1', help='AWS region') @click.option('--role-arn', help='Existing IAM role ARN for Lambda') def main(function_name, region, role_arn): """Deploy Lambda function to AWS""" click.echo(click.style("🚀 Starting simplified Lambda deployment...", fg="blue", bold=True)) # Initialize deployer deployer = SimpleLambdaDeployer(region) # Create deployment package zip_path = deployer.create_deployment_package(function_name) if not zip_path: return # Deploy function function_arn = deployer.deploy_lambda_function(function_name, zip_path, role_arn) if not function_arn: return # Test function if deployer.test_lambda_function(function_name): click.echo(click.style("✅ Lambda deployment completed successfully!", fg="green", bold=True)) click.echo(click.style(f"Function ARN: {function_arn}", fg="blue")) else: click.echo(click.style("❌ Lambda deployment failed!", fg="red", bold=True)) if __name__ == '__main__': main()