Changed project name to be IPTV Manager Service
All checks were successful
AWS Deploy on Push / build (push) Successful in 8m29s
All checks were successful
AWS Deploy on Push / build (push) Successful in 8m29s
This commit is contained in:
@@ -4,7 +4,7 @@ MOCK_AUTH=true/false
|
||||
DB_USER=MyDBUser
|
||||
DB_PASSWORD=MyDBPassword
|
||||
DB_HOST=MyDBHost
|
||||
DB_NAME=iptv_updater
|
||||
DB_NAME=iptv_manager
|
||||
|
||||
FREEDNS_User=MyFreeDNSUsername
|
||||
FREEDNS_Password=MyFreeDNSPassword
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
run: |
|
||||
INSTANCE_IDS=$(aws ec2 describe-instances \
|
||||
--region us-east-2 \
|
||||
--filters "Name=tag:Name,Values=IptvUpdaterStack/IptvUpdaterInstance" \
|
||||
--filters "Name=tag:Name,Values=IptvManagerStack/IptvManagerInstance" \
|
||||
"Name=instance-state-name,Values=running" \
|
||||
--query "Reservations[].Instances[].InstanceId" \
|
||||
--output text)
|
||||
@@ -69,11 +69,11 @@ jobs:
|
||||
--instance-ids "$INSTANCE_ID" \
|
||||
--document-name "AWS-RunShellScript" \
|
||||
--parameters 'commands=[
|
||||
"cd /home/ec2-user/iptv-updater-aws",
|
||||
"cd /home/ec2-user/iptv-manager-service",
|
||||
"git pull",
|
||||
"pip3 install -r requirements.txt",
|
||||
"alembic upgrade head",
|
||||
"sudo systemctl restart iptv-updater"
|
||||
"sudo systemctl restart iptv-manager"
|
||||
]'
|
||||
done
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.11.2
|
||||
rev: v0.11.12
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
||||
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"python.terminal.activateEnvironment": true,
|
||||
"python.terminal.activateEnvInCurrentTerminal": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "charliermarsh.ruff",
|
||||
"ruff.importStrategy": "fromEnvironment",
|
||||
@@ -31,10 +33,13 @@
|
||||
"cluflogo",
|
||||
"clulogo",
|
||||
"cpulogo",
|
||||
"crond",
|
||||
"cronie",
|
||||
"cuflgo",
|
||||
"CUNF",
|
||||
"cunflogo",
|
||||
"cuulogo",
|
||||
"datname",
|
||||
"deadstreams",
|
||||
"delenv",
|
||||
"delogo",
|
||||
@@ -50,6 +55,7 @@
|
||||
"freedns",
|
||||
"fullchain",
|
||||
"gitea",
|
||||
"httpx",
|
||||
"iptv",
|
||||
"isort",
|
||||
"KHTML",
|
||||
@@ -61,7 +67,9 @@
|
||||
"ondelete",
|
||||
"onupdate",
|
||||
"passlib",
|
||||
"PGPASSWORD",
|
||||
"poolclass",
|
||||
"psql",
|
||||
"psycopg",
|
||||
"pycache",
|
||||
"pycodestyle",
|
||||
@@ -82,6 +90,7 @@
|
||||
"testdb",
|
||||
"testpass",
|
||||
"testpaths",
|
||||
"testuser",
|
||||
"uflogo",
|
||||
"umlogo",
|
||||
"usefixtures",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# IPTV Updater AWS
|
||||
# IPTV Manager Service
|
||||
|
||||
An automated IPTV playlist and EPG updater service deployed on AWS infrastructure using CDK.
|
||||
An automated IPTV playlist and EPG manager service deployed on AWS infrastructure using CDK.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -25,7 +25,7 @@ This project provides a service for automatically updating IPTV playlists and El
|
||||
|
||||
```bash
|
||||
git clone <repo-url>
|
||||
cd iptv-updater-aws
|
||||
cd iptv-manager-service
|
||||
```
|
||||
|
||||
2. Copy the example environment file:
|
||||
@@ -145,7 +145,7 @@ scripts/ # Utility scripts for deployment and management
|
||||
The following environment variables are required:
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| ----------------- | ------------------------------------ |
|
||||
| FREEDNS_User | FreeDNS username |
|
||||
| FREEDNS_Password | FreeDNS password |
|
||||
| DOMAIN_NAME | Your domain name |
|
||||
|
||||
@@ -15,7 +15,8 @@ config = context.config
|
||||
if config.config_file_name is not None:
|
||||
fileConfig(config.config_file_name)
|
||||
|
||||
# Setup target metadata for autogenerate support
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
target_metadata = Base.metadata
|
||||
|
||||
# Override sqlalchemy.url with dynamic credentials
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
"""Add priority and in_use fields
|
||||
|
||||
Revision ID: 036879e47172
|
||||
Revises:
|
||||
Create Date: 2025-05-26 19:21:32.285656
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '036879e47172'
|
||||
down_revision: Union[str, None] = None
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
# 1. Create priorities table if not exists
|
||||
if not op.get_bind().engine.dialect.has_table(op.get_bind(), 'priorities'):
|
||||
op.create_table('priorities',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('description', sa.String(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
||||
# 2. Insert default priorities (skip if already exists)
|
||||
op.execute("""
|
||||
INSERT INTO priorities (id, description)
|
||||
VALUES (100, 'High'), (200, 'Medium'), (300, 'Low')
|
||||
ON CONFLICT (id) DO NOTHING
|
||||
""")
|
||||
# Add new columns with temporary nullable=True
|
||||
op.add_column('channels_urls', sa.Column('in_use', sa.Boolean(), nullable=True))
|
||||
op.add_column('channels_urls', sa.Column('priority_id', sa.Integer(), nullable=True))
|
||||
|
||||
# Set default values
|
||||
op.execute("UPDATE channels_urls SET in_use = false, priority_id = 100")
|
||||
|
||||
# Convert to NOT NULL
|
||||
op.alter_column('channels_urls', 'in_use', nullable=False)
|
||||
op.alter_column('channels_urls', 'priority_id', nullable=False)
|
||||
op.create_foreign_key(None, 'channels_urls', 'priorities', ['priority_id'], ['id'])
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint('channels_urls_priority_id_fkey', 'channels_urls', type_='foreignkey')
|
||||
op.drop_column('channels_urls', 'priority_id')
|
||||
op.drop_column('channels_urls', 'in_use')
|
||||
op.drop_table('priorities')
|
||||
# ### end Alembic commands ###
|
||||
79
alembic/versions/95b61a92455a_create_initial_tables.py
Normal file
79
alembic/versions/95b61a92455a_create_initial_tables.py
Normal file
@@ -0,0 +1,79 @@
|
||||
"""create initial tables
|
||||
|
||||
Revision ID: 95b61a92455a
|
||||
Revises:
|
||||
Create Date: 2025-05-29 14:42:16.239587
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '95b61a92455a'
|
||||
down_revision: Union[str, None] = None
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('channels',
|
||||
sa.Column('id', sa.UUID(), nullable=False),
|
||||
sa.Column('tvg_id', sa.String(), nullable=False),
|
||||
sa.Column('name', sa.String(), nullable=False),
|
||||
sa.Column('group_title', sa.String(), nullable=False),
|
||||
sa.Column('tvg_name', sa.String(), nullable=True),
|
||||
sa.Column('tvg_logo', sa.String(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('group_title', 'name', name='uix_group_title_name')
|
||||
)
|
||||
op.create_table('priorities',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('description', sa.String(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('channels_urls',
|
||||
sa.Column('id', sa.UUID(), nullable=False),
|
||||
sa.Column('channel_id', sa.UUID(), nullable=False),
|
||||
sa.Column('url', sa.String(), nullable=False),
|
||||
sa.Column('in_use', sa.Boolean(), nullable=False),
|
||||
sa.Column('priority_id', sa.Integer(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['channel_id'], ['channels.id'], ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['priority_id'], ['priorities.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
# Seed initial priorities
|
||||
op.bulk_insert(
|
||||
sa.Table(
|
||||
'priorities',
|
||||
sa.MetaData(),
|
||||
sa.Column('id', sa.Integer),
|
||||
sa.Column('description', sa.String),
|
||||
),
|
||||
[
|
||||
{'id': 100, 'description': 'High'},
|
||||
{'id': 200, 'description': 'Medium'},
|
||||
{'id': 300, 'description': 'Low'},
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# Remove seeded priorities
|
||||
op.execute("DELETE FROM priorities WHERE id IN (100, 200, 300);")
|
||||
|
||||
# Drop tables
|
||||
op.drop_table('channels_urls')
|
||||
op.drop_table('priorities')
|
||||
op.drop_table('channels')
|
||||
6
app.py
6
app.py
@@ -3,7 +3,7 @@ import os
|
||||
|
||||
import aws_cdk as cdk
|
||||
|
||||
from infrastructure.stack import IptvUpdaterStack
|
||||
from infrastructure.stack import IptvManagerStack
|
||||
|
||||
app = cdk.App()
|
||||
|
||||
@@ -31,9 +31,9 @@ if missing_vars:
|
||||
f"Missing required environment variables: {', '.join(missing_vars)}"
|
||||
)
|
||||
|
||||
IptvUpdaterStack(
|
||||
IptvManagerStack(
|
||||
app,
|
||||
"IptvUpdaterStack",
|
||||
"IptvManagerStack",
|
||||
freedns_user=freedns_user,
|
||||
freedns_password=freedns_password,
|
||||
domain_name=domain_name,
|
||||
|
||||
@@ -15,8 +15,8 @@ async def lifespan(app: FastAPI):
|
||||
|
||||
app = FastAPI(
|
||||
lifespan=lifespan,
|
||||
title="IPTV Updater API",
|
||||
description="API for IPTV Updater service",
|
||||
title="IPTV Manager API",
|
||||
description="API for IPTV Manager service",
|
||||
version="1.0.0",
|
||||
)
|
||||
|
||||
@@ -60,7 +60,7 @@ app.openapi = custom_openapi
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
return {"message": "IPTV Updater API"}
|
||||
return {"message": "IPTV Manager API"}
|
||||
|
||||
|
||||
# Include routers
|
||||
|
||||
@@ -19,16 +19,16 @@ def get_db_credentials():
|
||||
|
||||
ssm = boto3.client("ssm", region_name=AWS_REGION)
|
||||
try:
|
||||
host = ssm.get_parameter(Name="/iptv-updater/DB_HOST", WithDecryption=True)[
|
||||
host = ssm.get_parameter(Name="/iptv-manager/DB_HOST", WithDecryption=True)[
|
||||
"Parameter"
|
||||
]["Value"]
|
||||
user = ssm.get_parameter(Name="/iptv-updater/DB_USER", WithDecryption=True)[
|
||||
user = ssm.get_parameter(Name="/iptv-manager/DB_USER", WithDecryption=True)[
|
||||
"Parameter"
|
||||
]["Value"]
|
||||
password = ssm.get_parameter(
|
||||
Name="/iptv-updater/DB_PASSWORD", WithDecryption=True
|
||||
Name="/iptv-manager/DB_PASSWORD", WithDecryption=True
|
||||
)["Parameter"]["Value"]
|
||||
dbname = ssm.get_parameter(Name="/iptv-updater/DB_NAME", WithDecryption=True)[
|
||||
dbname = ssm.get_parameter(Name="/iptv-manager/DB_NAME", WithDecryption=True)[
|
||||
"Parameter"
|
||||
]["Value"]
|
||||
return f"postgresql://{user}:{password}@{host}/{dbname}"
|
||||
|
||||
@@ -3,10 +3,11 @@ version: '3.8'
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:13
|
||||
container_name: postgres
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: iptv_updater
|
||||
POSTGRES_DB: iptv_manager
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
|
||||
@@ -6,7 +6,7 @@ services:
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: iptv_updater
|
||||
POSTGRES_DB: iptv_manager
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
@@ -20,7 +20,7 @@ services:
|
||||
DB_USER: postgres
|
||||
DB_PASSWORD: postgres
|
||||
DB_HOST: postgres
|
||||
DB_NAME: iptv_updater
|
||||
DB_NAME: iptv_manager
|
||||
MOCK_AUTH: "true"
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
@@ -9,7 +9,7 @@ from aws_cdk import aws_ssm as ssm
|
||||
from constructs import Construct
|
||||
|
||||
|
||||
class IptvUpdaterStack(Stack):
|
||||
class IptvManagerStack(Stack):
|
||||
def __init__(
|
||||
self,
|
||||
scope: Construct,
|
||||
@@ -27,7 +27,7 @@ class IptvUpdaterStack(Stack):
|
||||
# Create VPC
|
||||
vpc = ec2.Vpc(
|
||||
self,
|
||||
"IptvUpdaterVPC",
|
||||
"IptvManagerVPC",
|
||||
max_azs=2, # Need at least 2 AZs for RDS subnet group
|
||||
nat_gateways=0, # No NAT Gateway to stay in free tier
|
||||
subnet_configuration=[
|
||||
@@ -44,7 +44,7 @@ class IptvUpdaterStack(Stack):
|
||||
|
||||
# Security Group
|
||||
security_group = ec2.SecurityGroup(
|
||||
self, "IptvUpdaterSG", vpc=vpc, allow_all_outbound=True
|
||||
self, "IptvManagerSG", vpc=vpc, allow_all_outbound=True
|
||||
)
|
||||
|
||||
security_group.add_ingress_rule(
|
||||
@@ -66,18 +66,18 @@ class IptvUpdaterStack(Stack):
|
||||
"Allow PostgreSQL traffic for tunneling",
|
||||
)
|
||||
|
||||
# Key pair for IPTV Updater instance
|
||||
# Key pair for IPTV Manager instance
|
||||
key_pair = ec2.KeyPair(
|
||||
self,
|
||||
"IptvUpdaterKeyPair",
|
||||
key_pair_name="iptv-updater-key",
|
||||
"IptvManagerKeyPair",
|
||||
key_pair_name="iptv-manager-key",
|
||||
public_key_material=ssh_public_key,
|
||||
)
|
||||
|
||||
# Create IAM role for EC2
|
||||
role = iam.Role(
|
||||
self,
|
||||
"IptvUpdaterRole",
|
||||
"IptvManagerRole",
|
||||
assumed_by=iam.ServicePrincipal("ec2.amazonaws.com"),
|
||||
)
|
||||
|
||||
@@ -114,7 +114,7 @@ class IptvUpdaterStack(Stack):
|
||||
# EC2 Instance
|
||||
instance = ec2.Instance(
|
||||
self,
|
||||
"IptvUpdaterInstance",
|
||||
"IptvManagerInstance",
|
||||
vpc=vpc,
|
||||
vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PUBLIC),
|
||||
instance_type=ec2.InstanceType.of(
|
||||
@@ -132,7 +132,7 @@ class IptvUpdaterStack(Stack):
|
||||
|
||||
# Option: 2: Create Elastic IP (not free tier compatible)
|
||||
# eip = ec2.CfnEIP(
|
||||
# self, "IptvUpdaterEIP",
|
||||
# self, "IptvManagerEIP",
|
||||
# domain="vpc",
|
||||
# instance_id=instance.instance_id
|
||||
# )
|
||||
@@ -140,8 +140,8 @@ class IptvUpdaterStack(Stack):
|
||||
# Add Cognito User Pool
|
||||
user_pool = cognito.UserPool(
|
||||
self,
|
||||
"IptvUpdaterUserPool",
|
||||
user_pool_name="iptv-updater-users",
|
||||
"IptvManagerUserPool",
|
||||
user_pool_name="iptv-manager-users",
|
||||
self_sign_up_enabled=False, # Only admins can create users
|
||||
password_policy=cognito.PasswordPolicy(
|
||||
min_length=8,
|
||||
@@ -156,7 +156,7 @@ class IptvUpdaterStack(Stack):
|
||||
|
||||
# Add App Client with the correct callback URL
|
||||
client = user_pool.add_client(
|
||||
"IptvUpdaterClient",
|
||||
"IptvManagerClient",
|
||||
access_token_validity=Duration.minutes(60),
|
||||
id_token_validity=Duration.minutes(60),
|
||||
refresh_token_validity=Duration.days(1),
|
||||
@@ -171,8 +171,8 @@ class IptvUpdaterStack(Stack):
|
||||
|
||||
# Add domain for hosted UI
|
||||
domain = user_pool.add_domain(
|
||||
"IptvUpdaterDomain",
|
||||
cognito_domain=cognito.CognitoDomainOptions(domain_prefix="iptv-updater"),
|
||||
"IptvManagerDomain",
|
||||
cognito_domain=cognito.CognitoDomainOptions(domain_prefix="iptv-manager"),
|
||||
)
|
||||
|
||||
# Read the userdata script with proper path resolution
|
||||
@@ -226,7 +226,7 @@ class IptvUpdaterStack(Stack):
|
||||
# Create RDS PostgreSQL instance (free tier compatible - db.t3.micro)
|
||||
db = rds.DatabaseInstance(
|
||||
self,
|
||||
"IptvUpdaterDB",
|
||||
"IptvManagerDB",
|
||||
engine=rds.DatabaseInstanceEngine.postgres(
|
||||
version=rds.PostgresEngineVersion.VER_13
|
||||
),
|
||||
@@ -240,7 +240,7 @@ class IptvUpdaterStack(Stack):
|
||||
security_groups=[rds_sg],
|
||||
allocated_storage=10,
|
||||
max_allocated_storage=10,
|
||||
database_name="iptv_updater",
|
||||
database_name="iptv_manager",
|
||||
removal_policy=RemovalPolicy.DESTROY,
|
||||
deletion_protection=False,
|
||||
publicly_accessible=False, # Avoid public IPv4 charges
|
||||
@@ -255,25 +255,25 @@ class IptvUpdaterStack(Stack):
|
||||
ssm.StringParameter(
|
||||
self,
|
||||
"DBHostParam",
|
||||
parameter_name="/iptv-updater/DB_HOST",
|
||||
parameter_name="/iptv-manager/DB_HOST",
|
||||
string_value=db.db_instance_endpoint_address,
|
||||
)
|
||||
ssm.StringParameter(
|
||||
self,
|
||||
"DBNameParam",
|
||||
parameter_name="/iptv-updater/DB_NAME",
|
||||
string_value="iptv_updater",
|
||||
parameter_name="/iptv-manager/DB_NAME",
|
||||
string_value="iptv_manager",
|
||||
)
|
||||
ssm.StringParameter(
|
||||
self,
|
||||
"DBUserParam",
|
||||
parameter_name="/iptv-updater/DB_USER",
|
||||
parameter_name="/iptv-manager/DB_USER",
|
||||
string_value=db.secret.secret_value_from_json("username").to_string(),
|
||||
)
|
||||
ssm.StringParameter(
|
||||
self,
|
||||
"DBPassParam",
|
||||
parameter_name="/iptv-updater/DB_PASSWORD",
|
||||
parameter_name="/iptv-manager/DB_PASSWORD",
|
||||
string_value=db.secret.secret_value_from_json("password").to_string(),
|
||||
)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Update system and install required packages
|
||||
dnf update -y
|
||||
dnf install -y python3-pip git cronie nginx certbot python3-certbot-nginx
|
||||
dnf install -y python3-pip git cronie nginx certbot python3-certbot-nginx postgresql awscli
|
||||
|
||||
# Start and enable crond service
|
||||
systemctl start crond
|
||||
@@ -11,27 +11,48 @@ systemctl enable crond
|
||||
cd /home/ec2-user
|
||||
|
||||
git clone ${REPO_URL}
|
||||
cd iptv-updater-aws
|
||||
cd iptv-manager-service
|
||||
|
||||
# Install Python packages with --ignore-installed to prevent conflicts with RPM packages
|
||||
pip3 install --ignore-installed -r requirements.txt
|
||||
|
||||
# Retrieve DB credentials from SSM Parameter Store
|
||||
export DB_HOST=$(aws ssm get-parameter --name "/iptv-manager/DB_HOST" --query "Parameter.Value" --output text)
|
||||
export DB_NAME=$(aws ssm get-parameter --name "/iptv-manager/DB_NAME" --query "Parameter.Value" --output text)
|
||||
export DB_USER=$(aws ssm get-parameter --name "/iptv-manager/DB_USER" --query "Parameter.Value" --output text)
|
||||
export DB_PASSWORD=$(aws ssm get-parameter --name "/iptv-manager/DB_PASSWORD" --query "Parameter.Value" --output text)
|
||||
|
||||
# Set PGPASSWORD for psql to use
|
||||
export PGPASSWORD=$DB_PASSWORD
|
||||
|
||||
# Wait for PostgreSQL to be ready
|
||||
echo "Waiting for PostgreSQL to start..."
|
||||
until psql -h $DB_HOST -U $DB_USER -d postgres -c '\q'; do
|
||||
sleep 1
|
||||
done
|
||||
echo "PostgreSQL is ready."
|
||||
|
||||
# Create database if it does not exist
|
||||
DB_EXISTS=$(psql -h $DB_HOST -U $DB_USER -d postgres -tc "SELECT 1 FROM pg_database WHERE datname = '$DB_NAME';")
|
||||
if [ -z "$DB_EXISTS" ]; then
|
||||
echo "Creating database $DB_NAME..."
|
||||
psql -h $DB_HOST -U $DB_USER -d postgres -c "CREATE DATABASE $DB_NAME;"
|
||||
echo "Database $DB_NAME created."
|
||||
fi
|
||||
|
||||
# Run database migrations
|
||||
alembic upgrade head
|
||||
|
||||
# Seed initial priorities
|
||||
python3 -c "from app.utils.database import SessionLocal; from app.models.db import Priority; db = SessionLocal(); db.add_all([Priority(id=100, description='High'), Priority(id=200, description='Medium'), Priority(id=300, description='Low')]); db.commit()"
|
||||
|
||||
# Create systemd service file
|
||||
cat << 'EOF' > /etc/systemd/system/iptv-updater.service
|
||||
cat << 'EOF' > /etc/systemd/system/iptv-manager.service
|
||||
[Unit]
|
||||
Description=IPTV Updater Service
|
||||
Description=IPTV Manager Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=ec2-user
|
||||
WorkingDirectory=/home/ec2-user/iptv-updater-aws
|
||||
WorkingDirectory=/home/ec2-user/iptv-manager-service
|
||||
ExecStart=/usr/local/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000
|
||||
EnvironmentFile=/etc/environment
|
||||
Restart=always
|
||||
@@ -56,7 +77,7 @@ sudo mkdir -p /etc/nginx/ssl
|
||||
--reloadcmd "service nginx force-reload"
|
||||
|
||||
# Create nginx config
|
||||
cat << EOF > /etc/nginx/conf.d/iptvUpdater.conf
|
||||
cat << EOF > /etc/nginx/conf.d/iptvManager.conf
|
||||
server {
|
||||
listen 80;
|
||||
server_name ${DOMAIN_NAME} *.${DOMAIN_NAME};
|
||||
@@ -83,5 +104,5 @@ EOF
|
||||
# Start nginx service
|
||||
systemctl enable nginx
|
||||
systemctl start nginx
|
||||
systemctl enable iptv-updater
|
||||
systemctl start iptv-updater
|
||||
systemctl enable iptv-manager
|
||||
systemctl start iptv-manager
|
||||
@@ -5,12 +5,21 @@ python_functions = test_*
|
||||
asyncio_mode = auto
|
||||
filterwarnings =
|
||||
ignore::DeprecationWarning:botocore.auth
|
||||
ignore:The 'app' shortcut is now deprecated:DeprecationWarning:httpx._client
|
||||
|
||||
# Coverage configuration
|
||||
addopts =
|
||||
--cov=app
|
||||
--cov-report=term-missing
|
||||
|
||||
# Test environment variables
|
||||
env =
|
||||
MOCK_AUTH=true
|
||||
DB_USER=test_user
|
||||
DB_PASSWORD=test_password
|
||||
DB_HOST=localhost
|
||||
DB_NAME=iptv_manager_test
|
||||
|
||||
# Test markers
|
||||
markers =
|
||||
slow: mark tests as slow running
|
||||
|
||||
@@ -15,3 +15,7 @@ alembic==1.16.1
|
||||
pytest==8.1.1
|
||||
pytest-asyncio==0.23.6
|
||||
pytest-mock==3.12.0
|
||||
pytest-cov==4.1.0
|
||||
pytest-env==1.1.1
|
||||
httpx==0.27.0
|
||||
pre-commit
|
||||
@@ -25,7 +25,7 @@ cdk deploy --app="python3 ${PWD}/app.py"
|
||||
# Update application on running instances
|
||||
INSTANCE_IDS=$(aws ec2 describe-instances \
|
||||
--region us-east-2 \
|
||||
--filters "Name=tag:Name,Values=IptvUpdaterStack/IptvUpdaterInstance" \
|
||||
--filters "Name=tag:Name,Values=IptvManagerStack/IptvManagerInstance" \
|
||||
"Name=instance-state-name,Values=running" \
|
||||
--query "Reservations[].Instances[].InstanceId" \
|
||||
--output text)
|
||||
@@ -35,7 +35,7 @@ for INSTANCE_ID in $INSTANCE_IDS; do
|
||||
aws ssm send-command \
|
||||
--instance-ids "$INSTANCE_ID" \
|
||||
--document-name "AWS-RunShellScript" \
|
||||
--parameters '{"commands":["cd /home/ec2-user/iptv-updater-aws && git pull && pip3 install -r requirements.txt && alembic upgrade head && sudo systemctl restart iptv-updater"]}' \
|
||||
--parameters '{"commands":["cd /home/ec2-user/iptv-manager-service && git pull && pip3 install -r requirements.txt && alembic upgrade head && sudo systemctl restart iptv-manager"]}' \
|
||||
--no-cli-pager \
|
||||
--no-paginate
|
||||
done
|
||||
|
||||
@@ -11,9 +11,3 @@ pre-commit autoupdate
|
||||
|
||||
# Verify pytest setup
|
||||
python3 -m pytest
|
||||
|
||||
# Initialize and run database migrations
|
||||
alembic upgrade head
|
||||
|
||||
# Seed initial data
|
||||
python3 -c "from app.utils.database import SessionLocal; from app.models.db import Priority; db = SessionLocal(); db.add_all([Priority(id=100, description='High'), Priority(id=200, description='Medium'), Priority(id=300, description='Low')]); db.commit()"
|
||||
@@ -1,21 +1,26 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Start PostgreSQL
|
||||
docker-compose -f docker/docker-compose-db.yml up -d
|
||||
|
||||
# Set mock auth and database environment variables
|
||||
# Set environment variables
|
||||
export MOCK_AUTH=true
|
||||
export DB_HOST=localhost
|
||||
export DB_USER=postgres
|
||||
export DB_PASSWORD=postgres
|
||||
export DB_HOST=localhost
|
||||
export DB_NAME=iptv_updater
|
||||
export DB_NAME=iptv_manager
|
||||
|
||||
echo "Ensuring database $DB_NAME exists using conditional DDL..."
|
||||
PGPASSWORD=$DB_PASSWORD docker exec -i postgres psql -U $DB_USER <<< "SELECT 'CREATE DATABASE $DB_NAME' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$DB_NAME')\gexec"
|
||||
echo "Database $DB_NAME check complete."
|
||||
|
||||
# Run database migrations
|
||||
alembic upgrade head
|
||||
|
||||
# Start FastAPI
|
||||
nohup uvicorn app.main:app --host 127.0.0.1 --port 8000 > app.log 2>&1 &
|
||||
echo $! > iptv-updater.pid
|
||||
echo $! > iptv-manager.pid
|
||||
|
||||
echo "Services started:"
|
||||
echo "- PostgreSQL running on localhost:5432"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Stop FastAPI
|
||||
if [ -f iptv-updater.pid ]; then
|
||||
kill $(cat iptv-updater.pid)
|
||||
rm iptv-updater.pid
|
||||
if [ -f iptv-manager.pid ]; then
|
||||
kill $(cat iptv-manager.pid)
|
||||
rm iptv-manager.pid
|
||||
echo "Stopped FastAPI"
|
||||
fi
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ def test_root_endpoint(client):
|
||||
"""Test root endpoint returns expected message"""
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"message": "IPTV Updater API"}
|
||||
assert response.json() == {"message": "IPTV Manager API"}
|
||||
|
||||
|
||||
def test_openapi_schema_generation(client):
|
||||
|
||||
Reference in New Issue
Block a user