Skip to content

Python sample app #2

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

Closed
wants to merge 3 commits into from
Closed
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/
2 changes: 2 additions & 0 deletions sample-apps/python/django_frontend_service/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
AWS_ACCESS_KEY_ID=ASIAQDILVRR2AIVYUKLD
AWS_SECRET_ACCESS_KEY=VSGS05QNQ5MDjtQuSNtfYNVsHo9MxsfL55YqU1x5
16 changes: 16 additions & 0 deletions sample-apps/python/django_frontend_service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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/
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for django_frontend_service project.

It exposes the ASGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/
"""

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,125 @@
"""
Django settings for django_frontend_service project.

Generated by 'django-admin startproject' using Django 5.0.1.

For more information on this file, see
https://docs.djangoproject.com/en/5.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.0/ref/settings/
"""

import os
from pathlib import Path

# 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,10 @@
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,16 @@
"""
WSGI config for django_frontend_service project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/
"""

import os

from django.core.wsgi import get_wsgi_application

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

application = get_wsgi_application()
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
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,3 @@
from django.db import models

# Create your models here.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from django.http import HttpResponse, JsonResponse
import boto3
import logging
import requests
import schedule
import time
from threading import Thread
from opentelemetry import trace
from opentelemetry.trace.span import format_trace_id

logger = logging.getLogger(__name__)

should_send_local_root_client_call = False
def run_local_root_client_call_recurring_service():
def runnable_task():
global should_send_local_root_client_call
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 = 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 HttpResponse(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 HttpResponse(get_xray_trace_id())

def downstream_service(request):
ip = request.GET.get('ip', '')
print("ip!!!!!!!!!!!!!")
print(ip)
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 HttpResponse(get_xray_trace_id())
except Exception as e:
logger.error("Could not complete http request to remote service:" + str(e))

return HttpResponse(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
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 = "1-" + trace_id[:8] + "-" + trace_id[8:]

return "traceId : " + xray_trace_id
22 changes: 22 additions & 0 deletions sample-apps/python/django_frontend_service/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
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()
6 changes: 6 additions & 0 deletions sample-apps/python/django_frontend_service/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Django~=4.2.9
requests~=2.31.0
boto3~=1.34.3
requests~=2.31.0
schedule~=1.2.1
opentelemetry-api~=1.22.0
16 changes: 16 additions & 0 deletions sample-apps/python/django_remote_service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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_remote_app

# Install dependencies
COPY django_remote_service/requirements.txt /django_remote_app/
RUN pip install -r requirements.txt

# Copy the project code into the container
COPY django_remote_service/. /django_remote_app/
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading