Skip to content

Commit

Permalink
Merge branch 'main' into unittest-Attributes-Generator
Browse files Browse the repository at this point in the history
  • Loading branch information
XinRanZhAWS authored Feb 2, 2024
2 parents e49f4e0 + 8e3078b commit bbf9dd7
Show file tree
Hide file tree
Showing 25 changed files with 459 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
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

Expand Down Expand Up @@ -78,8 +82,12 @@

DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
"ENGINE": "django.db.backends.postgresql",
"USER": os.environ.get("POSTGRES_USER"),
"NAME": os.environ.get("POSTGRES_DATABASE"),
"PASSWORD": os.environ.get("POSTGRES_PASSWORD"),
"HOST": os.environ.get("DB_SERVICE_HOST"),
"PORT": os.environ.get("DB_SERVICE_PORT"),
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Django~=5.0
requests~=2.31.0
boto3~=1.34.14
python-dotenv~=1.0.0
python-dotenv~=1.0.0
psycopg2~=2.9.9
38 changes: 18 additions & 20 deletions sample-applications/vehicle-dealership-sample-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ This directory contains code for a microservices based sample app that is used t

### EKS
To get started with AWS EKS, you can run the one touch script as below.
`bash script.sh <account_id> <cluster_name> <region> <mysql_password> <s3_bucket_name>`
`bash script.sh <account_id> <cluster_name> <region> <postgres_password> <s3_bucket_name>`

This will create the docker images, upload them to ECR and then create pods on EKS with those images.

Expand Down Expand Up @@ -52,7 +52,7 @@ To deploy to EC2, you will have to go through the following steps.
- AmazonS3FullAccess
- AmazonSQSFullAccess
- Name one vehicle-service and the other image-service
5. Go to RDS and create a MySQL DB with the following configurations:
5. Go to RDS and create a Postgres DB with the following configurations:
- Use the Dev/Test template
- Update the Master username to `root` and create a password of your choosing. Write it down since you will need it later.
- In the Connectivity settings, choose the VPC and security group created in step 3.
Expand All @@ -61,18 +61,15 @@ To deploy to EC2, you will have to go through the following steps.
```
sudo dnf install python3.11
sudo dnf install python3.11-pip
sudo dnf install mariadb105
sudo dnf install -y mariadb105-devel gcc python3.11-devel
sudo dnf install postgresql15
mysql -h <RDS_DB_Endpoint> -P 3306 -u root -p<password_from_step_5>
createdb vehicle_inventory -h <rds_url> -U root
createuser djangouser -h <rds_url> -U root
CREATE DATABASE vehicle_inventory;
psql -h <rds_url> -d vehicle_inventory -U root
CREATE USER 'djangouser'@'%' IDENTIFIED BY '<password_of_your_choosing>';
GRANT ALL PRIVILEGES ON vehicle_inventory.* TO 'djangouser'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
alter user djangouser with encrypted password '<password_of_your_choosing>';
grant all privileges on database vehicle_inventory to djangouser;
aws s3 sync s3://<s3_bucket_that_has_python_code> .
Expand All @@ -81,18 +78,19 @@ cd to the vehicle microservice directory and run:
python3.11 -m pip install -r requirements.txt
Create a .env file with the following:
MYSQL_ROOT_PASSWORD=<password_from_RDS_setup>
MYSQL_DATABASE=vehicle_inventory
MYSQL_USER=djangouser
MYSQL_PASSWORD=<password_from_this_step>
POSTGRES_ROOT_PASSWORD=<password_from_RDS_setup>
POSTGRES_DATABASE=vehicle_inventory
POSTGRES_USER=djangouser
POSTGRES_PASSWORD=<password_from_this_step>
DB_SERVICE_HOST=<RDS_DB_endpoint>
DB_SERVICE_PORT=3306
IMAGE_BACKEND_SERVICE_HOST=<image-service_ec2_public_IP>
IMAGE_BACKEND_SERVICE_PORT=8000
python3.11 manage.py migrate --noinput && python3.11 manage.py runserver 0.0.0.0:8001
```
7. Connect to the `image-service` EC2 instance and run the following:
7. Go to the EC2 console and select the `image-service`, Go Actions -> Networking -> Connect RDS database.
8. Connect to the `image-service` EC2 instance and run the following:
```
sudo dnf install python3.11
sudo dnf install python3.11-pip
Expand All @@ -113,18 +111,18 @@ Now you should be able to access the APIs below through the EC2 addr:port of eac

### Locally with Docker
To get started, make sure you either have you AWS creds in `$HOME/.aws` or the following: `AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN` are exported.
1. Run `bash local_script.sh <mysql_pass> <s3_bucket_name>`.
1. Run `bash local_script.sh <postgres_pass> <s3_bucket_name>`.
This will create docker containers, move the requirement env variables there and start them up.

They should be accessible through `0.0.0.0:8000` for the image service and `0.0.0.0:8001` for the vehicle service.

## APIs

The following are the APIs and what they do:
1. GET /vehicle-inventory/: returns all the vehicles entries for mysql db
2. PUT /vehicle-inventory/: puts vehicle into db. For example: `curl -X POST http://0.0.0.0:8001/vehicle-inventory/ -d '{"make": "BMW","model": "M340","year": 2022,"image_name": "newCar.jpg"}'`
1. GET /vehicle-inventory/: returns all the vehicles entries for postgres db
2. POST /vehicle-inventory/: puts vehicle into db. For example: `curl -X POST http://0.0.0.0:8001/vehicle-inventory/ -d '{"make": "BMW","model": "M340","year": 2022,"image_name": "newCar.jpg"}'`
3. GET /vehicle-inventory/<int>: returns vehicle entry with id = <int>
4. GET /vehicle-inventory/<int>/image: returns image file information from S3 for the specific vehicle by calling the image microservice
5. GET /images/name/<image_name>: returns image information for <image_name> from S3 if present.
6. PUT /images/name/<image_name>: creates an empty file in S3. This is an async endpoint since it will put image name in an SQS queue and not wait for the file to be created in S3. Instead, a long running thread will poll SQS and then create the image file later.
6. POST /images/name/<image_name>: creates an empty file in S3. This is an async endpoint since it will put image name in an SQS queue and not wait for the file to be created in S3. Instead, a long running thread will poll SQS and then create the image file later.
7. GET /image/remote-image: makes a remote http call to google.com.
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
path("", views.vehicle, name="vehicle"),
path("<int:vehicle_id>", views.get_vehicle_by_id, name="get_vehicle_by_id"),
path("<int:vehicle_id>/image", views.get_vehicle_image, name="get_vehicle_image"),
path("image/<str:image_name>", views.get_image_by_name, name="image_by_name"),
]
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
# SPDX-License-Identifier: Apache-2.0
import json
import os
import time

