Skip to content

Python sample application #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions sample-apps/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Python Demo Sample App Updating Guide

## Introduction:

The python sample app is used to perform E2E testing on cloudwatch, cloudwatch operator and adot repository. If any changes need to be made on the demo sample app, the following steps should be taken.

## EKS Use Case: Uploading to ECR

### Build the sample app locally:
run `docker-compose build` to generate two docker images: `pythonsampleapp/frontend-service` and `pythonsampleapp/remote-service`

### Steps to update image:
1. Login to the testing account
2. Create a new ECR repository if there's no existing one.
3. Login to ECR Repository: `aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin {REPOSITORY}`.
4. tag images and push to repository:
```
docker tag pythonsampleapp/frontend-service:latest ${REPOSITORY_PREFIX}/pythonsampleapp/frontend-service:latest
docker push ${REPOSITORY_PREFIX}/pythonsampleapp/frontend-service:latest
docker tag pythonsampleapp/remote-service:latest ${REPOSITORY_PREFIX}/pythonsampleapp/remote-service:latest
docker push ${REPOSITORY_PREFIX}/pythonsampleapp/remote-service:latest
```


## EC2 Use Case: Building the JAR Files:
1. Compress the folder with: `zip -r python-sample-app.zip .`
2. Login to the testing account
3. Create a new S3 bucket if there's no existing one.
4. upload `python-sample-app.zip` to the bucket


## APIs
The following are the APIs supported:
1. http://${ FRONTEND_SERVICE_IP }:8000/outgoing-http-call/
2. http://${ FRONTEND_SERVICE_IP }:8000/aws-sdk-call/
3. http://${ FRONTEND_SERVICE_IP }:8000/remote-service?ip=${ REMOTE_SERVICE_IP }/
4. http://${ FRONTEND_SERVICE_IP }:8000/client-call/
5 changes: 5 additions & 0 deletions sample-apps/python/django_frontend_service/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
static
.idea
.env
db.sqlite3
*.iml
19 changes: 19 additions & 0 deletions sample-apps/python/django_frontend_service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0

# Use an official Python runtime as a parent image
FROM python:3.10

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# Set the working directory
WORKDIR /django_frontend_app

# Install dependencies
COPY django_frontend_service/requirements.txt /django_frontend_app/
RUN pip install -r requirements.txt

# Copy the project code into the container
COPY django_frontend_service/. /django_frontend_app/
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
import os

from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_frontend_service.settings")

application = get_asgi_application()
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
import os
from pathlib import Path
from dotenv import load_dotenv

load_dotenv()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-!=+@($z#-ylp@au_@ey=9nh701y-p@_n-^c23k_&ia!o8catit"

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ["*"]


# Application definition
# settings.py
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]

MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]

ROOT_URLCONF = "django_frontend_service.urls"

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]

WSGI_APPLICATION = "django_frontend_service.wsgi.application"


# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases

DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}


# Password validation
# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]


# Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/

LANGUAGE_CODE = "en-us"

TIME_ZONE = "UTC"

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/

STATIC_URL = "static/"
STATIC_ROOT = os.path.join(BASE_DIR, "static")

# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
from django.urls import path
from frontend_service_app import views

urlpatterns = [
path('', views.healthcheck),
path('aws-sdk-call', views.aws_sdk_call),
path('outgoing-http-call', views.http_call),
path('remote-service', views.downstream_service),
path('client-call', views.async_service),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_frontend_service.settings")

application = get_wsgi_application()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
from django.apps import AppConfig


class FrontendServiceAppConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "frontend_service_app"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
from django.http import HttpResponse, JsonResponse
import boto3
import logging
import requests
import schedule
import time
import threading
from opentelemetry import trace
from opentelemetry.trace.span import format_trace_id

logger = logging.getLogger(__name__)

should_send_local_root_client_call = False
lock = threading.Lock()
def run_local_root_client_call_recurring_service():
def runnable_task():
global should_send_local_root_client_call
with lock:
if should_send_local_root_client_call:
should_send_local_root_client_call = False
try:
response = requests.get("http://local-root-client-call")
# Handle the response if needed
except Exception as e:
# Handle exceptions
pass

# Schedule the task to run every 1 second
schedule.every(1).seconds.do(runnable_task)

# Run the scheduler in a separate thread
def run_scheduler():
while True:
schedule.run_pending()
time.sleep(0.1) # Sleep to prevent high CPU usage

thread = threading.Thread(target=run_scheduler)
thread.daemon = True # Daemonize the thread so it exits when the main thread exits
thread.start()

run_local_root_client_call_recurring_service()

def healthcheck(request):
return HttpResponse("healthcheck")

def aws_sdk_call(request):
bucket_name = "e2e-test-bucket-name"
s3_client = boto3.client("s3")

try:
s3_client.get_bucket_location(
Bucket=bucket_name,
)
except Exception as e:
logger.error("Could not retrieve http request:" + str(e))

return get_xray_trace_id()

def http_call(request):
url = "https://www.amazon.com"
try:
response = requests.get(url)
status_code = response.status_code
logger.info("outgoing-http-call status code: " + str(status_code))
except Exception as e:
logger.error("Could not complete http request:" + str(e))
return get_xray_trace_id()

def downstream_service(request):
ip = request.GET.get('ip', '')
ip = ip.replace("/", "")
url = f"http://{ip}:8001/health-check"
try:
response = requests.get(url)
status_code = response.status_code
logger.info("Remote service call status code: " + str(status_code))
return get_xray_trace_id()
except Exception as e:
logger.error("Could not complete http request to remote service:" + str(e))

return get_xray_trace_id()

def async_service(request):
global should_send_local_root_client_call
# Log the request
logger.info("Client-call received")
# Set the condition to trigger the recurring service
with lock:
should_send_local_root_client_call = True
# Return a dummy traceId in the response
return JsonResponse({'traceId': '1-00000000-000000000000000000000000'})

def get_xray_trace_id():
span = trace.get_current_span()
trace_id = format_trace_id(span.get_span_context().trace_id)
xray_trace_id = f"1-{trace_id[:8]}-{trace_id[8:]}"

return JsonResponse({"traceId": xray_trace_id})
23 changes: 23 additions & 0 deletions sample-apps/python/django_frontend_service/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python
## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
## SPDX-License-Identifier: Apache-2.0
import os
import sys


def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_frontend_service.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)


if __name__ == "__main__":
main()
7 changes: 7 additions & 0 deletions sample-apps/python/django_frontend_service/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Django~=4.2.9
requests~=2.31.0
boto3~=1.34.3
requests~=2.31.0
schedule~=1.2.1
python-dotenv~=1.0.0
opentelemetry-api~=1.22.0
5 changes: 5 additions & 0 deletions sample-apps/python/django_remote_service/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
static
.idea
.env
db.sqlite3
*.iml
Loading