From fc6efda0c2101db46998695b85cfb474ce186fed Mon Sep 17 00:00:00 2001 From: Safgerd Date: Sun, 17 Nov 2024 08:07:00 +0400 Subject: [PATCH] minhasapov_ruslan_lab_3 --- minhasapov_ruslan_lab_3/README.md | 40 ++++++ .../club_service/Dockerfile | 11 ++ .../club_service/club_service.py | 103 +++++++++++++++ minhasapov_ruslan_lab_3/docker-compose.yaml | 26 ++++ minhasapov_ruslan_lab_3/nginx.conf | 25 ++++ minhasapov_ruslan_lab_3/requirements.txt | 2 + .../resource_service/Dockerfile | 11 ++ .../resource_service/resource_service.py | 118 ++++++++++++++++++ 8 files changed, 336 insertions(+) create mode 100644 minhasapov_ruslan_lab_3/README.md create mode 100644 minhasapov_ruslan_lab_3/club_service/Dockerfile create mode 100644 minhasapov_ruslan_lab_3/club_service/club_service.py create mode 100644 minhasapov_ruslan_lab_3/docker-compose.yaml create mode 100644 minhasapov_ruslan_lab_3/nginx.conf create mode 100644 minhasapov_ruslan_lab_3/requirements.txt create mode 100644 minhasapov_ruslan_lab_3/resource_service/Dockerfile create mode 100644 minhasapov_ruslan_lab_3/resource_service/resource_service.py diff --git a/minhasapov_ruslan_lab_3/README.md b/minhasapov_ruslan_lab_3/README.md new file mode 100644 index 0000000..78b473a --- /dev/null +++ b/minhasapov_ruslan_lab_3/README.md @@ -0,0 +1,40 @@ +# Лабораторная работа №3 +#### ПИбд-42. Минхасапов Руслан. + +--- + +#### При выполнении лабораторной работы были использованы: +- Python 3.12 +- Flask +- requests +- Docker +- Docker Compose + +--- + +#### Задание: +В рамках данной работы были созданы сущности: +##### 1. Клуб. Имеет поля: + - id + - address + - phone +##### 2. Ресурс. Имеет поля: + - id + - name + - amount + - club_id + +##### Каждому клубу могут принадлежать много ресурсов. +##### Были развернуты два сервиса - club_service и resource_service, синхронно обменивающиеся сообщениями. +##### Сущности хранятся в оперативной памяти (без БД) + +--- + +#### Инструкция +Для запуска выполненной лабораторной работы необходимо перейти в директорию *minhasapov_ruslan_lab_3* и выполнить команду в терминале: +``` +docker-compose up --build -d --remove-orphans +``` + +#### Демонстрация работы +Доступна по [ссылке](https://disk.yandex.ru/i/IeNyzBXG1oDSWg) \ No newline at end of file diff --git a/minhasapov_ruslan_lab_3/club_service/Dockerfile b/minhasapov_ruslan_lab_3/club_service/Dockerfile new file mode 100644 index 0000000..bc10eb8 --- /dev/null +++ b/minhasapov_ruslan_lab_3/club_service/Dockerfile @@ -0,0 +1,11 @@ +FROM python:latest + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir -r requirements.txt + +COPY club_service/club_service.py . + +CMD ["python", "club_service.py"] \ No newline at end of file diff --git a/minhasapov_ruslan_lab_3/club_service/club_service.py b/minhasapov_ruslan_lab_3/club_service/club_service.py new file mode 100644 index 0000000..e86ae06 --- /dev/null +++ b/minhasapov_ruslan_lab_3/club_service/club_service.py @@ -0,0 +1,103 @@ +from flask import Flask, jsonify, request +import requests + +app = Flask(__name__) + +resources_url = 'http://resourceService:20002/' + +class Club: + def __init__(self, id: int, address: str, phone: str): + self.id = id + self.address = address + self.phone = phone + + def to_dict(self): + return { + "id": self.id, + "address": self.address, + "phone": self.phone + } + + def to_dict_with_resources(self, resources: list): + return{ + "id": self.id, + "address": self.address, + "phone": self.phone, + "resources": resources + } + +clubs = [ + Club(1, 'Пушкина 3', '88005553535'), + Club(2, 'Колотушкина 4', '89006664646') +] + +@app.route('/', methods=['GET']) +def get_all_clubs(): + return jsonify([club.to_dict() for club in clubs]), 200 + +@app.route('/', methods=['GET']) +def get_club(club_id): + for club in clubs: + if club.id == club_id: + return club.to_dict(), 200 + + return f'Club with id {club_id} not found', 404 + +@app.route('/info/', methods=['GET']) +def get_club_with_resources(club_id): + for club in clubs: + if club.id == club_id: + response = requests.get(resources_url + f'by-club/{club_id}') + + return club.to_dict_with_resources(response.json()), 200 + + return f'Club with id {club_id} not found', 404 + +@app.route('/check/', methods=['GET']) +def check_club_exists(club_id): + for club in clubs: + if club.id == club_id: + return '', 200 + + return '', 404 + +@app.route('/', methods=['POST']) +def create_club(): + data = request.json + address = data.get('address') + phone = data.get('phone') + + if address is None or phone is None: + return 'Address and phone required to create club', 400 + + next_id = max([c.id for c in clubs]) + 1 if clubs else 1 + new_club = Club(next_id, address, phone) + clubs.append(new_club) + + return jsonify(new_club.to_dict()), 201 + +@app.route('/', methods=['PUT']) +def update_club(club_id): + data = request.json + + for club in clubs: + if club.id == club_id: + club.address = data.get('address', club.address) + club.phone = data.get('phone', club.phone) + + return jsonify(club.to_dict()), 200 + + return f'Club with id {club_id} not found', 404 + +@app.route('/', methods=['DELETE']) +def delete_club(club_id): + for club in clubs: + if club.id == club_id: + clubs.remove(club) + + return 'Club deleted', 200 + + return f'Club with id {club_id} not found', 404 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=20001, debug=True) \ No newline at end of file diff --git a/minhasapov_ruslan_lab_3/docker-compose.yaml b/minhasapov_ruslan_lab_3/docker-compose.yaml new file mode 100644 index 0000000..d0035df --- /dev/null +++ b/minhasapov_ruslan_lab_3/docker-compose.yaml @@ -0,0 +1,26 @@ +services: + club_service: + container_name: clubService + build: + context: . + dockerfile: ./club_service/Dockerfile + expose: + - 20001 + + resource_service: + container_name: resourceService + build: + context: . + dockerfile: ./resource_service/Dockerfile + expose: + - 20002 + + nginx: + image: nginx:latest + ports: + - "80:80" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + depends_on: + - club_service + - resource_service \ No newline at end of file diff --git a/minhasapov_ruslan_lab_3/nginx.conf b/minhasapov_ruslan_lab_3/nginx.conf new file mode 100644 index 0000000..6c3c225 --- /dev/null +++ b/minhasapov_ruslan_lab_3/nginx.conf @@ -0,0 +1,25 @@ +events { worker_connections 1024; } + +http { + server { + listen 80; + listen [::]:80; + server_name localhost; + + location /clubService/ { + proxy_pass http://clubService: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 /resourceService/ { + proxy_pass http://resourceService: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; + } + } +} \ No newline at end of file diff --git a/minhasapov_ruslan_lab_3/requirements.txt b/minhasapov_ruslan_lab_3/requirements.txt new file mode 100644 index 0000000..494909e --- /dev/null +++ b/minhasapov_ruslan_lab_3/requirements.txt @@ -0,0 +1,2 @@ +Flask==3.0.3 +requests==2.32.3 \ No newline at end of file diff --git a/minhasapov_ruslan_lab_3/resource_service/Dockerfile b/minhasapov_ruslan_lab_3/resource_service/Dockerfile new file mode 100644 index 0000000..e7eac4c --- /dev/null +++ b/minhasapov_ruslan_lab_3/resource_service/Dockerfile @@ -0,0 +1,11 @@ +FROM python:latest + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir -r requirements.txt + +COPY resource_service/resource_service.py . + +CMD ["python", "resource_service.py"] \ No newline at end of file diff --git a/minhasapov_ruslan_lab_3/resource_service/resource_service.py b/minhasapov_ruslan_lab_3/resource_service/resource_service.py new file mode 100644 index 0000000..5911357 --- /dev/null +++ b/minhasapov_ruslan_lab_3/resource_service/resource_service.py @@ -0,0 +1,118 @@ +from flask import Flask, jsonify, request +import requests + +app = Flask(__name__) + +clubs_url = 'http://clubService:20001/' + +class Resource: + def __init__(self, id: int, name: str, amount: int, club_id: int): + self.id = id + self.name = name + self.amount = amount + self.club_id = club_id + + def to_dict(self): + return { + "id": self.id, + "name": self.name, + "amount": self.amount, + "club_id": self.club_id + } + + def to_dict_with_club(self, club): + return { + "id": self.id, + "name": self.name, + "amount": self.amount, + "club": club + } + +resources = [ + Resource(1, 'PS5', 3, 1), + Resource(2, 'XBOX', 4, 2) +] + +@app.route('/', methods=['GET']) +def get_all_resources(): + return jsonify([resource.to_dict() for resource in resources]), 200 + +@app.route('/by-club/', methods=['GET']) +def get_resources_by_club(club_id): + resources_for_club = [resource.to_dict() for resource in resources if resource.club_id == club_id] + + return jsonify(resources_for_club), 200 + +@app.route('/', methods=['GET']) +def get_resource(resource_id): + for resource in resources: + if resource.id == resource_id: + return jsonify(resource.to_dict()), 200 + + return f'Resource with id {resource_id} not found', 404 + +@app.route('/info/', methods=['GET']) +def get_resource_with_club(resource_id): + for resource in resources: + if resource.id == resource_id: + try: + response = requests.get(clubs_url + str(resource.club_id)) + response.raise_for_status() + club = response.json() + + return jsonify(resource.to_dict_with_club(club)), 200 + + except requests.exceptions.RequestException as e: + return f"Error fetching club: {e}", 500 + + return f'Resource with id {resource_id} not found', 404 + +@app.route('/', methods=['POST']) +def create_resource(): + data = request.json + name = data.get('name') + amount = data.get('amount') + club_id = data.get('club_id') + + try: + response = requests.get(clubs_url + f'check/{club_id}') + response.raise_for_status() + + if response.status_code == 200: + next_id = max([r.id for r in resources]) + 1 if resources else 1 + new_resource = Resource(next_id, name, amount, club_id) + resources.append(new_resource) + + return jsonify(new_resource.to_dict()), 201 + else: + return f"Club with ID {club_id} not found", 404 + + except requests.exceptions.RequestException as e: + return f"Error checking club: {e}", 500 + +@app.route('/', methods=['PUT']) +def update_resource(resource_id): + data = request.json + + for resource in resources: + if resource.id == resource_id: + resource.name = data.get('name', resource.name) + resource.amount = data.get('amount', resource.amount) + resource.club_id = data.get('club_id', resource.club_id) + + return jsonify(resource.to_dict()), 200 + + return f'Resource with id {resource_id} not found', 404 + +@app.route('/', methods=['DELETE']) +def delete_resource(resource_id): + for resource in resources: + if resource.id == resource_id: + resources.remove(resource) + + return 'Resource deleted', 200 + + return f'Resource with id {resource_id} not found', 404 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=20002, debug=True) \ No newline at end of file