import boto3 import time import subprocess import platform import paramiko import string import random REGION = 'us-east-1' # -------------------------------------------------- # ----------------- AWS Connection ----------------- # -------------------------------------------------- def check_aws_connection(): try: s3 = boto3.client('s3') s3.list_buckets() print('AWS connection success.') except Exception as e: print(f'Error: {e}') print('AWS connection failed.') check_aws_connection() # -------------------------------------------------- # --------------- Utility functions ---------------- # -------------------------------------------------- def get_public_dns_name(inst): client = boto3.client('ec2', region_name=REGION) response = client.describe_instances(InstanceIds = [inst.id]) return response['Reservations'][0]['Instances'][0]['NetworkInterfaces'][0]['Association']['PublicDnsName'] def get_private_dns_name(inst): client = boto3.client('ec2', region_name=REGION) response = client.describe_instances(InstanceIds = [inst.id]) return response['Reservations'][0]['Instances'][0]['NetworkInterfaces'][0]['PrivateDnsName'] def random_string(length): letters = string.ascii_lowercase return ''.join(random.choice(letters) for i in range(length)) # -------------------------------------------------- # ----------------- Create key pair ---------------- # -------------------------------------------------- def create_key_pair(key_name): ec2 = boto3.client('ec2', region_name=REGION) key_pair = ec2.create_key_pair(KeyName=key_name) with open(f'{key_name}.pem', 'w') as file: file.write(key_pair['KeyMaterial']) return key_pair # -------------------------------------------------- # ------------------ Networking -------------------- # -------------------------------------------------- def get_default_vpc(): ec2 = boto3.client('ec2', region_name=REGION) response = ec2.describe_vpcs() vpc_id = response['Vpcs'][0]['VpcId'] return vpc_id def create_vpc(): ec2 = boto3.resource('ec2', region_name=REGION) vpc = ec2.create_vpc(CidrBlock='172.31.0.0/16') vpc.modify_attribute(EnableDnsSupport={'Value': True}) vpc.modify_attribute(EnableDnsHostnames={'Value': True}) igw = ec2.create_internet_gateway() vpc.attach_internet_gateway(InternetGatewayId=igw.id) return vpc, igw def create_subnet(vpc, cidr_block, availability_zone): subnet = vpc.create_subnet( CidrBlock=cidr_block, AvailabilityZone=availability_zone ) route_table = vpc.create_route_table() route_table.associate_with_subnet(SubnetId=subnet.id) route_table.create_route( DestinationCidrBlock='0.0.0.0/0', GatewayId=igw.id ) return subnet, route_table def create_security_group(vpc, group_name, description): ec2 = boto3.resource('ec2', region_name=REGION) security_group = ec2.create_security_group( GroupName=group_name, Description=description, VpcId=vpc.id ) security_group.authorize_ingress( CidrIp='0.0.0.0/0', IpProtocol='tcp', FromPort=22, ToPort=22 ) security_group.authorize_ingress( CidrIp='0.0.0.0/0', IpProtocol='tcp', FromPort=80, ToPort=80 ) security_group.authorize_ingress( CidrIp='0.0.0.0/0', IpProtocol='tcp', FromPort=443, ToPort=443 ) security_group.authorize_ingress( CidrIp='172.31.0.0/16', IpProtocol='tcp', FromPort=5432, ToPort=5432 ) return security_group # -------------------------------------------------- # ------------ AWS Machine reservation ------------- # -------------------------------------------------- def create_ec2_instance(ami_id, instance_name, security_group_id, subnet_id, key_pair, with_volume=False): ec2 = boto3.resource('ec2', region_name=REGION) instance = ec2.create_instances( ImageId=ami_id, InstanceType='t2.micro', MinCount=1, MaxCount=1, NetworkInterfaces=[{ 'SubnetId': subnet_id, 'DeviceIndex': 0, 'AssociatePublicIpAddress': True, 'DeleteOnTermination': True, 'Groups': [security_group_id] }], TagSpecifications=[{'ResourceType': 'instance', 'Tags': [{'Key': 'Name', 'Value': instance_name}]}], KeyName=key_pair['KeyName'] )[0] instance.wait_until_running() if with_volume: volume = ec2.create_volume( AvailabilityZone=instance.placement['AvailabilityZone'], Size=8, VolumeType='gp2', TagSpecifications=[{'ResourceType': 'volume', 'Tags': [{'Key': 'Name', 'Value': f'{instance_name}-volume'}]}] ) counter = 10 while counter > 0: time.sleep(5) try: instance.attach_volume( Device='/dev/sdf', VolumeId=volume.id ) break except Exception as e: if (counter == 1): print(f"Error: {e}") counter -= 1 return instance if __name__ == "__main__": try: ami_id = 'ami-0ee3dd41c47751fe6' # Create a VPC print("[Stage 1/8] Creating VPC...") vpc, igw = create_vpc() # Create security group for the instances print("[Stage 2/8] Creating security group...") security_group = create_security_group(vpc, 'GiteaSecurityGroup', 'Gitea Security Group') # Create subnets within the VPC for each instance print("[Stage 3/8] Creating subnets...") subnet, route_table = create_subnet(vpc, '172.31.2.0/16', REGION + 'a') # Create a key pair for SSH access print("[Stage 4/8] Creating key pair...") key_pair = create_key_pair('gitea-key') # Create two EC2 instances within their respective subnets print("[Stage 5/8] Creating EC2 instances (POSTGRES)...") postgres_instance = create_ec2_instance(ami_id, 'PostgresInstance', security_group.group_id, subnet.id, key_pair) print("[Stage 6/8] Creating EC2 instances (GITEA)...") gitea_instance = create_ec2_instance(ami_id, 'GiteaInstance', security_group.group_id, subnet.id, key_pair, True) # Get public DNS of the instances gitea_public_dns = get_public_dns_name(gitea_instance) postgres_public_dns = get_public_dns_name(postgres_instance) postgres_private_dns = postgres_instance.private_dns_name # Print public DNS of the instances print(f"Postgres instance public DNS: {postgres_public_dns}") print(f"Gitea instance public DNS: {gitea_public_dns}") db_password = random_string(16) # ssh into the instance and install PostgreSQL print("[Stage 7/8] Configuring Postgres instance...") counter = 5 while counter > 0: try: print(f"Trying to connect to {postgres_public_dns}...") ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh_client.connect(postgres_public_dns, username='ec2-user', key_filename=f'{key_pair["KeyName"]}.pem') break except Exception as e: print(f"Error: {e}") print("Retrying...") time.sleep(5) counter -= 1 print("Connected to Postgres instance.") stdin, stdout, stderr = ssh_client.exec_command('sudo yum update -y') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo yum install -y docker') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo service docker start') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo mkdir postgres-dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo touch postgres-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo chmod 777 postgres-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo echo "FROM postgres:latest" >> postgres-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo echo "ENV POSTGRES_USER gitea" >> postgres-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command(f'sudo echo "ENV POSTGRES_PASSWORD {db_password}" >> postgres-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo echo "ENV POSTGRES_DB gitea" >> postgres-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo docker build -t postgres postgres-dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command(f'sudo docker run -d -p 5432:5432 postgres') # Configure gitea instance print("[Stage 8/8] Configuring Gitea instance...") counter = 5 while counter > 0: try: print(f"Trying to connect to {gitea_public_dns}...") ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh_client.connect(gitea_public_dns, username='ec2-user', key_filename=f'{key_pair["KeyName"]}.pem') break except Exception as e: print(f"Error: {e}") print("Retrying...") time.sleep(5) counter -= 1 print("Connected to Gitea instance.") stdin, stdout, stderr = ssh_client.exec_command('sudo yum update -y') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo mkfs.ext4 /dev/xvdf') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo mkdir /data') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo mount /dev/xvdf /data') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo mkdir /data/gitea') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo yum install -y docker') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo service docker start') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo mkdir gitea-dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo touch gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo chmod 777 gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo echo "FROM gitea/gitea:latest" >> gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo echo "ENV GITEA__database__DB_TYPE postgres" >> gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command(f'sudo echo "ENV GITEA__database__HOST {postgres_private_dns}:5432" >> gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo echo "ENV GITEA__database__NAME gitea" >> gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo echo "ENV GITEA__database__USER gitea" >> gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command(f'sudo echo "ENV GITEA__database__PASSWD {db_password}" >> gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo echo "ENV GITEA__server__APP_DATA_PATH /data/gitea" >> gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo echo "RUN mkdir -p /data/gitea" >> gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo echo "EXPOSE 3000" >> gitea-dockerfile/Dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo docker build -t gitea gitea-dockerfile') print(stdout.read().decode()) stdin, stdout, stderr = ssh_client.exec_command('sudo docker run -d -p 80:3000 -v /data/gitea:/data gitea') print(stdout.read().decode()) print("Gitea and Postgres instances are ready to use.") print(f"Website is available at: http://{gitea_public_dns}") finally: # Wait for user input to destroy resources input("Press Enter to destroy resources...") # Cleanup resources if 'gitea_instance' in locals(): print("Terminating Gitea instance...") gitea_instance.terminate() gitea_instance.wait_until_terminated() if 'postgres_instance' in locals(): print("Terminating Postgres instance...") postgres_instance.terminate() postgres_instance.wait_until_terminated() if 'subnet' in locals(): print("Deleting subnet...") subnet.delete() if 'route_table' in locals(): print("Deleting route table...") route_table.delete() if 'security_group' in locals(): print("Deleting security group...") security_group.delete() if 'igw' in locals(): print("Detaching and deleting Internet Gateway...") igw.detach_from_vpc(VpcId=vpc.id) igw.delete() if 'vpc' in locals(): print("Deleting VPC...") vpc.delete() if 'key_pair' in locals(): print("Deleting key pair...") client = boto3.client('ec2', region_name=REGION) client.delete_key_pair(KeyName=key_pair['KeyName']) print("Resources destroyed.")