import requests
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed, HttpResponseNotFound
from django.views.decorators.csrf import csrf_exempt
from dotenv import load_dotenv
from MainService.models import Vehicle
Expand All @@ -27,8 +28,7 @@ def vehicle(request):
make=body["make"], model=body["model"], year=body["year"], image_name=body["image_name"]
)
vehicle_object.save()
print(get_image_endpoint() + "/images/name/" + body["image_name"])
requests.post(get_image_endpoint() + "/images/name/" + body["image_name"], timeout=10)
requests.post(build_image_url(body["image_name"]), timeout=10)
return HttpResponse("VehicleId = " + str(vehicle_object.id))
except KeyError as exception:
return HttpResponseBadRequest("Missing key: " + str(exception))
Expand All @@ -40,14 +40,38 @@ def vehicle(request):

def get_vehicle_by_id(request, vehicle_id):
if request.method == "GET":
throttle_time = request.GET.get("throttle")
if throttle_time:
print("going to throttle for " + throttle_time + " seconds")
time.sleep(int(throttle_time))

vehicle_objects = Vehicle.objects.filter(id=vehicle_id).values()
if not vehicle_objects:
return HttpResponseNotFound("Vehicle with id=" + str(vehicle_id) + " is not found")
return HttpResponse(vehicle_objects)
return HttpResponseNotAllowed("Only GET requests are allowed!")


def get_vehicle_image(request, vehicle_id):
if request.method == "GET":
vehicle_object = Vehicle.objects.filter(id=vehicle_id).first()
if not vehicle_object:
return HttpResponseNotFound("Vehicle with id=" + str(vehicle_id) + " is not found")
image_name = getattr(vehicle_object, "image_name")
return HttpResponse(requests.get(get_image_endpoint() + "/images/name/" + image_name, timeout=10))
return HttpResponse(requests.get(build_image_url(image_name), timeout=10))
return HttpResponseNotAllowed("Only GET requests are allowed!")


@csrf_exempt
def get_image_by_name(request, image_name):
print(image_name)
if request.method == "GET":
response = requests.get(build_image_url(image_name), timeout=10)
if response.ok:
return HttpResponse(response)
return HttpResponseNotFound("Image with name: " + image_name + " is not found")
return HttpResponseNotAllowed("Only GET requests are allowed!")


def build_image_url(image_name):
return get_image_endpoint() + "/images/name/" + image_name
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@

DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"USER": os.environ.get("MYSQL_USER"),
"NAME": os.environ.get("MYSQL_DATABASE"),
"PASSWORD": os.environ.get("MYSQL_PASSWORD"),
"ENGINE": "django.db.backends.postgresql",
"USER": os.environ.get("POSTGRES_USER"),
"NAME": os.environ.get("POSTGRES_DATABASE"),
"PASSWORD": os.environ.get("POSTGRES_PASSWORD"),
"HOST": os.environ.get("DB_SERVICE_HOST"),
"PORT": os.environ.get("DB_SERVICE_PORT"),
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Django~=5.0
requests~=2.31.0
mysqlclient~=2.2.1
psycopg2~=2.9.9
python-dotenv~=1.0.0
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@
version: '3'
services:
db:
image: mysql:8.0
image: postgres:14.0
container_name: vehicle_inventory_db
restart: always
volumes:
- data:/var/lib/mysql
- data:/var/lib/postgres
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
POSTGRES_DB: ${POSTGRES_DATABASE}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
PGUSER: ${POSTGRES_USER}
ports:
- "3306:3306"
- "5432:5432"
healthcheck:
test: ["CMD", "mysql", "-h", "localhost", "-u", "root", "-p${MYSQL_PASSWORD}", "-e", "SELECT 1"]
test: ["CMD", "pg_isready", "-d", "vehicle_inventory", "-U", "djangouser"]
timeout: 20s
retries: 10
expose:
- 3306
- 5432

vehicle-inventory-backend:
image: pythonsampleapp/vehicle-inventory-service
Expand All @@ -44,13 +44,17 @@ services:
context: .
dockerfile: ImageServiceApp/Dockerfile
container_name: image-service-backend
command: sh -c "python3 manage.py migrate --noinput && python3 manage.py collectstatic --noinput && python3 manage.py runserver 0.0.0.0:8000"
command: sh -c "python3 manage.py runserver 0.0.0.0:8000"
restart: always
volumes:
- ./ImageServiceApp/.:/image-service-app
- $HOME/.aws/credentials:/home/app/.aws/credentials:ro
ports:
- "8000:8000"
depends_on:
db:
condition: service_healthy

volumes:
data:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,11 @@ spec:
image: ${REPOSITORY_PREFIX}/pythonsampleapp/vehicle-inventory-service:latest
name: vehicle-inventory-backend
env:
- name: MYSQL_DATABASE
- name: POSTGRES_DATABASE
value: vehicle_inventory
- name: MYSQL_PASSWORD
value: ${MYSQL_PASSWORD}
- name: MYSQL_ROOT_PASSWORD
value: ${MYSQL_PASSWORD}
- name: MYSQL_USER
- name: POSTGRES_PASSWORD
value: ${POSTGRES_PASSWORD}
- name: POSTGRES_USER
value: djangouser
imagePullPolicy: Always
ports:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,36 +29,31 @@ spec:
spec:
containers:
- env:
- name: MYSQL_DATABASE
- name: POSTGRES_DB
value: vehicle_inventory
- name: MYSQL_PASSWORD
value: ${MYSQL_PASSWORD}
- name: MYSQL_ROOT_PASSWORD
value: ${MYSQL_PASSWORD}
- name: MYSQL_USER
- name: POSTGRES_PASSWORD
value: ${POSTGRES_PASSWORD}
- name: POSTGRES_USER
value: djangouser
image: mysql:8.0
image: postgres:14.0
livenessProbe:
exec:
command:
- mysql
- -h
- localhost
- -u
- root
- -p${MYSQL_PASSWORD}
- -e
- SELECT 1
- pg_isready
- -d
- vehicle_inventory
- -U
- djangouser
failureThreshold: 10
timeoutSeconds: 20
name: vehicle-inventory-db
ports:
- containerPort: 3306
hostPort: 3306
- containerPort: 5432
hostPort: 5432
protocol: TCP
resources: {}
volumeMounts:
- mountPath: /var/lib/mysql
- mountPath: /var/lib/postgres
name: data
restartPolicy: Always
volumes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ metadata:
name: db
spec:
ports:
- port: 3306
- port: 5432
selector:
io.kompose.service: db
status:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ spec:
- args:
- sh
- -c
- python3 manage.py migrate --noinput; python3 manage.py collectstatic --noinput; python3 manage.py runserver 0.0.0.0:8000
- python3 manage.py runserver 0.0.0.0:8000
image: ${REPOSITORY_PREFIX}/pythonsampleapp/image-service:latest
name: image-service-backend
imagePullPolicy: Always
Expand All @@ -43,5 +43,11 @@ spec:
env:
- name: S3_BUCKET
value: ${S3_BUCKET}
- name: POSTGRES_DATABASE
value: vehicle_inventory
- name: POSTGRES_PASSWORD
value: ${POSTGRES_PASSWORD}
- name: POSTGRES_USER
value: djangouser
restartPolicy: Always
status: {}
Loading

0 comments on commit bbf9dd7

Please sign in to comment.