From 055bb25d6b39ae349ecf73eebbac18bf81f26e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=BE=D0=B2=D0=BE=D0=BF=D0=BE=D0=BB=D1=8C=D1=86?= =?UTF-8?q?=D0=B5=D0=B2=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4?= =?UTF-8?q?=D1=80?= Date: Wed, 11 Dec 2024 14:11:10 +0400 Subject: [PATCH] novopolcev_alexander_lab_3 is ready --- novopolcev_alexander_lab_3/.gitignore | 2 + novopolcev_alexander_lab_3/README.md | 46 +++++++ novopolcev_alexander_lab_3/docker-compose.yml | 29 ++++ .../hospital_service/Dockerfile | 16 +++ .../hospital_service/hospital_service.py | 110 +++++++++++++++ novopolcev_alexander_lab_3/nginx.conf | 26 ++++ .../patient_service/Dockerfile | 16 +++ .../patient_service/patient_service.py | 130 ++++++++++++++++++ novopolcev_alexander_lab_3/requirements.txt | 3 + 9 files changed, 378 insertions(+) create mode 100644 novopolcev_alexander_lab_3/.gitignore create mode 100644 novopolcev_alexander_lab_3/README.md create mode 100644 novopolcev_alexander_lab_3/docker-compose.yml create mode 100644 novopolcev_alexander_lab_3/hospital_service/Dockerfile create mode 100644 novopolcev_alexander_lab_3/hospital_service/hospital_service.py create mode 100644 novopolcev_alexander_lab_3/nginx.conf create mode 100644 novopolcev_alexander_lab_3/patient_service/Dockerfile create mode 100644 novopolcev_alexander_lab_3/patient_service/patient_service.py create mode 100644 novopolcev_alexander_lab_3/requirements.txt diff --git a/novopolcev_alexander_lab_3/.gitignore b/novopolcev_alexander_lab_3/.gitignore new file mode 100644 index 0000000..0196882 --- /dev/null +++ b/novopolcev_alexander_lab_3/.gitignore @@ -0,0 +1,2 @@ +/.venv +/.idea diff --git a/novopolcev_alexander_lab_3/README.md b/novopolcev_alexander_lab_3/README.md new file mode 100644 index 0000000..30bfce4 --- /dev/null +++ b/novopolcev_alexander_lab_3/README.md @@ -0,0 +1,46 @@ +# Лабораторная работа №3 - REST API, Gateway и синхронный обмен между микросервисами + +## Задание + +* Создать 2 микросервиса, реализующих CRUD на связанных сущностях. +* Реализовать механизм синхронного обмена сообщениями между микросервисами. +* Реализовать шлюз на основе прозрачного прокси-сервера nginx. + +## Предметная область: + +Имеются 2 сущности: одна сущность - больница, вторая - пациент, привязанный к этой больнице +Поля больницы: УИД (уникальный идентификатор) больницы, название, адрес. Поля пациента: УИД пациента, имя, фамилия, телефон, УИД больницы, к которой привязан пациент. + + +## Запуск ЛР: + +Введем в терминале команду: +``` +docker compose up --build + +``` +Эта команда сначала выполнит сборку, а затем запустит контейнеры. + +Также нужно убедиться в том,что 80 порт свободен и тогда вся система запустится. + +Для каждой сущности были реализованы CRUD-операции. + +### Patient сервис: + +* GET /patients — получить список всех пациентов +* POST /patients — создать нового пациента +* GET /patients/{id} — получить пациента по ID +* PUT /patients/{id} — обновить пациента по ID +* DELETE /patients/{id} — удалить пациента по ID + +### Hospital сервис: + +* GET /hospitals — получить все больницы +* POST /hospitals — создать новую больницу +* GET /hospitals/{id} — получить больницу по ID +* PUT /hospitals/{id} — обновить больницу по ID +* DELETE /hospitals/{id} — удалить больницу по ID + + +# Видео +https://disk.yandex.ru/i/10ziaq_H6ltg5g diff --git a/novopolcev_alexander_lab_3/docker-compose.yml b/novopolcev_alexander_lab_3/docker-compose.yml new file mode 100644 index 0000000..1d945bc --- /dev/null +++ b/novopolcev_alexander_lab_3/docker-compose.yml @@ -0,0 +1,29 @@ + +services: + + patient_service: + container_name: patient_service + build: + context: . + dockerfile: ./patient_service/Dockerfile + expose: + - 20001 + + hospital_service: + container_name: hospital_service + build: + context: . + dockerfile: ./hospital_service/Dockerfile + expose: + - 20002 + + nginx: + image: nginx:latest + ports: + - "80:80" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + depends_on: + - patient_service + - hospital_service + diff --git a/novopolcev_alexander_lab_3/hospital_service/Dockerfile b/novopolcev_alexander_lab_3/hospital_service/Dockerfile new file mode 100644 index 0000000..ff88203 --- /dev/null +++ b/novopolcev_alexander_lab_3/hospital_service/Dockerfile @@ -0,0 +1,16 @@ +FROM python:latest + +# Устанавливаю рабочую директорию внутри контейнера +WORKDIR /app + +# Копирую файл requirements.txt в контейнер +COPY requirements.txt . + +# Устанавливаю зависимости +RUN pip install --no-cache-dir -r requirements.txt + +# Копирую все файлы в контейнер +COPY hospital_service/hospital_service.py . + +# Команда для запуска Python-скрипта +CMD ["python", "hospital_service.py"] diff --git a/novopolcev_alexander_lab_3/hospital_service/hospital_service.py b/novopolcev_alexander_lab_3/hospital_service/hospital_service.py new file mode 100644 index 0000000..54c5fb4 --- /dev/null +++ b/novopolcev_alexander_lab_3/hospital_service/hospital_service.py @@ -0,0 +1,110 @@ +from flask import Flask, jsonify, request +from uuid import uuid4 +import uuid +import requests + + +class Hospital: + def __init__(self, name, adress, uuid_: uuid): + if uuid_ is None: + self.uuid_: uuid = uuid4() + else: + self.uuid_: uuid = uuid.UUID(uuid_) + self.name: str = name + self.adress: str = adress + + def to_dict(self): + return { + "uuid": self.uuid_, + "name": self.name, + "adress": self.adress + } + + def to_dict_with_patients(self, patients: list): + return { + "uuid": self.uuid_, + "name": self.name, + "adress": self.adress, + "patients": patients + } + + +app = Flask(__name__) + +hospitals: list[Hospital] = [ + Hospital(name='Hospital 1', adress='Narimanova 22', uuid_='997aa4c5-ebb2-4794-ba81-e742f9f1fa30'), + Hospital(name='Hospital 2', adress='Repina', uuid_='694827e4-0f93-45a5-8f75-bad7ef2d21fe') +] + +patients_url = 'http://patient_service:20002/' + + +def list_jsonify(): + return jsonify([hospital.to_dict() for hospital in hospitals]) + +@app.route('/', methods=['GET']) +def get_all(): + return list_jsonify(), 200 + +@app.route('/', methods=['GET']) +def get_one(uuid_): + for hospital in hospitals: + if hospital.uuid_ == uuid_: + return hospital.to_dict(), 200 + + return 'Больница с таким uuid не была найдена', 404 + + +@app.route('/with-patients/', methods=['GET']) +def get_one_with_patients(uuid_): + for hospital in hospitals: + if hospital.uuid_ == uuid_: + response = requests.get(patients_url + f'by-hospital/{uuid_}') + print(response.json()) + return hospital.to_dict_with_patients(response.json()), 200 + + return 'Больница с таким uuid не была найдена', 404 + + +@app.route('/', methods=['POST']) +def create(): + data = request.json + adress = data.get('adress', None) + name = data.get('name', None) + if name is None or adress is None: + return 'Недостаточно полей для создания новой больницы', 404 + + new_hospital = Hospital(name,adress, None) + hospitals.append(new_hospital) + return get_one(new_hospital.uuid_) + + +@app.route('/', methods=['PUT']) +def update_by_id(uuid_): + data = request.json + new_adress = data.get('adress', None) + new_name = data.get('name', None) + + for hospital in hospitals: + if hospital.uuid_ == uuid_: + if new_adress is not None: + hospital.adress = new_adress + if new_name is not None: + hospital.name = new_name + return get_one(hospital.uuid_) + + return 'Больница с таким uuid не была найдена', 404 + + +@app.route('/', methods=['DELETE']) +def delete(uuid_): + for hospital in hospitals: + if hospital.uuid_ == uuid_: + hospitals.remove(hospital) + return 'Больница успешно удалена', 200 + + return 'Больница с таким uuid не была найдена', 404 + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=20001, debug=True) \ No newline at end of file diff --git a/novopolcev_alexander_lab_3/nginx.conf b/novopolcev_alexander_lab_3/nginx.conf new file mode 100644 index 0000000..bf6a6f7 --- /dev/null +++ b/novopolcev_alexander_lab_3/nginx.conf @@ -0,0 +1,26 @@ + +events { worker_connections 1024; } + +http { + server { + listen 80; + listen [::]:80; + server_name localhost; + + location /hospital_service/ { + proxy_pass http://hospital_service:20001/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /patient_service/ { + proxy_pass http://patient_service:20002/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + } +} diff --git a/novopolcev_alexander_lab_3/patient_service/Dockerfile b/novopolcev_alexander_lab_3/patient_service/Dockerfile new file mode 100644 index 0000000..d4259db --- /dev/null +++ b/novopolcev_alexander_lab_3/patient_service/Dockerfile @@ -0,0 +1,16 @@ +FROM python:latest + +# Устанавливаю рабочую директорию внутри контейнера +WORKDIR /app + +# Копирую файл requirements.txt в контейнер +COPY requirements.txt . + +# Устанавливаю зависимости +RUN pip install --no-cache-dir -r requirements.txt + +# Копирую все файлы в контейнер +COPY patient_service/patient_service.py . + +# Команда для запуска Python-скрипта +CMD ["python", "patient_service.py"] diff --git a/novopolcev_alexander_lab_3/patient_service/patient_service.py b/novopolcev_alexander_lab_3/patient_service/patient_service.py new file mode 100644 index 0000000..143da7a --- /dev/null +++ b/novopolcev_alexander_lab_3/patient_service/patient_service.py @@ -0,0 +1,130 @@ +from flask import Flask, jsonify, request +import requests +from uuid import uuid4 +import uuid + + +class Patient: + def __init__(self, name, surname, phone, uuid_: uuid, hospital_id: uuid): + if uuid_ is None: + self.uuid_: uuid = uuid4() + else: + self.uuid_: uuid = uuid.UUID(uuid_) + self.name: str = name + self.surname: str = surname + self.phone: str = phone + self.hospital_id: uuid = uuid.UUID(hospital_id) + + def to_dict(self): + return { + 'name': self.name, + 'surname': self.surname, + 'phone': self.phone, + 'hospital_id': self.hospital_id, + 'uuid': self.uuid_ + } + + def to_dict_for_hospitals(self): + return { + 'name': self.name, + 'surname': self.surname, + 'phone': self.phone, + 'uuid': self.uuid_ + } + + + +app = Flask(__name__) + +patients: list[Patient] = [ + Patient(name='Anna', surname='Smirnova', phone= '89456289578', uuid_='89fa1e7a-7e88-445e-a4d8-6d4497ea8f19', + hospital_id='997aa4c5-ebb2-4794-ba81-e742f9f1fa30'), + Patient(name='Maria', surname='Nasteeva', phone='89236289569', uuid_='dfc17619-7690-47aa-ae8e-6a5068f8ddec', + hospital_id='997aa4c5-ebb2-4794-ba81-e742f9f1fa30') +] + +hospitals_url = 'http://hospital_service:20001/' + + +def list_jsonify(): + return jsonify([patient.to_dict() for patient in patients]) + + + +@app.route('/', methods=['GET']) +def get_all(): + return list_jsonify(), 200 + + + +@app.route('/by-hospital/', methods=['GET']) +def get_by_hospital_id(hospital_uuid): + return [patient.to_dict_for_hospitals() for patient in patients if patient.hospital_id == hospital_uuid], 200 + + + +@app.route('/', methods=['GET']) +def get_one(uuid_): + for patient in patients: + if patient.uuid_ == uuid_: + return patient.to_dict(), 200 + + return 'Пациент с таким uuid не был найден', 404 + + + + +# создание новой книги +@app.route('/', methods=['POST']) +def create(): + data = request.json + name = data.get('name', None) + surname = data.get('surname', None) + phone = data.get('phone', None) + hospital_id = data.get('hospital_id', None) + #checking = requests.get(hospitals_url + f'/check/{hospital_id}') + #print(checking) + #if checking.status_code == 200: + new_patient = Patient(name, surname,phone, None, hospital_id) + patients.append(new_patient) + return get_one(new_patient.uuid_) + #if checking.status_code == 404: + # return 'Больница с таким uuid не существует', 404 + + #return 'Неизвестная ошибка', 500 + + +@app.route('/', methods=['PUT']) +def update_by_id(uuid_): + data = request.json + new_name = data.get('name', None) + new_surname = data.get('surname', None) + new_phone = data.get('phone', None) + + for patient in patients: + print(patient.uuid_) + + if patient.uuid_ == uuid_: + if new_name is not None: + patient.name = new_name + if new_surname is not None: + patient.surname = new_surname + if new_phone is not None: + patient.phone= new_phone + return get_one(patient.uuid_) + + return 'Пациент с таким uuid не был найден', 404 + + +@app.route('/', methods=['DELETE']) +def delete(uuid_): + for patient in patients: + if patient.uuid_ == uuid_: + patients.remove(patient) + return 'Пациент успешно удален', 200 + + return 'Пациент с таким uuid не был найден', 404 + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=20002, debug=True) diff --git a/novopolcev_alexander_lab_3/requirements.txt b/novopolcev_alexander_lab_3/requirements.txt new file mode 100644 index 0000000..2c6edec --- /dev/null +++ b/novopolcev_alexander_lab_3/requirements.txt @@ -0,0 +1,3 @@ + Flask==3.0.3 + requests==2.32.3 +