From 1b01d7461ccfff8323461218a56994cd853b4e13 Mon Sep 17 00:00:00 2001 From: oleh Date: Sun, 13 Apr 2025 00:40:37 +0200 Subject: [PATCH] add deploy scripts --- sk1/Backend/model.py | 234 ++++++++++++++++++++--------------------- sk1/connect.sh | 10 ++ sk1/deploy-instance.sh | 43 ++++++++ sk1/setup-docker.sh | 24 +++++ sk1/start-instance.sh | 19 ++++ sk1/stop-instance.sh | 19 ++++ sk1/terminate.sh | 26 +++++ 7 files changed, 256 insertions(+), 119 deletions(-) create mode 100644 sk1/connect.sh create mode 100644 sk1/deploy-instance.sh create mode 100644 sk1/setup-docker.sh create mode 100644 sk1/start-instance.sh create mode 100644 sk1/stop-instance.sh create mode 100644 sk1/terminate.sh diff --git a/sk1/Backend/model.py b/sk1/Backend/model.py index 590a666..720a0f0 100644 --- a/sk1/Backend/model.py +++ b/sk1/Backend/model.py @@ -22,20 +22,17 @@ mistral_api_key = "hXDC4RBJk1qy5pOlrgr01GtOlmyCBaNs" if not mistral_api_key: raise ValueError("Mistral API key not found in configuration.") - ############################################################################### -# Simple functions for translation (stub) +# Jednoduché funkcie pre preklad (stub) ############################################################################### def translate_to_slovak(text: str) -> str: return text - def translate_preserving_medicine_names(text: str) -> str: return text - ############################################################################### -# Function for evaluating the completeness of the answer +# Funkcia pre vyhodnotenie úplnosti odpovede ############################################################################### def evaluate_complete_answer(query: str, answer: str) -> dict: evaluation_prompt = ( @@ -51,13 +48,12 @@ def evaluate_complete_answer(query: str, answer: str) -> dict: try: score = float(score_str.strip()) except Exception as e: - logger.error(f"Error parsing evaluation score: {e}") + logger.error(f"Chyba pri parsovaní skóre: {e}") score = 0.0 - return {"rating": round(score, 2), "explanation": "Evaluation based on required criteria."} - + return {"rating": round(score, 2), "explanation": "Vyhodnotenie na základe požadovaných kritérií."} ############################################################################### -# Function for validating the response logic +# Funkcia pre validáciu logiky odpovede ############################################################################### def validate_answer_logic(query: str, answer: str) -> str: validation_prompt = ( @@ -70,15 +66,14 @@ def validate_answer_logic(query: str, answer: str) -> str: ) try: validated_answer = llm_small.generate_text(prompt=validation_prompt, max_tokens=800, temperature=0.5) - logger.info(f"Validated answer: {validated_answer}") + logger.info(f"Validovaná odpoveď: {validated_answer}") return validated_answer except Exception as e: - logger.error(f"Error during answer validation: {e}") + logger.error(f"Chyba pri validácii odpovede: {e}") return answer - ############################################################################### -# Function for creating a dynamic prompt with information from documents +# Funkcia pre vytvorenie dynamického promptu s informáciami z dokumentov ############################################################################### def build_dynamic_prompt(query: str, documents: list) -> str: documents_str = "\n".join(documents) @@ -95,9 +90,8 @@ def build_dynamic_prompt(query: str, documents: list) -> str: ) return prompt - ############################################################################### -# Function to get user data from the database via endpoint /api/get_user_data +# Funkcia na získanie používateľských dát z databázy prostredníctvom endpointu /api/get_user_data ############################################################################### def get_user_data_from_db(chat_id: str) -> str: try: @@ -106,14 +100,13 @@ def get_user_data_from_db(chat_id: str) -> str: data = response.json() return data.get("user_data", "") else: - logger.warning(f"Nezískané user_data, status: {response.status_code}") + logger.warning(f"Nepodarilo sa získať user_data, status: {response.status_code}") except Exception as e: - logger.error(f"Error retrieving user_data from DB: {e}", exc_info=True) + logger.error(f"Chyba pri získavaní user_data z DB: {e}", exc_info=True) return "" - ############################################################################### -# Class for calling Mistral LLM +# Trieda pre volanie Mistral LLM ############################################################################### class CustomMistralLLM: def __init__(self, api_key: str, endpoint_url: str, model_name: str): @@ -138,86 +131,54 @@ class CustomMistralLLM: response = requests.post(self.endpoint_url, headers=headers, json=payload) response.raise_for_status() result = response.json() - logger.info(f"Full response from model {self.model_name}: {result}") + logger.info(f"Úplná odpoveď od modelu {self.model_name}: {result}") return result.get("choices", [{}])[0].get("message", {}).get("content", "No response") except HTTPError as e: if response.status_code == 429: - logger.warning(f"Rate limit exceeded. Waiting {delay} seconds before retry.") + logger.warning(f"Rate limit prekročený. Čakám {delay} sekúnd pred ďalšou skúškou.") time.sleep(delay) attempt += 1 else: - logger.error(f"HTTP Error: {e}") + logger.error(f"HTTP chyba: {e}") raise e except Exception as ex: - logger.error(f"Error: {str(ex)}") + logger.error(f"Chyba: {str(ex)}") raise ex - raise Exception("Reached maximum number of retries for API request") - + raise Exception("Dosiahnutý maximálny počet pokusov pre API request") ############################################################################### -# Function for generating a detailed evaluation description +# Funkcia pre kontrolu, či správa súvisí s témou medicíny a liekov ############################################################################### -# def detailed_evaluation_description(query: str, answer: str, rating: float) -> str: -# prompt = ( -# f"Podrobne opíš, prečo odpoveď: '{answer}' na otázku: '{query}' dosiahla hodnotenie {rating} zo 10. " -# "Uveď relevantné aspekty, ktoré ovplyvnili toto hodnotenie, vrátane úplnosti, presnosti a kvality vysvetlenia." -# ) -# description = llm_small.generate_text(prompt=prompt, max_tokens=150, temperature=0.5) -# return description.strip() -# -# Ak chcete vidieť podrobné hodnotenie, odkomentujte funkciu detailed_evaluation_description a príslušné časti kódu. +def check_if_message_is_relevant(query: str) -> (bool, str): + # Ak je dotaz rovnaký s textami pre doplňujúce informácie, preskočíme kontrolu + missing_msgs = [ + "Prosím, uveďte vek pacienta.", + "Má pacient nejaké chronické ochorenia alebo alergie?", + "Ide o liek na predpis alebo voľnopredajný liek?" + ] + if query.strip() in missing_msgs: + return True, "Ano" - -############################################################################### -# Initialisation of Embeddings and Elasticsearch -############################################################################### -logger.info("Loading HuggingFaceEmbeddings model...") -embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2") - -index_name = "drug_docs" -if config.get("useCloud", False): - logger.info("Using cloud Elasticsearch.") - cloud_id = "tt:dXMtZWFzdC0yLmF3cy5lbGFzdGljLWNsb3VkLmNvbTo0NDMkOGM3ODQ0ZWVhZTEyNGY3NmFjNjQyNDFhNjI4NmVhYzMkZTI3YjlkNTQ0ODdhNGViNmEyMTcxMjMxNmJhMWI0ZGU=" - vectorstore = ElasticsearchStore( - es_cloud_id=cloud_id, - index_name=index_name, - embedding=embeddings, - es_user="elastic", - es_password="sSz2BEGv56JRNjGFwoQ191RJ" + prompt_relevance = ( + f"Pozri si nasledujúci dotaz užívateľa: '{query}'.\n" + "Patrí tento dotaz logicky do témy medicíny a odporúčaní liekov? " + "Ak áno, odpíš presne slovom 'Ano'. Ak nie, uveď dôvod, prečo sa dotaz netýka našej témy." ) -else: - logger.info("Using local Elasticsearch.") - vectorstore = ElasticsearchStore( - es_url="http://elasticsearch:9200", - index_name=index_name, - embedding=embeddings, - ) - -logger.info("Connected to Elasticsearch.") + response = llm_small.generate_text(prompt=prompt_relevance, max_tokens=200, temperature=0.3) + response = response.strip() + if response.lower() == "ano": + return True, "Ano" + else: + return False, response ############################################################################### -# Initialisation of LLM small & large -############################################################################### -llm_small = CustomMistralLLM( - api_key=mistral_api_key, - endpoint_url="https://api.mistral.ai/v1/chat/completions", - model_name="mistral-small-latest" -) -llm_large = CustomMistralLLM( - api_key=mistral_api_key, - endpoint_url="https://api.mistral.ai/v1/chat/completions", - model_name="mistral-large-latest" -) - - -############################################################################### -# Request classification function: vyhladavanie vs. upresnenie +# Funkcia pre klasifikáciu dopytu: vyhľadávanie vs. upresnenie ############################################################################### def classify_query(query: str, chat_history: str = "") -> str: if not chat_history.strip(): return "vyhladavanie" prompt = ( - "Ty si zdravotnícky expert, ktorý analyzuje otázky používateľov. " + "Si zdravotnícky expert, ktorý analyzuje otázky používateľov. " "Analyzuj nasledujúci dopyt a urči, či ide o dopyt na vyhľadanie liekov alebo " "o upresnenie/doplnenie už poskytnutej odpovede.\n" "Ak dopyt obsahuje výrazy ako 'čo pit', 'aké lieky', 'odporuč liek', 'hľadám liek', " @@ -235,16 +196,15 @@ def classify_query(query: str, chat_history: str = "") -> str: return "upresnenie" return "vyhladavanie" - ############################################################################### -# Template for upresnenie dopytu +# Šablóna pre upresnenie dopytu ############################################################################### def build_upresnenie_prompt_no_history(chat_history: str, user_query: str) -> str: prompt = f""" -Ty si zdravotnícky expert. Máš k dispozícii históriu chatu a novú upresňujúcu otázku. +Si zdravotnícky expert. Máš k dispozícii históriu chatu a novú upresňujúcu otázku. Ak v histórii chatu už existuje jasná odpoveď na túto upresňujúcu otázku, napíš: -"FOUND_IN_HISTORY: <ľudský vysvetľajúci text>" +"FOUND_IN_HISTORY: <ľudský vysvetľujúci text>" Ak však v histórii chatu nie je dostatok informácií, napíš: "NO_ANSWER_IN_HISTORY: " @@ -260,9 +220,8 @@ Upresňujúca otázka od používateľa: """ return prompt - ############################################################################### -# Function for retrieving the last vyhladavacieho dopytu z histórie +# Funkcia pre získanie posledného vyhľadávacieho dopytu z histórie ############################################################################### def extract_last_vyhladavacie_query(chat_history: str) -> str: lines = chat_history.splitlines() @@ -273,9 +232,8 @@ def extract_last_vyhladavacie_query(chat_history: str) -> str: break return last_query - ############################################################################### -# Agent class for data storage: vek, anamneza, predpis, user_data, search_query +# Trieda pre agenta konverzácie (dátové ukladanie: vek, anamnéza, predpis, user_data, search_query) ############################################################################### class ConversationalAgent: def __init__(self): @@ -333,15 +291,13 @@ class ConversationalAgent: def ask_follow_up(self, missing_info: dict) -> str: return " ".join(missing_info.values()) - ############################################################################### -# Main function process_query_with_mistral with updated logic +# Hlavná funkcia process_query_with_mistral s aktualizovanou logikou ############################################################################### CHAT_HISTORY_ENDPOINT = "http://localhost:5000/api/chat_history_detail" - def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10): - logger.info("Processing query started.") + logger.info("Spustenie spracovania dopytu.") chat_history = "" if chat_context: @@ -363,6 +319,17 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10 except Exception as e: logger.error(f"Chyba pri načítaní histórie: {e}") + # Kontrola relevancie správy + is_relevant, relevance_response = check_if_message_is_relevant(query) + if not is_relevant: + logger.info("Dotaz sa netýka témy medicíny, vraciam vysvetlenie.") + return { + "best_answer": relevance_response, + "model": "RelevanceCheck", + "rating": 0, + "explanation": "Dotaz sa netýka témy medicíny a odporúčaní liekov." + } + agent = ConversationalAgent() if chat_history: agent.load_memory_from_history(chat_history) @@ -381,11 +348,11 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10 try: update_response = requests.post("http://localhost:5000/api/save_user_data", json=update_payload) if update_response.status_code == 200: - logger.info("User data was successfully updated via endpoint /api/save_user_data (data question flag).") + logger.info("Používateľské dáta boli úspešne aktualizované cez endpoint /api/save_user_data (data question flag).") else: - logger.warning(f"Failed to update data (data question flag): {update_response.text}") + logger.warning(f"Neúspešná aktualizácia dát (data question flag): {update_response.text}") except Exception as e: - logger.error(f"Error when updating user_data via endpoint (data question flag): {e}") + logger.error(f"Chyba pri aktualizácii user_data cez endpoint (data question flag): {e}") if missing_info: logger.info(f"Chýbajúce informácie: {missing_info}") @@ -396,27 +363,27 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10 try: update_response = requests.post("http://localhost:5000/api/save_user_data", json=update_payload) if update_response.status_code == 200: - logger.info("User data was successfully updated via endpoint /api/save_user_data.") + logger.info("Používateľské dáta boli úspešne aktualizované cez endpoint /api/save_user_data.") else: - logger.warning(f"Failed to update the data: {update_response.text}") + logger.warning(f"Neúspešná aktualizácia dát: {update_response.text}") except Exception as e: - logger.error(f"Error when updating user_data via endpoint: {e}") + logger.error(f"Chyba pri aktualizácii user_data cez endpoint: {e}") return { "best_answer": combined_missing_text, "model": "FollowUp (new chat)", "rating": 0, - "explanation": "Additional data pre pokračovanie is required.", + "explanation": "Pre pokračovanie je potrebné doplniť ďalšie údaje.", "patient_data": query } qtype = classify_query(query, chat_history) logger.info(f"Typ dopytu: {qtype}") - logger.info(f"Chat context (snippet): {chat_history[:200]}...") + logger.info(f"Časť histórie chatu: {chat_history[:200]}...") if qtype == "vyhladavanie": user_data_db = get_user_data_from_db(chat_id) if user_data_db: - query = query + " Udaje cloveka: " + user_data_db + query = query + " Údaje človeka: " + user_data_db agent.long_term_memory["search_query"] = query if qtype == "upresnenie": @@ -428,21 +395,21 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10 combined_query = (original_search + " " + query).strip() user_data_db = get_user_data_from_db(chat_id) if user_data_db: - combined_query += " Udaje cloveka: " + user_data_db - logger.info(f"Combined query for search: {combined_query}") + combined_query += " Údaje človeka: " + user_data_db + logger.info(f"Kombinovaný dopyt pre vyhľadávanie: {combined_query}") upres_prompt = build_upresnenie_prompt_no_history(chat_history, combined_query) response_str = llm_small.generate_text(upres_prompt, max_tokens=1200, temperature=0.5) normalized = response_str.strip() - logger.info(f"Upresnenie prompt response: {normalized}") + logger.info(f"Odpoveď na prompt pre upresnenie: {normalized}") if re.match(r"(?i)^found_in_history:\s*", normalized): - logger.info("Zistený FOUND_IN_HISTORY – vykonávame vyhľadávanie s kombinovaným dopytom.") + logger.info("Nájdené FOUND_IN_HISTORY – vykonávam vyhľadávanie s kombinovaným dopytom.") elif re.match(r"(?i)^no_answer_in_history:\s*", normalized): parts = re.split(r"(?i)^no_answer_in_history:\s*", normalized, maxsplit=1) if len(parts) >= 2: combined_query = parts[1].strip() - logger.info(f"Upravený vyhľadávací dopyт z NO_ANSWER_IN_HISTORY: {combined_query}") + logger.info(f"Upravený vyhľadávací dopyt z NO_ANSWER_IN_HISTORY: {combined_query}") vector_results = vectorstore.similarity_search(combined_query, k=k) max_docs = 5 @@ -453,7 +420,7 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10 "best_answer": "Ľutujem, nenašli sa žiadne relevantné informácie.", "model": "Upresnenie-NoResults", "rating": 0, - "explanation": "No results from search." + "explanation": "Žiadne výsledky z vyhľadávania." } joined_docs = "\n".join(vector_docs) final_prompt = ( @@ -474,19 +441,11 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10 {"summary": val_large, "eval": eval_large, "model": "Mistral Large"}, ] - # - # for candidate in candidates: - # detailed_desc = detailed_evaluation_description(combined_query, candidate["summary"], candidate["eval"]["rating"]) - # candidate["eval"]["detailed_description"] = detailed_desc - # - - best = max(candidates, key=lambda x: x["eval"]["rating"]) logger.info(f"Odpoveď od modelu {best['model']} má rating: {best['eval']['rating']}/10") - evaluation_table = "=== Výsledky hodnotenia odpovedí ===\n" - evaluation_table += "{:<15} | {:<6} | {:<60}\n".format("Model", "Rating", "Evaluated Text") + evaluation_table += "{:<15} | {:<6} | {:<60}\n".format("Model", "Rating", "Evaluovaný text") evaluation_table += "-" * 100 + "\n" for candidate in candidates: model_name = candidate["model"] @@ -495,10 +454,6 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10 evaluation_table += "{:<15} | {:<6} | {:<60}\n".format(model_name, rating, evaluated_text) evaluation_table += "=" * 100 + "\n" - # with open("evaluation.txt", "w", encoding="utf-8") as f: - # f.write(evaluation_table) - # logger.info("Evaluation table записана в evaluation.txt") - final_answer = translate_preserving_medicine_names(best["summary"]) memory_json = json.dumps(agent.long_term_memory) memory_block = f"[MEMORY]{memory_json}[/MEMORY]" @@ -519,7 +474,7 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10 "best_answer": "Ľutujem, nenašli sa žiadne relevantné informácie.", "model": "Vyhladavanie-NoDocs", "rating": 0, - "explanation": "No results" + "explanation": "Žiadne výsledky" } joined_docs = "\n".join(vector_docs) final_prompt = ( @@ -539,3 +494,44 @@ def process_query_with_mistral(query: str, chat_id: str, chat_context: str, k=10 "rating": 9, "explanation": "Vyhľadávacia cesta" } + +############################################################################### +# Inicializácia Embeddings a Elasticsearch +############################################################################### +logger.info("Načítavam model HuggingFaceEmbeddings...") +embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2") + +index_name = "drug_docs" +if config.get("useCloud", False): + logger.info("Používam cloud Elasticsearch.") + cloud_id = "tt:dXMtZWFzdC0yLmF3cy5lbGFzdGljLWNsb3VkLmNvbTo0NDMkOGM3ODQ0ZWVhZTEyNGY3NmFjNjQyNDFhNjI4NmVhYzMkZTI3YjlkNTQ0ODdhNGViNmEyMTcxMjMxNmJhMWI0ZGU=" + vectorstore = ElasticsearchStore( + es_cloud_id=cloud_id, + index_name=index_name, + embedding=embeddings, + es_user="elastic", + es_password="sSz2BEGv56JRNjGFwoQ191RJ" + ) +else: + logger.info("Používam lokálny Elasticsearch.") + vectorstore = ElasticsearchStore( + es_url="http://elasticsearch:9200", + index_name=index_name, + embedding=embeddings, + ) + +logger.info("Pripojenie k Elasticsearch bolo úspešné.") + +############################################################################### +# Inicializácia LLM small a large +############################################################################### +llm_small = CustomMistralLLM( + api_key=mistral_api_key, + endpoint_url="https://api.mistral.ai/v1/chat/completions", + model_name="mistral-small-latest" +) +llm_large = CustomMistralLLM( + api_key=mistral_api_key, + endpoint_url="https://api.mistral.ai/v1/chat/completions", + model_name="mistral-large-latest" +) diff --git a/sk1/connect.sh b/sk1/connect.sh new file mode 100644 index 0000000..5589685 --- /dev/null +++ b/sk1/connect.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +IP="52.51.10.99" +KEY_PATH="/c/Users/olezk/Desktop/mykey.pem" + + +ssh-keygen -R $IP > /dev/null + + +ssh -i "$KEY_PATH" ubuntu@$IP diff --git a/sk1/deploy-instance.sh b/sk1/deploy-instance.sh new file mode 100644 index 0000000..550a24c --- /dev/null +++ b/sk1/deploy-instance.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# ========== Конфигурация ========== +AMI_ID="ami-01c7096235204c7be" +INSTANCE_TYPE="t3.xlarge" +KEY_NAME="mykey" +SECURITY_GROUP="sg-0e08dfcd575ebfe2e" +EIP_ALLOC_ID="eipalloc-0ab8a278c183034a3" +SUBNET_ID="subnet-015876fa51f73f1ad" +LOCAL_PEM_PATH="/c/Users/olezk/Desktop/mykey.pem" +USERNAME="ubuntu" +SSH_OUTPUT_FILE="ssh-key.txt" + +# ========== Запуск EC2-инстанса ========== +echo "🚀 Запускаем EC2 инстанс..." +INSTANCE_ID=$(aws ec2 run-instances \ + --image-id $AMI_ID \ + --instance-type $INSTANCE_TYPE \ + --key-name $KEY_NAME \ + --security-group-ids $SECURITY_GROUP \ + --subnet-id $SUBNET_ID \ + --associate-public-ip-address \ + --query "Instances[0].InstanceId" \ + --output text) + +echo "🟡 Инстанс создаётся: $INSTANCE_ID" +aws ec2 wait instance-running --instance-ids $INSTANCE_ID +echo "✅ Инстанс $INSTANCE_ID работает." + +# ========== Получение публичного IP ========== +PUBLIC_IP=$(aws ec2 describe-instances \ + --instance-ids "$INSTANCE_ID" \ + --query "Reservations[0].Instances[0].PublicIpAddress" \ + --output text) + +# ========== Привязка Elastic IP ========== +echo "🔗 Привязываем Elastic IP..." +aws ec2 associate-address \ + --instance-id $INSTANCE_ID \ + --allocation-id $EIP_ALLOC_ID + +echo "✅ Готово!" +echo "🔗 IP для подключения: $PUBLIC_IP" diff --git a/sk1/setup-docker.sh b/sk1/setup-docker.sh new file mode 100644 index 0000000..8f04c59 --- /dev/null +++ b/sk1/setup-docker.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +echo "🔧 Обновляем пакеты..." +sudo apt-get update + +echo "🐳 Устанавливаем Docker..." +sudo apt-get install -y docker.io + +echo "📦 Устанавливаем Docker Compose..." +sudo apt-get install -y docker-compose + +echo "🔁 Разрешаем запуск Docker без sudo..." +sudo usermod -aG docker $USER +newgrp docker + +echo "🔧 Включаем автозапуск Docker..." +sudo systemctl enable docker +sudo systemctl start docker + +echo "🧬 Устанавливаем Git..." +sudo apt-get install -y git + +echo "✅ Готово! Система готова к запуску:" +echo "👉 docker-compose up --build" diff --git a/sk1/start-instance.sh b/sk1/start-instance.sh new file mode 100644 index 0000000..7fa4982 --- /dev/null +++ b/sk1/start-instance.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +INSTANCE_ID=$(aws ec2 describe-instances \ + --filters "Name=instance-state-name,Values=stopped" \ + --query "Reservations[-1].Instances[-1].InstanceId" \ + --output text) + +if [ "$INSTANCE_ID" == "None" ] || [ -z "$INSTANCE_ID" ]; then + echo "❌ Нет остановленных инстансов для запуска." + exit 1 +fi + +echo "🚀 Запускаем инстанс $INSTANCE_ID..." +aws ec2 start-instances --instance-ids "$INSTANCE_ID" + +echo "⏳ Ждём запуска..." +aws ec2 wait instance-running --instance-ids "$INSTANCE_ID" + +echo "✅ Инстанс $INSTANCE_ID работает." diff --git a/sk1/stop-instance.sh b/sk1/stop-instance.sh new file mode 100644 index 0000000..a32169d --- /dev/null +++ b/sk1/stop-instance.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +INSTANCE_ID=$(aws ec2 describe-instances \ + --filters "Name=instance-state-name,Values=running" \ + --query "Reservations[-1].Instances[-1].InstanceId" \ + --output text) + +if [ "$INSTANCE_ID" == "None" ] || [ -z "$INSTANCE_ID" ]; then + echo "❌ Нет работающих инстансов для остановки." + exit 1 +fi + +echo "🛑 Останавливаем инстанс $INSTANCE_ID..." +aws ec2 stop-instances --instance-ids "$INSTANCE_ID" + +echo "⏳ Ждём остановки..." +aws ec2 wait instance-stopped --instance-ids "$INSTANCE_ID" + +echo "✅ Инстанс $INSTANCE_ID остановлен." diff --git a/sk1/terminate.sh b/sk1/terminate.sh new file mode 100644 index 0000000..e148456 --- /dev/null +++ b/sk1/terminate.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Найдём только running-инстансы +INSTANCE_ID=$(aws ec2 describe-instances \ + --filters "Name=instance-state-name,Values=running" \ + --query "Reservations[-1].Instances[-1].InstanceId" \ + --output text) + +if [ "$INSTANCE_ID" == "None" ] || [ -z "$INSTANCE_ID" ]; then + echo "❌ Нет работающих (running) EC2-инстансов для остановки и удаления." + exit 1 +fi + +echo "🟡 Останавливаем EC2-инстанс: $INSTANCE_ID..." +aws ec2 stop-instances --instance-ids "$INSTANCE_ID" + +echo "⏳ Ждём полной остановки..." +aws ec2 wait instance-stopped --instance-ids "$INSTANCE_ID" + +echo "🔴 Удаляем остановленный инстанс: $INSTANCE_ID..." +aws ec2 terminate-instances --instance-ids "$INSTANCE_ID" + +echo "⏳ Ждём удаления..." +aws ec2 wait instance-terminated --instance-ids "$INSTANCE_ID" + +echo "✅ Успешно остановлен и удалён инстанс: $INSTANCE_ID"