From 3dab386360a84c4c5e8c89fe48f56a63bc83dfa5 Mon Sep 17 00:00:00 2001 From: z30057876 Date: Fri, 10 Oct 2025 17:33:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=9E=E5=90=88=E9=83=A8=E7=BD=B2=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=94=B9=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/chart/README.md | 10 +- deploy/chart/agents/Chart.yaml | 2 +- deploy/chart/agents/templates/NOTES.txt | 2 +- deploy/chart/agents/values.yaml | 102 ++-- deploy/chart/authhub/Chart.yaml | 2 +- deploy/chart/authhub/templates/NOTES.txt | 12 +- deploy/chart/authhub/values.yaml | 66 +-- deploy/chart/databases/Chart.yaml | 2 +- deploy/chart/databases/templates/NOTES.txt | 6 +- deploy/chart/databases/values.yaml | 97 ++-- deploy/chart/euler_copilot/Chart.yaml | 2 +- .../euler_copilot/configs/deepinsight/.env | 6 +- .../chart/euler_copilot/templates/NOTES.txt | 8 +- .../templates/deepinsight/deepinsight.yaml | 4 +- .../templates/web/web-config.yaml | 1 - deploy/chart/euler_copilot/values.yaml | 160 +++--- .../{ => common}/chart_ssl/traefik-config.yml | 0 .../chart_ssl/traefik-secret.yaml | 0 .../chart_ssl/traefik-tlsstore.yaml | 0 deploy/{ => common}/secret_helper/Dockerfile | 0 deploy/{ => common}/secret_helper/__init__.py | 0 .../secret_helper/config.example.yaml | 0 .../{ => common}/secret_helper/file_copy.py | 0 deploy/{ => common}/secret_helper/job.py | 0 deploy/{ => common}/secret_helper/main.py | 0 .../secret_helper/requirements.txt | 0 .../0-one-click-deploy/one-click-deploy_en.sh | 294 +++++++++++ ...click-deploy.sh => one-click-deploy_zh.sh} | 0 deploy/scripts/1-check-env/check_env_en.sh | 250 +++++++++ .../{check_env.sh => check_env_zh.sh} | 0 .../2-install-tools/install_tools_en.sh | 381 ++++++++++++++ .../{install_tools.sh => install_tools_zh.sh} | 0 .../3-install-ollama/install_ollama_en.sh | 337 ++++++++++++ ...install_ollama.sh => install_ollama_zh.sh} | 0 .../4-deploy-deepseek/deploy_deepseek_en.sh | 252 +++++++++ ...ploy_deepseek.sh => deploy_deepseek_zh.sh} | 0 .../5-deploy-embedding/deploy-embedding_en.sh | 252 +++++++++ ...oy-embedding.sh => deploy-embedding_zh.sh} | 0 .../install_databases_en.sh | 169 ++++++ ...l_databases.sh => install_databases_zh.sh} | 0 .../7-install-authhub/install_authhub_en.sh | 240 +++++++++ ...stall_authhub.sh => install_authhub_zh.sh} | 0 .../install_eulercopilot_en.sh | 480 ++++++++++++++++++ ...rcopilot.sh => install_eulercopilot_zh.sh} | 0 .../9-other-script/backup_databases.sh | 250 +++++---- .../get_client_id_and_secret.py | 54 +- deploy/scripts/9-other-script/get_log.sh | 57 +-- .../scripts/9-other-script/import_images.sh | 130 ++--- .../9-other-script/migrate_minio_database.sh | 190 +++---- .../9-other-script/migrate_mysql_database.sh | 198 ++++---- .../migrate_opengauss_database.sh | 164 +++--- .../modify_eulercopilot_yaml.py | 68 +-- .../scripts/9-other-script/prepare_docker.sh | 186 +++---- deploy/scripts/9-other-script/save_images.sh | 84 +-- deploy/scripts/deploy.sh | 468 +++++++++++++---- 55 files changed, 3954 insertions(+), 1032 deletions(-) rename deploy/{ => common}/chart_ssl/traefik-config.yml (100%) rename deploy/{ => common}/chart_ssl/traefik-secret.yaml (100%) rename deploy/{ => common}/chart_ssl/traefik-tlsstore.yaml (100%) rename deploy/{ => common}/secret_helper/Dockerfile (100%) rename deploy/{ => common}/secret_helper/__init__.py (100%) rename deploy/{ => common}/secret_helper/config.example.yaml (100%) rename deploy/{ => common}/secret_helper/file_copy.py (100%) rename deploy/{ => common}/secret_helper/job.py (100%) rename deploy/{ => common}/secret_helper/main.py (100%) rename deploy/{ => common}/secret_helper/requirements.txt (100%) create mode 100644 deploy/scripts/0-one-click-deploy/one-click-deploy_en.sh rename deploy/scripts/0-one-click-deploy/{one-click-deploy.sh => one-click-deploy_zh.sh} (100%) mode change 100755 => 100644 create mode 100644 deploy/scripts/1-check-env/check_env_en.sh rename deploy/scripts/1-check-env/{check_env.sh => check_env_zh.sh} (100%) mode change 100755 => 100644 create mode 100644 deploy/scripts/2-install-tools/install_tools_en.sh rename deploy/scripts/2-install-tools/{install_tools.sh => install_tools_zh.sh} (100%) mode change 100755 => 100644 create mode 100644 deploy/scripts/3-install-ollama/install_ollama_en.sh rename deploy/scripts/3-install-ollama/{install_ollama.sh => install_ollama_zh.sh} (100%) mode change 100755 => 100644 create mode 100644 deploy/scripts/4-deploy-deepseek/deploy_deepseek_en.sh rename deploy/scripts/4-deploy-deepseek/{deploy_deepseek.sh => deploy_deepseek_zh.sh} (100%) mode change 100755 => 100644 create mode 100644 deploy/scripts/5-deploy-embedding/deploy-embedding_en.sh rename deploy/scripts/5-deploy-embedding/{deploy-embedding.sh => deploy-embedding_zh.sh} (100%) mode change 100755 => 100644 create mode 100644 deploy/scripts/6-install-databases/install_databases_en.sh rename deploy/scripts/6-install-databases/{install_databases.sh => install_databases_zh.sh} (100%) mode change 100755 => 100644 create mode 100644 deploy/scripts/7-install-authhub/install_authhub_en.sh rename deploy/scripts/7-install-authhub/{install_authhub.sh => install_authhub_zh.sh} (100%) mode change 100755 => 100644 create mode 100644 deploy/scripts/8-install-EulerCopilot/install_eulercopilot_en.sh rename deploy/scripts/8-install-EulerCopilot/{install_eulercopilot.sh => install_eulercopilot_zh.sh} (100%) mode change 100755 => 100644 diff --git a/deploy/chart/README.md b/deploy/chart/README.md index 75dd156d0..f0b9c6b87 100644 --- a/deploy/chart/README.md +++ b/deploy/chart/README.md @@ -1,10 +1,10 @@ # EulerCopilot -## 部署顺序 +## Deployment Sequence -1. databases [必须部署] -2. authhub [必须部署] -3. witchaind [必须部署] -4. euler-copilot [必须部署] +1. databases [Required] +2. authhub [Required] +3. witchaind [Required] +4. euler-copilot [Required] 5. rca 6. agents diff --git a/deploy/chart/agents/Chart.yaml b/deploy/chart/agents/Chart.yaml index 84e88fcb2..d6d275524 100644 --- a/deploy/chart/agents/Chart.yaml +++ b/deploy/chart/agents/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: euler-copilot-helm -description: Euler Copilot Helm部署包 +description: Euler Copilot Helm Chart type: application version: 0.9.1 appVersion: "1.16.0" diff --git a/deploy/chart/agents/templates/NOTES.txt b/deploy/chart/agents/templates/NOTES.txt index 5c28f225e..2b076bd6b 100644 --- a/deploy/chart/agents/templates/NOTES.txt +++ b/deploy/chart/agents/templates/NOTES.txt @@ -1 +1 @@ -感谢您选择Euler Copilot! \ No newline at end of file +Thank you for choosing Euler Copilot! diff --git a/deploy/chart/agents/values.yaml b/deploy/chart/agents/values.yaml index 770c9f969..b7da9d16d 100644 --- a/deploy/chart/agents/values.yaml +++ b/deploy/chart/agents/values.yaml @@ -1,100 +1,100 @@ -# 全局设置 +# Global Settings globals: - # 【必填】镜像仓库 + # [Required] Image Registry imageRegistry: "hub.oepkgs.net/neocopilot" - # 【必填】镜像拉取策略 + # [Required] Image Pull Policy imagePullPolicy: IfNotPresent -# OpenEuler产品Agents +# OpenEuler Product Agents agents: ai_infra: - # 【必填】是否启用AI容器镜像Agent + # [Required] Enable AI Container Image Agent enabled: true - # 镜像设置 + # Image Settings image: - # 镜像仓库。留空则使用全局设置。 + # Image registry. Leave empty to use global settings. registry: "" - # 【必填】镜像名 + # [Required] Image name name: compatibility-ai-infra - # 【必填】镜像Tag + # [Required] Image Tag tag: "0.9.1" - # 拉取策略。留空则使用全局设置 + # Pull policy. Leave empty to use global settings imagePullPolicy: "" - # 【必填】容器根目录只读 + # [Required] Container root directory read-only readOnly: true - # 性能限制设置 + # Resource limits settings resources: {} - # Service设置 + # Service Settings service: - # 【必填】Service类型,ClusterIP或NodePort + # [Required] Service type, ClusterIP or NodePort type: ClusterIP - nodePort: + nodePort: rca: - # 【必填】是否启用智能诊断Agent。必须配合智能诊断服务端使用。 + # [Required] Enable Intelligent Diagnostics Agent. Must be used with intelligent diagnostics server. enabled: true - # 镜像设置 + # Image Settings image: - # 镜像仓库。留空则使用全局设置。 + # Image registry. Leave empty to use global settings. registry: "hub.oepkgs.net/a-ops" - # 【必填】镜像名称 + # [Required] Image name name: euler-copilot-rca - # 【必填】镜像标签 + # [Required] Image tag tag: "0.9.1" - # 拉取策略。留空则使用全局设置。 + # Pull policy. Leave empty to use global settings. imagePullPolicy: "" - # 【必填】容器根目录只读 + # [Required] Container root directory read-only readOnly: true - # 性能限制设置 + # Resource limits settings resources: {} - # Service设置 + # Service Settings service: - # 【必填】Service类型,ClusterIP或NodePort + # [Required] Service type, ClusterIP or NodePort type: ClusterIP - nodePort: + nodePort: tune: - # 【必填】是否启用智能调优Agent。 + # [Required] Enable Intelligent Tuning Agent. enabled: true - # 镜像设置 + # Image Settings image: - # 镜像仓库。留空则使用全局设置。 + # Image registry. Leave empty to use global settings. registry: "" - # 【必填】镜像名称 + # [Required] Image name name: euler-copilot-tune - # 【必填】镜像标签 + # [Required] Image tag tag: "0.9.1" - # 拉取策略。留空则使用全局设置。 + # Pull policy. Leave empty to use global settings. imagePullPolicy: "" - # 【必填】容器根目录只读 + # [Required] Container root directory read-only readOnly: true - # 性能限制设置 + # Resource limits settings resources: {} - # Service设置 + # Service Settings service: - # 【必填】Service类型,ClusterIP或NodePort + # [Required] Service type, ClusterIP or NodePort type: ClusterIP - nodePort: - # 大模型设置 + nodePort: + # Large Language Model Settings llm: - # 【必填】模型地址(需要包含v1后缀) - url: - # 【必填】模型名称 + # [Required] Model URL (must include v1 suffix) + url: + # [Required] Model name name: "" - # 【必填】模型API Key + # [Required] Model API Key key: "" - # 【必填】模型最大Token数 + # [Required] Model maximum tokens max_tokens: 8096 - # 【必填】Embedding地址 + # [Required] Embedding URL embedding: "" - # 待优化机器信息 + # Target machine information for optimization machine: - # 【必填】IP地址 + # [Required] IP address ip: "" - # 【必填】Root用户密码 - # 注意:必需启用Root用户以密码形式SSH登录 + # [Required] Root user password + # Note: Must enable Root user SSH login with password password: "" - # 待优化应用设置 + # Target application settings for optimization mysql: - # 【必填】数据库用户名 + # [Required] Database username user: "root" - # 【必填】数据库密码 + # [Required] Database password password: "" diff --git a/deploy/chart/authhub/Chart.yaml b/deploy/chart/authhub/Chart.yaml index 59e2499f4..64e763d73 100644 --- a/deploy/chart/authhub/Chart.yaml +++ b/deploy/chart/authhub/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: authhub-chart -description: AuthHub Helm部署包 +description: AuthHub Helm Chart type: application version: 0.10.0 appVersion: "0.10.0" diff --git a/deploy/chart/authhub/templates/NOTES.txt b/deploy/chart/authhub/templates/NOTES.txt index 0d517be75..896a6441a 100644 --- a/deploy/chart/authhub/templates/NOTES.txt +++ b/deploy/chart/authhub/templates/NOTES.txt @@ -1,7 +1,7 @@ -感谢您使用openEuler Intelligence! -当前为0.10.0版本。 -当前Chart的功能为:AuthHub统一登录系统部署。 +Thank you for using openEuler Intelligence! +Current version is 0.10.0. +The current Chart functionality is: AuthHub Unified Login System deployment. -说明: -AuthHub的默认用户名为:administrator -AuthHub的默认密码为:changeme +Notes: +The default username for AuthHub is: administrator +The default password for AuthHub is: changeme diff --git a/deploy/chart/authhub/values.yaml b/deploy/chart/authhub/values.yaml index e6fc8fa88..fd2e249a3 100644 --- a/deploy/chart/authhub/values.yaml +++ b/deploy/chart/authhub/values.yaml @@ -1,72 +1,72 @@ -# 全局设置 +# Global Settings globals: - # 节点架构:默认是x86 - # [必填] 节点设置:["x86", "arm"] + # Node Architecture: default is x86 + # [Required] Node settings: ["x86", "arm"] arch: - # 镜像拉取策略;默认为IfNotPresent + # Image pull policy; default is IfNotPresent imagePullPolicy: - # 副本数,默认为1 + # Replica count, default is 1 replicaCount: - # 存储类名称;默认为local-path + # Storage class name; default is local-path storageClassName: storage: - # MySQL持久化存储大小,默认为10Gi + # MySQL persistent storage size, default is 10Gi mysql: domain: - # [必填] AuthHub web端URL, 默认是http://127.0.0.1:30081 + # [Required] AuthHub web URL, default is http://127.0.0.1:30081 authhub: -# 部署AuthHub本地鉴权服务 +# Deploy AuthHub local authentication service authhub: - # 配置文件工具 + # Configuration file tool secret_inject: - # 镜像设置;默认为hub.oepkgs.net/neocopilot/secret_inject:dev-x86 - # 镜像标签:["dev-x86", "dev-arm"] + # Image settings; default is hub.oepkgs.net/neocopilot/secret_inject:dev-x86 + # Image tags: ["dev-x86", "dev-arm"] image: web: - # [必填] 是否部署AuthHub前端服务 + # [Required] Whether to deploy AuthHub frontend service enabled: true - # 镜像设置;默认为hub.oepkgs.net/neocopilot/authhub-web:0.9.3-x86 - # 镜像标签:["0.9.3-x86", "0.9.3-arm"] + # Image settings; default is hub.oepkgs.net/neocopilot/authhub-web:0.9.3-x86 + # Image tags: ["0.9.3-x86", "0.9.3-arm"] image: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,例如NodePort + # Service type, e.g., NodePort type: NodePort - # 当类型为NodePort时,填写主机的端口号 + # When type is NodePort, specify the host port number nodePort: 30081 backend: - # [必填] 是否部署AuthHub后端服务 + # [Required] Whether to deploy AuthHub backend service enabled: true - # 镜像设置;默认为hub.oepkgs.net/neocopilot/authhub:0.9.3-x86 - # 镜像标签:["0.9.3-x86", "0.9.3-arm"] + # Image settings; default is hub.oepkgs.net/neocopilot/authhub:0.9.3-x86 + # Image tags: ["0.9.3-x86", "0.9.3-arm"] image: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,例如NodePort + # Service type, e.g., NodePort type: - # 当类型为NodePort时,填写主机的端口号 + # When type is NodePort, specify the host port number nodePort: mysql: - # [必填] 是否启用MySQL + # [Required] Whether to enable MySQL enabled: true - # 镜像设置;默认为hub.oepkgs.net/neocopilot/mysql:8-x86 - # 镜像标签:["8-x86", "8-arm"] + # Image settings; default is hub.oepkgs.net/neocopilot/mysql:8-x86 + # Image tags: ["8-x86", "8-arm"] image: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,例如NodePort + # Service type, e.g., NodePort type: - # 当类型为NodePort时,填写主机的端口号 + # When type is NodePort, specify the host port number nodePort: diff --git a/deploy/chart/databases/Chart.yaml b/deploy/chart/databases/Chart.yaml index 448a3c5f8..df548c6cd 100644 --- a/deploy/chart/databases/Chart.yaml +++ b/deploy/chart/databases/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: euler-copilot-databases -description: Euler Copilot 数据库 Helm部署包 +description: Euler Copilot Database Helm Chart type: application version: 0.10.0 appVersion: "0.10.0" diff --git a/deploy/chart/databases/templates/NOTES.txt b/deploy/chart/databases/templates/NOTES.txt index 5447b7de6..e845ceb64 100644 --- a/deploy/chart/databases/templates/NOTES.txt +++ b/deploy/chart/databases/templates/NOTES.txt @@ -1,3 +1,3 @@ -感谢您使用openEuler Intelligence! -当前为0.10.0版本。 -当前Chart的功能为:数据库部署。 +Thank you for using openEuler Intelligence! +The current version is 0.10.0. +The current Chart functionality is: Database Deployment. diff --git a/deploy/chart/databases/values.yaml b/deploy/chart/databases/values.yaml index ee614fd5a..a4c1bde8b 100644 --- a/deploy/chart/databases/values.yaml +++ b/deploy/chart/databases/values.yaml @@ -1,91 +1,92 @@ -# 全局设置 globals: - # 节点架构:默认是x86 - # 节点设置:["x86", "arm"] + # Node Architecture: default is x86 + # Node settings: ["x86", "arm"] arch: - # 部署副本数,默认为1 + # Deployment replica count, default is 1 replicaCount: - # 镜像拉取策略,默认为IfNotPresent - imagePullPolicy: - # 存储类,默认为local-path - storageClass: + # Image pull policy, default is IfNotPresent + imagePullPolicy: + # Storage class, default is local-path + storageClass: -# 存储设置 +# Storage Settings storage: - # MinIO存储大小,默认为10GB + # MinIO storage size, default is 10GB minio: - # 向量数据库存储大小,默认为10GB + # MongoDB storage size, default is 10GB + mongo: + # Vector database storage size, default is 10GB opengauss: - # PostgreSQL存储大小,默认为10GB + # PostgreSQL storage size, default is 10GB pgsql: -# 域名设置 +# Domain Settings domain: - # 需要修改为MinIO Console绑定的域名。单节点部署时,服务基于Host进行区分,无法使用IP地址 - minioConsole: + # Should be modified to the domain name bound to MinIO Console. + minioConsole: databases: minio: - # [必填] 是否部署MinIO实例 + # [Required] Whether to deploy MinIO instance enabled: true - # 镜像设置:默认为hub.oepkgs.net/neocopilot/minio:empty-x86 - # 镜像版本:["empty-x86", "empty-arm"] + # Image settings: default is hub.oepkgs.net/neocopilot/minio:empty-x86 + # Image versions: ["empty-x86", "empty-arm"] image: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,例如NodePort + # Service type, e.g., NodePort type: - # 当类型为NodePort时,填写MinIO数据端口对应的主机的端口号 + # When type is NodePort, specify the host port number corresponding to MinIO data port dataNodePort: - # 当类型为NodePort时,填写MinIO控制台对应的主机的端口号 + # When type is NodePort, specify the host port number corresponding to MinIO console consoleNodePort: - # Ingress设置 + # Ingress settings ingress: - # [必填] 是否暴露MinIO的Console + # [Required] Whether to expose MinIO Console enabled: true - # Ingress URL前缀 + # Ingress URL prefix prefix: / redis: - # [必填] 是否部署Redis实例 + # [Required] Whether to deploy Redis instance enabled: true - # 镜像设置,默认为hub.oepkgs.net/neocopilot/redis:7.4-alpine-x86 - # 镜像版本: ["7.4-alpine-x86", "7.4-alpine-arm"] + # Image settings, default is hub.oepkgs.net/neocopilot/redis:7.4-alpine-x86 + # Image versions: ["7.4-alpine-x86", "7.4-alpine-arm"] image: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,如NodePort + # Service type, e.g., NodePort type: - # 当类型为nodePort时,填写主机的端口号 - nodePort: + # When type is nodePort, specify the host port number + nodePort: opengauss: - # [必填] 是否部署PostgreSQL实例 + # [Required] Whether to deploy OpenGauss instance enabled: true - # 镜像设置,默认为hub.oepkgs.net/neocopilot/opengauss:latest-x86 - # 镜像版本: ["latest-x86", "latest-arm"] + # Image settings, default is hub.oepkgs.net/neocopilot/opengauss:latest-x86 + # Image versions: ["latest-x86", "latest-arm"] image: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,如NodePort + # Service type, e.g., NodePort type: - # 当类型为NodePort时,填写主机的端口号 + # When type is NodePort, specify the host port number nodePort: pgsql: - # [必填] 是否部署PostgreSQL实例 + # [Required] Whether to deploy PostgreSQL instance enabled: false - # 镜像设置,默认为hub.oepkgs.net/neocopilot/pgsql-empty:pg16-x86 - # 镜像版本: ["pg16-x86", "pg16-arm"] + # Image settings, default is hub.oepkgs.net/neocopilot/pgsql-empty:pg16-x86 + # Image versions: ["pg16-x86", "pg16-arm"] image: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,如NodePort + # Service type, e.g., NodePort type: - # 当类型为NodePort时,填写主机的端口号 + # When type is NodePort, specify the host port number nodePort: diff --git a/deploy/chart/euler_copilot/Chart.yaml b/deploy/chart/euler_copilot/Chart.yaml index 0d0497a95..781b5d466 100644 --- a/deploy/chart/euler_copilot/Chart.yaml +++ b/deploy/chart/euler_copilot/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: euler-copilot -description: Euler Copilot Helm部署包 +description: Euler Copilot Helm Chart type: application version: 0.10.0 appVersion: "0.10.0" diff --git a/deploy/chart/euler_copilot/configs/deepinsight/.env b/deploy/chart/euler_copilot/configs/deepinsight/.env index c51f1cc14..3fe5bebe4 100644 --- a/deploy/chart/euler_copilot/configs/deepinsight/.env +++ b/deploy/chart/euler_copilot/configs/deepinsight/.env @@ -4,8 +4,8 @@ MODEL_PLATFORM=deepseek # 支持列表见camel官方文档:https://docs.camel-ai.org/key_modules/models#direct-integrations MODEL_TYPE=deepseek-chat -MODEL_API_KEY=sk-882ee9907bdf4bf4afee6994dea5697b -DEEPSEEK_API_KEY=sk-882ee9907bdf4bf4afee6994dea5697b +MODEL_API_KEY=sk- +DEEPSEEK_API_KEY=sk- # 数据库配置,默认使用sqlite,支持postgresql和sqlite DB_TYPE=sqlite @@ -24,7 +24,7 @@ MONGODB_HOST=mongo-db.{{ .Release.Namespace }}.svc.cluster.local MONGODB_PORT=27017 MONGODB_DATABASE=euler_copilot -# 是否需要认证鉴权: deepInsight集成到openeuler intelligence依赖认证健全,如果单用户部署则不需要,默认用户为admin +# 是否需要认证鉴权: deepInsight集成到openeuler intelligence依赖认证鉴权,如果单用户部署则不需要,默认用户为admin REQUIRE_AUTHENTICATION=false # 默认监听地址和端口 diff --git a/deploy/chart/euler_copilot/templates/NOTES.txt b/deploy/chart/euler_copilot/templates/NOTES.txt index fdb725dd2..48a494921 100644 --- a/deploy/chart/euler_copilot/templates/NOTES.txt +++ b/deploy/chart/euler_copilot/templates/NOTES.txt @@ -1,5 +1,5 @@ -感谢您使用openEuler Intelligence! -当前为0.10.0版本。 -当前Chart的功能为:openEuler Intelligence核心组件部署。 +Thank you for using openEuler Intelligence! +Current version is 0.10.0. +The current Chart functionality is: openEuler Intelligence Core Components Deployment. -更多项目动态和分享会议,请关注openEuler sig-intelligence:https://www.openeuler.org/en/sig/sig-detail/?name=sig-intelligence +For more project updates and sharing sessions, please follow openEuler sig-intelligence: https://www.openeuler.org/en/sig/sig-detail/?name=sig-intelligence diff --git a/deploy/chart/euler_copilot/templates/deepinsight/deepinsight.yaml b/deploy/chart/euler_copilot/templates/deepinsight/deepinsight.yaml index 8f987af21..5a5bfdddc 100644 --- a/deploy/chart/euler_copilot/templates/deepinsight/deepinsight.yaml +++ b/deploy/chart/euler_copilot/templates/deepinsight/deepinsight.yaml @@ -1,3 +1,4 @@ +@@ -1,102 +0,0 @@ {{- if .Values.euler_copilot.deepinsight.enabled -}} --- apiVersion: v1 @@ -99,4 +100,5 @@ spec: - name: deepinsight-shared emptyDir: medium: Memory -{{- end -}} \ No newline at end of file +{{- end -}} +No newline at end of file diff --git a/deploy/chart/euler_copilot/templates/web/web-config.yaml b/deploy/chart/euler_copilot/templates/web/web-config.yaml index 77c79a85a..1793023e1 100644 --- a/deploy/chart/euler_copilot/templates/web/web-config.yaml +++ b/deploy/chart/euler_copilot/templates/web/web-config.yaml @@ -8,5 +8,4 @@ data: .env: |- RAG_WEB_URL=http://rag-web-service.{{ .Release.Namespace }}.svc.cluster.local:9888 FRAMEWORK_URL=http://framework-service.{{ .Release.Namespace }}.svc.cluster.local:8002 - DEEPINSIGHT_WEB_URL=http://deepinsight-web-service.{{ .Release.Namespace }}.svc.cluster.local:9222 {{- end -}} \ No newline at end of file diff --git a/deploy/chart/euler_copilot/values.yaml b/deploy/chart/euler_copilot/values.yaml index 2990ca90b..6104cb5b5 100644 --- a/deploy/chart/euler_copilot/values.yaml +++ b/deploy/chart/euler_copilot/values.yaml @@ -1,157 +1,155 @@ -# 全局设置 +# Global Settings globals: - # 节点架构:默认是x86 - # [必填] 节点设置:["x86", "arm"] + # Node Architecture: default is x86 + # [Required] Node settings: ["x86", "arm"] arch: - # 镜像拉取策略, 默认为IfNotPresent + # Image pull policy, default is IfNotPresent imagePullPolicy: - # 存储类;默认为local-path + # Storage class; default is local-path storageClass: -# 模型设置 +# Model Settings models: - # 用于问答的大模型;需要为OpenAI兼容接口 + # Large language model for Q&A; requires OpenAI-compatible API answer: - # [必填] 接口URL(请根据 API 提供商文档确定是否需要带上“v1”后缀) + # [Required] API endpoint URL (please check API provider documentation whether to include "v1" suffix) endpoint: - # [必填] 接口API Key;默认置空 + # [Required] API Key; empty by default key: - # [必填] 模型名称 + # [Required] Model name name: - # [必填] 模型最大上下文数;建议>=8192 + # [Required] Model maximum context length; recommended >=8192 ctxLength: 8192 - # 模型最大输出长度,建议>=2048 + # Model maximum output length, recommended >=2048 maxTokens: 2048 - # 用于Function Call的模型;建议使用特定推理框架 + # Model for Function Call; recommended to use specific inference framework functionCall: - # 推理框架类型,默认为ollama - # 可用的框架类型:["vllm", "sglang", "ollama", "openai"] + # Inference framework type, default is ollama + # Available framework types: ["vllm", "sglang", "ollama", "openai"] backend: - # [必填] 模型地址;请根据 API 提供商文档确定是否需要带上“v1”后缀 - # 选择不填则与问答模型一致 + # [Required] Model endpoint; please check API provider documentation whether to include "v1" suffix + # Leave empty to use same as Q&A model endpoint: - # API Key;不填则与问答模型一致 + # API Key; leave empty to use same as Q&A model key: - # 模型名称;不填则与问答模型一致 + # Model name; leave empty to use same as Q&A model name: - # 模型最大上下文数;不填则与问答模型一致 + # Model maximum context length; leave empty to use same as Q&A model ctxLength: - # 模型最大输出长度;不填则与问答模型一致 + # Model maximum output length; leave empty to use same as Q&A model maxTokens: - # 用于数据向量化(Embedding)的模型 + # Model for data embedding embedding: - # 推理框架类型,默认为openai - # [必填] Embedding接口类型:["openai", "mindie"] + # Inference framework type, default is openai + # [Required] Embedding API type: ["openai", "mindie"] type: - # [必填] Embedding URL(需要带上“v1”后缀) + # [Required] Embedding URL (requires "v1" suffix) endpoint: - # [必填] Embedding 模型API Key + # [Required] Embedding model API Key key: - # [必填] Embedding 模型名称 + # [Required] Embedding model name name: -# 登录设置 +# Login Settings login: - # 客户端ID设置,仅在type为authhub时有效 + # Client ID settings, only effective when type is authhub client: - # [必填] 客户端ID - id: - # [必填] 客户端密钥 - secret: + # [Required] Client ID + id: FKULtX09EKMXxaCNft5Aqtww + # [Required] Client secret + secret: Hw2QtzGP2gkuU4FQPA7v1rjbLVG5J68exq4x1eR7ITrNxtDj -#域名设置 +# Domain Settings domain: - # [必填] EulerCopilot的web前端url;默认为http://127.0.0.1:30080 - euler_copilot: - # [必填] authhub的web前端url;默认为http://127.0.0.1:30081 - authhub: + # [Required] EulerCopilot web frontend URL; default is http://127.0.0.1:30080 + euler_copilot: http://139.9.242.191:30080 + # [Required] AuthHub web frontend URL; default is http://127.0.0.1:30081 + authhub: http://139.9.242.191:30081 -# 存储设置 +# Storage Settings storage: - # 语义接口 + # Framework semantics frameworkSemantics: - # 语义接口地址 + # Framework semantics path path: - # 语义接口存储大小,默认为5GB + # Framework semantics storage size, default is 5GB size: - # 共享存储 + # Shared storage webAsset: - # 前后端共享存储大小,默认为10GB + # Frontend/backend shared storage size, default is 10GB size: euler_copilot: - # 配置文件工具 + # Configuration file tool secretInject: - # 镜像设置;默认为hub.oepkgs.net/neocopilot/secret_inject:dev-x86 - # 镜像标签:["dev-x86", "dev-arm"] + # Image settings; default is hub.oepkgs.net/neocopilot/secret_inject:dev-x86 + # Image tags: ["dev-x86", "dev-arm"] image: framework: - # [必填] 是否部署Framework后端框架服务 + # [Required] Whether to deploy Framework backend service enabled: true - # 镜像设置;默认为hub.oepkgs.net/neocopilot/euler-copilot-framework:0.10.0-x86 - # 镜像标签:["0.10.0-x86", "0.10.0-arm"] + # Image settings; default is hub.oepkgs.net/neocopilot/euler-copilot-framework:0.10.0-x86 + # Image tags: ["0.10.0-x86", "0.10.0-arm"] image: - # 容器根目录只读 + # Container root directory read-only readOnly: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,例如NodePorts + # Service type, e.g., NodePort type: - # 当类型为nodePort时,填写主机的端口号 + # When type is nodePort, specify the host port number nodePort: web: - # [必填] 是否部署Web前端用户界面 + # [Required] Whether to deploy Web frontend user interface enabled: true - # 镜像设置;默认为hub.oepkgs.net/neocopilot/euler-copilot-web:0.10.0-x86 - # 镜像标签:["0.10.0-x86", "0.10.0-arm"] + # Image settings; default is hub.oepkgs.net/neocopilot/euler-copilot-web:0.10.0-x86 + # Image tags: ["0.10.0-x86", "0.10.0-arm"] image: - # 容器根目录只读 + # Container root directory read-only readOnly: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,例如NodePort + # Service type, e.g., NodePort type: NodePort - # 当类型为NodePort时,填写主机的端口号 + # When type is NodePort, specify the host port number nodePort: 30080 rag_web: - # [必填] 是否部署RAG Web前端用户界面 + # [Required] Whether to deploy RAG Web frontend user interface enabled: true - # 镜像设置;默认为hub.oepkgs.net/neocopilot/data_chain_web:0.10.0-x86 - # 镜像标签:["0.10.0-x86", "0.10.0-arm"] + # Image settings; default is hub.oepkgs.net/neocopilot/data_chain_web:0.10.0-x86 + # Image tags: ["0.10.0-x86", "0.10.0-arm"] image: - # 容器根目录只读 + # Container root directory read-only readOnly: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,例如NodePort + # Service type, e.g., NodePort type: - # 当类型为NodePort时,填写主机的端口号 + # When type is NodePort, specify the host port number nodePort: rag: - # [必填] 是否部署RAG后端服务 + # [Required] Whether to deploy RAG backend service enabled: true - # 镜像设置;默认为hub.oepkgs.net/neocopilot/data_chain_back_end:0.10.0-x86 - # 镜像标签:["0.10.0-x86", "0.10.0-arm"] + # Image settings; default is hub.oepkgs.net/neocopilot/data_chain_back_end:0.10.0-x86 + # Image tags: ["0.10.0-x86", "0.10.0-arm"] image: - # 容器根目录只读 + # Container root directory read-only readOnly: - # 性能限制设置 + # Resource limits settings resourceLimits: {} - # Service设置 + # Service settings service: - # Service类型,例如NodePort + # Service type, e.g., NodePort type: - # 当类型为NodePort时,填写主机的端口号 + # When type is NodePort, specify the host port number nodePort: - - diff --git a/deploy/chart_ssl/traefik-config.yml b/deploy/common/chart_ssl/traefik-config.yml similarity index 100% rename from deploy/chart_ssl/traefik-config.yml rename to deploy/common/chart_ssl/traefik-config.yml diff --git a/deploy/chart_ssl/traefik-secret.yaml b/deploy/common/chart_ssl/traefik-secret.yaml similarity index 100% rename from deploy/chart_ssl/traefik-secret.yaml rename to deploy/common/chart_ssl/traefik-secret.yaml diff --git a/deploy/chart_ssl/traefik-tlsstore.yaml b/deploy/common/chart_ssl/traefik-tlsstore.yaml similarity index 100% rename from deploy/chart_ssl/traefik-tlsstore.yaml rename to deploy/common/chart_ssl/traefik-tlsstore.yaml diff --git a/deploy/secret_helper/Dockerfile b/deploy/common/secret_helper/Dockerfile similarity index 100% rename from deploy/secret_helper/Dockerfile rename to deploy/common/secret_helper/Dockerfile diff --git a/deploy/secret_helper/__init__.py b/deploy/common/secret_helper/__init__.py similarity index 100% rename from deploy/secret_helper/__init__.py rename to deploy/common/secret_helper/__init__.py diff --git a/deploy/secret_helper/config.example.yaml b/deploy/common/secret_helper/config.example.yaml similarity index 100% rename from deploy/secret_helper/config.example.yaml rename to deploy/common/secret_helper/config.example.yaml diff --git a/deploy/secret_helper/file_copy.py b/deploy/common/secret_helper/file_copy.py similarity index 100% rename from deploy/secret_helper/file_copy.py rename to deploy/common/secret_helper/file_copy.py diff --git a/deploy/secret_helper/job.py b/deploy/common/secret_helper/job.py similarity index 100% rename from deploy/secret_helper/job.py rename to deploy/common/secret_helper/job.py diff --git a/deploy/secret_helper/main.py b/deploy/common/secret_helper/main.py similarity index 100% rename from deploy/secret_helper/main.py rename to deploy/common/secret_helper/main.py diff --git a/deploy/secret_helper/requirements.txt b/deploy/common/secret_helper/requirements.txt similarity index 100% rename from deploy/secret_helper/requirements.txt rename to deploy/common/secret_helper/requirements.txt diff --git a/deploy/scripts/0-one-click-deploy/one-click-deploy_en.sh b/deploy/scripts/0-one-click-deploy/one-click-deploy_en.sh new file mode 100644 index 000000000..f44178e41 --- /dev/null +++ b/deploy/scripts/0-one-click-deploy/one-click-deploy_en.sh @@ -0,0 +1,294 @@ +#!/bin/bash + +# Enhanced color definitions +RESET='\033[0m' +BOLD='\033[1m' +RED='\033[38;5;196m' +GREEN='\033[38;5;46m' +YELLOW='\033[38;5;226m' +BLUE='\033[38;5;45m' +MAGENTA='\033[38;5;201m' +CYAN='\033[38;5;51m' +WHITE='\033[38;5;255m' +BG_RED='\033[48;5;196m' +BG_GREEN='\033[48;5;46m' +BG_BLUE='\033[48;5;45m' +DIM='\033[2m' + +# Progress bar width +PROGRESS_WIDTH=50 +NAMESPACE="euler-copilot" +TIMEOUT=300 # Max wait time (seconds) +INTERVAL=10 # Check interval (seconds) + +# Global variables +authhub_address="" +eulercopilot_address="" + +# Parse command line arguments +parse_arguments() { + while [[ $# -gt 0 ]]; do + case "$1" in + --eulercopilot_address) + if [ -n "$2" ]; then + eulercopilot_address="$2" + shift 2 + else + echo -e "${RED}Error: --eulercopilot_address requires a value${RESET}" >&2 + exit 1 + fi + ;; + --authhub_address) + if [ -n "$2" ]; then + authhub_address="$2" + shift 2 + else + echo -e "${RED}Error: --authhub_address requires a value${RESET}" >&2 + exit 1 + fi + ;; + *) + echo -e "${RED}Unknown option: $1${RESET}" >&2 + exit 1 + ;; + esac + done +} + +# Prompt user for required parameters +prompt_for_addresses() { + # If eulercopilot_address not provided via command line, prompt user + if [ -z "$eulercopilot_address" ]; then + echo -e "${YELLOW}EulerCopilot address not provided${RESET}" + read -p "$(echo -e "${CYAN}Enter EulerCopilot address (e.g., http://myhost:30080): ${RESET}")" eulercopilot_address + + # Validate input not empty + while [ -z "$eulercopilot_address" ]; do + echo -e "${RED}Error: EulerCopilot address cannot be empty${RESET}" + read -p "$(echo -e "${CYAN}Enter EulerCopilot address (e.g., http://myhost:30080): ${RESET}")" eulercopilot_address + done + fi + + # If authhub_address not provided via command line, prompt user + if [ -z "$authhub_address" ]; then + echo -e "${YELLOW}Authhub address not provided${RESET}" + read -p "$(echo -e "${CYAN}Enter Authhub address (e.g., http://myhost:30081): ${RESET}")" authhub_address + + # Validate input not empty + while [ -z "$authhub_address" ]; do + echo -e "${RED}Error: Authhub address cannot be empty${RESET}" + read -p "$(echo -e "${CYAN}Enter Authhub address (e.g., http://myhost:30081): ${RESET}")" authhub_address + done + fi +} + +# Colorful progress bar function +colorful_progress() { + local current=$1 + local total=$2 + local progress=$((current*100/total)) + local completed=$((PROGRESS_WIDTH*current/total)) + local remaining=$((PROGRESS_WIDTH-completed)) + + printf "\r${BOLD}${BLUE}⟦${RESET}" + printf "${BG_BLUE}${WHITE}%${completed}s${RESET}" | tr ' ' '▌' + printf "${DIM}${BLUE}%${remaining}s${RESET}" | tr ' ' '·' + printf "${BOLD}${BLUE}⟧${RESET} ${GREEN}%3d%%${RESET} ${CYAN}[%d/%d]${RESET}" \ + $progress $current $total +} + +# Print separator line +print_separator() { + echo -e "${BLUE}${BOLD}$(printf '━%.0s' $(seq 1 $(tput cols)))${RESET}" +} + +# Print step title +print_step_title() { + echo -e "\n${BG_BLUE}${WHITE}${BOLD} Step $1 ${RESET} ${MAGENTA}${BOLD}$2${RESET}" + echo -e "${DIM}${BLUE}$(printf '━%.0s' $(seq 1 $(tput cols)))${RESET}" +} + +# Get main script absolute path and switch to its directory +MAIN_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +cd "$MAIN_DIR" || exit 1 + +run_script_with_check() { + local script_path=$1 + local script_name=$2 + local step_number=$3 + local auto_input=${4:-false} + shift 4 + local extra_args=("$@") # Use array for extra parameters + + # Pre-check: script exists + if [ ! -f "$script_path" ]; then + echo -e "\n${BOLD}${RED}✗ Fatal error:${RESET}${YELLOW}${script_name}${RESET}${RED} not found (path: ${CYAN}${script_path}${RED})${RESET}" >&2 + exit 1 + fi + + print_step_title $step_number "$script_name" + + # Get absolute path and execution directory + local script_abs_path=$(realpath "$script_path") + local script_dir=$(dirname "$script_abs_path") + local script_base=$(basename "$script_abs_path") + + echo -e "${DIM}${BLUE}🠖 Script path: ${YELLOW}${script_abs_path}${RESET}" + echo -e "${DIM}${BLUE}🠖 Working directory: ${YELLOW}${script_dir}${RESET}" + echo -e "${DIM}${BLUE}🠖 Extra args: ${YELLOW}${extra_args[*]}${RESET}" + echo -e "${DIM}${BLUE}🠖 Start time: ${YELLOW}$(date +'%Y-%m-%d %H:%M:%S')${RESET}" + + # Create temporary log file + local log_file=$(mktemp) + echo -e "${DIM}${BLUE}🠖 Temp log: ${YELLOW}${log_file}${RESET}" + + # Execute script (with auto-input and real-time logging) + local exit_code=0 + if $auto_input; then + (cd "$script_dir" && yes "" | bash "./$script_base" "${extra_args[@]}" 2>&1 | tee "$log_file") + else + (cd "$script_dir" && bash "./$script_base" "${extra_args[@]}" 2>&1 | tee "$log_file") + fi + exit_code=${PIPESTATUS[0]} + + # Handle execution result + if [ $exit_code -eq 0 ]; then + echo -e "\n${BOLD}${GREEN}✓ ${script_name} executed successfully!${RESET}" + echo -e "${DIM}${CYAN}$(printf '%.0s─' $(seq 1 $(tput cols)))${RESET}" + echo -e "${DIM}${CYAN}Operation log:${RESET}" + cat "$log_file" | sed -e "s/^/${DIM}${CYAN} 🠖 ${RESET}/" + echo -e "${DIM}${CYAN}$(printf '%.0s─' $(seq 1 $(tput cols)))${RESET}" + else + echo -e "\n${BOLD}${RED}✗ ${script_name} execution failed!${RESET}" >&2 + echo -e "${DIM}${RED}$(printf '%.0s─' $(seq 1 $(tput cols)))${RESET}" >&2 + echo -e "${DIM}${RED}Error log:${RESET}" >&2 + cat "$log_file" | sed -e "s/^/${DIM}${RED} ✗ ${RESET}/" >&2 + echo -e "${DIM}${RED}$(printf '%.0s─' $(seq 1 $(tput cols)))${RESET}" >&2 + rm "$log_file" + exit 1 + fi + + rm "$log_file" + return $exit_code +} + +# Uninstall all components +uninstall_all() { + echo -e "\n${CYAN}▸ Uninstalling all Helm Releases...${RESET}" + local RELEASES + RELEASES=$(helm list -n $NAMESPACE --short 2>/dev/null || true) + + if [ -n "$RELEASES" ]; then + echo -e "${YELLOW}Found Helm Releases:${RESET}" + echo "$RELEASES" | awk '{print " ➤ "$0}' + for release in $RELEASES; do + echo -e "${BLUE}Deleting: ${release}${RESET}" + helm uninstall "$release" -n $NAMESPACE || echo -e "${RED}Delete failed, continuing...${RESET}" + done + else + echo -e "${YELLOW}No Helm Releases to clean${RESET}" + fi + + echo -e "\n${CYAN}▸ Cleaning persistent storage...${RESET}" + local pvc_list + pvc_list=$(kubectl get pvc -n $NAMESPACE -o name 2>/dev/null || true) + + if [ -n "$pvc_list" ]; then + echo -e "${YELLOW}Found PVC resources:${RESET}" + echo "$pvc_list" | awk '{print " ➤ "$0}' + echo "$pvc_list" | xargs -n 1 kubectl delete -n $NAMESPACE || echo -e "${RED}Delete failed, continuing...${RESET}" + else + echo -e "${YELLOW}No PVCs to clean${RESET}" + fi + + echo -e "\n${CYAN}▸ Cleaning Secret resources...${RESET}" + local secret_list + secret_list=$(kubectl get secret -n $NAMESPACE -o name 2>/dev/null || true) + + if [ -n "$secret_list" ]; then + echo -e "${YELLOW}Found Secret resources:${RESET}" + echo "$secret_list" | awk '{print " ➤ "$0}' + echo "$secret_list" | xargs -n 1 kubectl delete -n $NAMESPACE || echo -e "${RED}Delete failed, continuing...${RESET}" + else + echo -e "${YELLOW}No Secrets to clean${RESET}" + fi + + echo -e "\n${BG_GREEN}${WHITE}${BOLD} ✓ Complete ${RESET} ${GREEN}All resources cleaned${RESET}" +} + +# Main header display +show_header() { + clear + echo -e "\n${BOLD}${MAGENTA}$(printf '✧%.0s' $(seq 1 $(tput cols)))${RESET}" + echo -e "${BOLD}${WHITE} Euler Copilot One-Click Deployment System ${RESET}" + echo -e "${BOLD}${MAGENTA}$(printf '✧%.0s' $(seq 1 $(tput cols)))${RESET}" + echo -e "${CYAN}◈ Main directory: ${YELLOW}${MAIN_DIR}${RESET}" + echo -e "${CYAN}◈ EulerCopilot address: ${YELLOW}${eulercopilot_address:-Not set}${RESET}" + echo -e "${CYAN}◈ Authhub address: ${YELLOW}${authhub_address:-Not set}${RESET}\n" +} + +# Modified start_deployment function step configuration +start_deployment() { + local total_steps=8 + local current_step=1 + + # Step configuration (script_path script_name auto_input extra_args_array) + local steps=( + "../1-check-env/check_env.sh Environment check false" + "_conditional_tools_step Basic tools installation(k3s+helm) true" + "../3-install-ollama/install_ollama.sh Ollama deployment true" + "../4-deploy-deepseek/deploy_deepseek.sh Deepseek model deployment false" + "../5-deploy-embedding/deploy-embedding.sh Embedding service deployment false" + "../6-install-databases/install_databases.sh Database cluster deployment false" + "../7-install-authhub/install_authhub.sh Authhub deployment true --authhub_address ${authhub_address}" + "_conditional_eulercopilot_step EulerCopilot deployment true" + ) + + for step in "${steps[@]}"; do + local script_path=$(echo "$step" | awk '{print $1}') + local script_name=$(echo "$step" | awk '{print $2}') + local auto_input=$(echo "$step" | awk '{print $3}') + local extra_args=$(echo "$step" | awk '{for(i=4;i<=NF;i++) printf $i" "}') + + # Special step handling + if [[ "$script_path" == "_conditional_tools_step" ]]; then + handle_tools_step $current_step + elif [[ "$script_path" == "_conditional_eulercopilot_step" ]]; then + sleep 60 + handle_eulercopilot_step $current_step + else + run_script_with_check "$script_path" "$script_name" $current_step $auto_input $extra_args + fi + + colorful_progress $current_step $total_steps + ((current_step++)) + done +} + +# Handle tools installation step +handle_tools_step() { + local current_step=$1 + if command -v k3s >/dev/null 2>&1 && command -v helm >/dev/null 2>&1; then + echo -e "${CYAN}🠖 k3s and helm detected, performing environment cleanup...${RESET}" + uninstall_all + else + run_script_with_check "../2-install-tools/install_tools.sh" "Basic tools installation" $current_step true + fi +} + +handle_eulercopilot_step() { + local current_step=$1 + local extra_args=() + + # Build extra arguments array + [ -n "$authhub_address" ] && extra_args+=(--authhub_address "$authhub_address") + [ -n "$eulercopilot_address" ] && extra_args+=(--eulercopilot_address "$eulercopilot_address") + + run_script_with_check "../8-install-EulerCopilot/install_eulercopilot.sh" "EulerCopilot deployment" $current_step true "${extra_args[@]}" +} + +# Main execution flow +parse_arguments "$@" +prompt_for_addresses +show_header +start_deployment diff --git a/deploy/scripts/0-one-click-deploy/one-click-deploy.sh b/deploy/scripts/0-one-click-deploy/one-click-deploy_zh.sh old mode 100755 new mode 100644 similarity index 100% rename from deploy/scripts/0-one-click-deploy/one-click-deploy.sh rename to deploy/scripts/0-one-click-deploy/one-click-deploy_zh.sh diff --git a/deploy/scripts/1-check-env/check_env_en.sh b/deploy/scripts/1-check-env/check_env_en.sh new file mode 100644 index 000000000..0ab87a24c --- /dev/null +++ b/deploy/scripts/1-check-env/check_env_en.sh @@ -0,0 +1,250 @@ +#!/bin/bash + +# Color definitions +COLOR_INFO='\033[34m' # Blue info +COLOR_SUCCESS='\033[32m' # Green success +COLOR_ERROR='\033[31m' # Red error +COLOR_WARNING='\033[33m' # Yellow warning +COLOR_RESET='\033[0m' # Reset color + +# Global mode flag +OFFLINE_MODE=false + +function check_user { + if [[ $(id -u) -ne 0 ]]; then + echo -e "${COLOR_ERROR}[Error] Please run this script with root privileges!${COLOR_RESET}" + return 1 + fi + return 0 +} + +function check_version { + local current_version_id="$1" + local supported_versions=("${@:2}") + + echo -e "${COLOR_INFO}[Info] Current OS version: $current_version_id${COLOR_RESET}" + for version_id in "${supported_versions[@]}"; do + if [[ "$current_version_id" == "$version_id" ]]; then + echo -e "${COLOR_SUCCESS}[Success] OS meets compatibility requirements${COLOR_RESET}" + return 0 + fi + done + + echo -e "${COLOR_ERROR}[Error] OS does not meet compatibility requirements, script will exit${COLOR_RESET}" + return 1 +} + +function check_os_version { + local id=$(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"') + local version=$(grep -E "^VERSION_ID=" /etc/os-release | cut -d '"' -f 2) + + echo -e "${COLOR_INFO}[Info] Current distribution: $id${COLOR_RESET}" + + case $id in + "openEuler"|"bclinux") + local supported_versions=("22.03" "22.09" "23.03" "23.09" "24.03") + check_version "$version" "${supported_versions[@]}" + ;; + "InLinux") + local supported_versions=("23.12") + check_version "$version" "${supported_versions[@]}" + ;; + "FusionOS") + local supported_versions=("23") + check_version "$version" "${supported_versions[@]}" + ;; + "uos") + local supported_versions=("20") + check_version "$version" "${supported_versions[@]}" + ;; + "HopeOS") + local supported_versions=("V22") + check_version "$version" "${supported_versions[@]}" + ;; + "kylin") + local supported_versions=("V10") + check_version "$version" "${supported_versions[@]}" + ;; + *) + echo -e "${COLOR_ERROR}[Error] Distribution not supported, script will exit${COLOR_RESET}" + return 1 + ;; + esac + return $? +} + +function check_hostname { + local current_hostname=$(cat /etc/hostname) + if [[ -z "$current_hostname" ]]; then + echo -e "${COLOR_ERROR}[Error] Hostname not set, automatically set to localhost${COLOR_RESET}" + set_hostname "localhost" + return $? + else + echo -e "${COLOR_INFO}[Info] Current hostname: $current_hostname${COLOR_RESET}" + echo -e "${COLOR_SUCCESS}[Success] Hostname is set${COLOR_RESET}" + return 0 + fi +} + +function set_hostname { + if ! command -v hostnamectl &> /dev/null; then + echo "$1" > /etc/hostname + echo -e "${COLOR_SUCCESS}[Success] Manual hostname set successful${COLOR_RESET}" + return 0 + fi + + if hostnamectl set-hostname "$1"; then + echo -e "${COLOR_SUCCESS}[Success] Hostname set successfully${COLOR_RESET}" + return 0 + else + echo -e "${COLOR_ERROR}[Error] Hostname set failed${COLOR_RESET}" + return 1 + fi +} + +function check_dns { + echo -e "${COLOR_INFO}[Info] Checking DNS settings${COLOR_RESET}" + if grep -q "^nameserver" /etc/resolv.conf; then + echo -e "${COLOR_SUCCESS}[Success] DNS configured${COLOR_RESET}" + return 0 + fi + + if $OFFLINE_MODE; then + echo -e "${COLOR_WARNING}[Warning] Offline mode: Please manually configure internal DNS server${COLOR_RESET}" + return 0 + else + echo -e "${COLOR_ERROR}[Error] DNS not configured, automatically set to 8.8.8.8${COLOR_RESET}" + set_dns "8.8.8.8" + return $? + fi +} + +function set_dns { + if systemctl is-active --quiet NetworkManager; then + local net_ic=$(nmcli -t -f NAME con show --active | head -n 1) + if [[ -z "$net_ic" ]]; then + echo -e "${COLOR_ERROR}[Error] No active network connection found${COLOR_RESET}" + return 1 + fi + + if nmcli con mod "$net_ic" ipv4.dns "$1" && nmcli con mod "$net_ic" ipv4.ignore-auto-dns yes; then + nmcli con down "$net_ic" && nmcli con up "$net_ic" + echo -e "${COLOR_SUCCESS}[Success] DNS set successfully${COLOR_RESET}" + return 0 + else + echo -e "${COLOR_ERROR}[Error] DNS set failed${COLOR_RESET}" + return 1 + fi + else + cp /etc/resolv.conf /etc/resolv.conf.bak + echo "nameserver $1" >> /etc/resolv.conf + echo -e "${COLOR_SUCCESS}[Success] Manual DNS set successful${COLOR_RESET}" + return 0 + fi +} + +function check_ram { + local RAM_THRESHOLD=16000 + local current_mem=$(free -m | awk '/Mem/{print $2}') + + echo -e "${COLOR_INFO}[Info] Current memory: $current_mem MB${COLOR_RESET}" + if (( current_mem < RAM_THRESHOLD )); then + echo -e "${COLOR_ERROR}[Error] Insufficient memory ${RAM_THRESHOLD} MB${COLOR_RESET}" + return 1 + fi + echo -e "${COLOR_SUCCESS}[Success] Memory meets requirements${COLOR_RESET}" + return 0 +} + +check_disk_space() { + local DIR="$1" + local THRESHOLD="$2" + + local USAGE=$(df --output=pcent "$DIR" | tail -n 1 | sed 's/%//g' | tr -d ' ') + + if [ "$USAGE" -ge "$THRESHOLD" ]; then + echo -e "${COLOR_WARNING}[Warning] Disk usage for $DIR has reached ${USAGE}%, exceeding threshold ${THRESHOLD}%${COLOR_RESET}" + return 1 + else + echo -e "${COLOR_INFO}[Info] Disk usage for $DIR is ${USAGE}%, below threshold ${THRESHOLD}%${COLOR_RESET}" + return 0 + fi +} + +function check_network { + echo -e "${COLOR_INFO}[Info] Checking network connection...${COLOR_RESET}" + + # Use TCP check instead of curl + if timeout 5 bash -c 'cat < /dev/null > /dev/tcp/www.baidu.com/80' 2>/dev/null; then + echo -e "${COLOR_SUCCESS}[Success] Network connection normal${COLOR_RESET}" + return 0 + else + echo -e "${COLOR_ERROR}[Error] Cannot access external network${COLOR_RESET}" + return 1 + fi +} + +function check_selinux { + sed -i 's/^SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config + echo -e "${COLOR_SUCCESS}[Success] SELinux configuration disabled${COLOR_RESET}" + setenforce 0 &>/dev/null + echo -e "${COLOR_SUCCESS}[Success] SELinux temporarily disabled${COLOR_RESET}" + return 0 +} + +function check_firewall { + systemctl disable --now firewalld &>/dev/null + echo -e "${COLOR_SUCCESS}[Success] Firewall closed and disabled${COLOR_RESET}" + return 0 +} + +function prepare_offline { + echo -e "${COLOR_INFO}[Info] Preparing offline deployment environment..." + mkdir -p /home/eulercopilot/images + mkdir -p /home/eulercopilot/tools + mkdir -p /home/eulercopilot/models + echo -e "1. Please ensure offline installation images are uploaded to /home/eulercopilot/images" + echo -e "2. Please confirm local software repository is configured" + echo -e "3. All tool packages pre-downloaded to local directory /home/eulercopilot/tools" + echo -e "4. All model files pre-downloaded to local directory /home/eulercopilot/models${COLOR_RESET}" +} + +function main { + check_user || return 1 + check_os_version || return 1 + check_hostname || return 1 + + # Network check and mode determination + if check_network; then + OFFLINE_MODE=false + else + OFFLINE_MODE=true + echo -e "${COLOR_WARNING}[Warning] Switching to offline deployment mode${COLOR_RESET}" + prepare_offline + fi + + check_dns || return 1 + check_ram || return 1 + check_disk_space "/" 70 + + if [ $? -eq 1 ]; then + echo -e "${COLOR_WARNING}[Warning] Disk space cleanup required!${COLOR_RESET}" + else + echo -e "${COLOR_SUCCESS}[Success] Disk space normal${COLOR_RESET}" + fi + + check_selinux || return 1 + check_firewall || return 1 + + # Final deployment prompt + echo -e "\n${COLOR_SUCCESS}#####################################" + if $OFFLINE_MODE; then + echo -e "# Environment check complete, ready for offline deployment #" + else + echo -e "# Environment check complete, ready for online deployment #" + fi + echo -e "#####################################${COLOR_RESET}" + return 0 +} + +main diff --git a/deploy/scripts/1-check-env/check_env.sh b/deploy/scripts/1-check-env/check_env_zh.sh old mode 100755 new mode 100644 similarity index 100% rename from deploy/scripts/1-check-env/check_env.sh rename to deploy/scripts/1-check-env/check_env_zh.sh diff --git a/deploy/scripts/2-install-tools/install_tools_en.sh b/deploy/scripts/2-install-tools/install_tools_en.sh new file mode 100644 index 000000000..4346d0b82 --- /dev/null +++ b/deploy/scripts/2-install-tools/install_tools_en.sh @@ -0,0 +1,381 @@ +#!/bin/bash + +GITHUB_MIRROR="https://gh-proxy.com" +ARCH=$(uname -m) +TOOLS_DIR="/home/eulercopilot/tools" +eulercopilot_version=0.10.0 + +SCRIPT_PATH="$( + cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 + pwd +)/$(basename "${BASH_SOURCE[0]}")" + +IMPORT_SCRIPT="$( + canonical_path=$(readlink -f "$SCRIPT_PATH" 2>/dev/null || echo "$SCRIPT_PATH") + dirname "$(dirname "$canonical_path")" +)" + +# Function: Display help information +function help { + echo -e "Usage: bash install_tools.sh [options]" + echo -e "Options:" + echo -e " --mirror cn Use China mirror for acceleration" + echo -e " --k3s-version VERSION Specify k3s version (default: v1.30.2+k3s1)" + echo -e " --helm-version VERSION Specify helm version (default: v3.15.0)" + echo -e " -h, --help Show help information" + echo -e "Examples:" + echo -e " bash install_tools.sh # Install with default settings" + echo -e " bash install_tools.sh --mirror cn # Use China mirror" + echo -e " bash install_tools.sh --k3s-version v1.30.1+k3s1 --helm-version v3.15.0" + echo -e "Offline installation instructions:" + echo -e "1. Rename k3s binary to k3s or k3s-arm64 and place in $TOOLS_DIR" + echo -e "2. Rename k3s image package to k3s-airgap-images-.tar.zst and place in $TOOLS_DIR" + echo -e "3. Rename helm package to helm--linux-.tar.gz and place in $TOOLS_DIR" +} + +# Parse command line arguments +MIRROR="" +K3S_VERSION="" +HELM_VERSION="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --mirror) + MIRROR="$2" + shift 2 + ;; + --k3s-version) + K3S_VERSION="$2" + shift 2 + ;; + --helm-version) + HELM_VERSION="$2" + shift 2 + ;; + cn) + MIRROR="cn" + shift + ;; + -h|--help) + help + exit 0 + ;; + *) + echo "Unknown parameter: $1" + help + exit 1 + ;; + esac +done + +# Enhanced network check +function check_network { + echo -e "[Info] Checking network connection..." + if curl --retry 3 --retry-delay 2 --connect-timeout 5 -Is https://github.com | head -n 1 | grep 200 >/dev/null; then + echo -e "\033[32m[OK] Network connection normal\033[0m" + return 0 + else + echo -e "\033[33m[Warn] No network connection, switching to offline mode\033[0m" + return 1 + fi +} + +function check_user { + if [[ $(id -u) -ne 0 ]]; then + echo -e "\033[31m[Error] Please run this script with root privileges!\033[0m" + exit 1 + fi +} + +function check_arch { + case $ARCH in + x86_64) ARCH=amd64 ;; + aarch64) ARCH=arm64 ;; + *) + echo -e "\033[31m[Error] Current CPU architecture not supported\033[0m" + return 1 + ;; + esac + return 0 +} + +install_basic_tools() { + # Install basic tools + echo "Installing tar, vim, curl, wget..." + yum install -y tar vim curl wget python3 + + # Check if pip is installed + if ! command -v pip3 &> /dev/null; then + echo -e "pip could not be found, installing python3-pip..." + yum install -y python3-pip + else + echo -e "pip is already installed." + fi + + echo "Installing requests ruamel.yaml with pip3..." + if ! pip3 install \ + --disable-pip-version-check \ + --retries 3 \ + --timeout 60 \ + --trusted-host mirrors.huaweicloud.com \ + -i https://mirrors.huaweicloud.com/repository/pypi/simple \ + ruamel.yaml requests; then + echo -e "[ERROR] Failed to install ruamel.yaml and requests via pip" >&2 + fi + echo "All basic tools have been installed." + return 0 +} + +function check_local_k3s_files { + local version="${1:-v1.30.2+k3s1}" + local k3s_version="$version" + + # Auto-complete v prefix + if [[ $k3s_version != v* ]]; then + k3s_version="v$k3s_version" + fi + + local image_name="k3s-airgap-images-$ARCH.tar.zst" + local bin_name="k3s" + [[ $ARCH == "arm64" ]] && bin_name="k3s-arm64" + + # Check if local files exist + if [[ -f "$TOOLS_DIR/$bin_name" && -f "$TOOLS_DIR/$image_name" ]]; then + echo -e "\033[32m[Info] Local K3s installation files detected, using local files\033[0m" + return 0 + else + echo -e "\033[33m[Info] Local K3s installation files incomplete, attempting online download\033[0m" + return 1 + fi +} + +function install_k3s { + local version="${1:-v1.30.2+k3s1}" + local use_mirror="$2" + + # Auto-complete v prefix + if [[ $version != v* ]]; then + version="v$version" + fi + local k3s_version="$version" + + local image_name="k3s-airgap-images-$ARCH.tar.zst" + local bin_name="k3s" + [[ $ARCH == "arm64" ]] && bin_name="k3s-arm64" + + # First check if local files exist + if check_local_k3s_files "$version"; then + # Use local files for installation + echo -e "\033[33m[Info] Entering offline K3s installation mode\033[0m" + + echo -e "[Info] Installing using local packages..." + cp "$TOOLS_DIR/$bin_name" /usr/local/bin/k3s + chmod +x /usr/local/bin/k3s + + mkdir -p /var/lib/rancher/k3s/agent/images + cp "$TOOLS_DIR/$image_name" "/var/lib/rancher/k3s/agent/images/$image_name" + + # Offline installation script + local local_install_script="$TOOLS_DIR/k3s-install.sh" + if [[ -f "$local_install_script" ]]; then + echo -e "\033[33m[Info] Using local installation script: $local_install_script\033[0m" + chmod +x "$local_install_script" + if INSTALL_K3S_SKIP_DOWNLOAD=true "$local_install_script"; then + echo -e "\033[32m[Success] K3s installation completed\033[0m" + return 0 + else + echo -e "\033[31m[Error] Local installation failed\033[0m" + return 1 + fi + else + echo -e "\033[31m[Error] Missing local installation script: $local_install_script\033[0m" + echo -e "Please pre-download and save to specified directory:" + echo -e "Online: curl -sfL https://get.k3s.io -o $local_install_script" + echo -e "China mirror: curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh -o $local_install_script" + return 1 + fi + else + # Local files not found, check network + if check_network; then + echo -e "\033[32m[Info] Starting online K3s installation\033[0m" + + # Online download and installation + local k3s_bin_url="$GITHUB_MIRROR/https://github.com/k3s-io/k3s/releases/download/$k3s_version/$bin_name" + local k3s_image_url="$GITHUB_MIRROR/https://github.com/k3s-io/k3s/releases/download/$k3s_version/$image_name" + + echo -e "[Info] Downloading K3s binary..." + if ! curl -L "$k3s_bin_url" -o /usr/local/bin/k3s; then + echo -e "\033[31m[Error] Binary download failed\033[0m" + return 1 + fi + chmod +x /usr/local/bin/k3s + + echo -e "[Info] Downloading dependency images..." + mkdir -p /var/lib/rancher/k3s/agent/images + if ! curl -L "$k3s_image_url" -o "/var/lib/rancher/k3s/agent/images/$image_name"; then + echo -e "\033[33m[Warn] Image download failed, may affect offline capability\033[0m" + fi + + local install_source="https://get.k3s.io" + [[ $use_mirror == "cn" ]] && install_source="https://rancher-mirror.rancher.cn/k3s/k3s-install.sh" + + echo -e "\033[32m[Info] Using online installation script\033[0m" + if ! curl -sfL "$install_source" | INSTALL_K3S_SKIP_DOWNLOAD=true sh -; then + echo -e "\033[31m[Error] Online installation failed\033[0m" + return 1 + fi + else + # Neither local files nor network connection available + echo -e "\033[31m[Error] Cannot install K3s:\033[0m" + echo -e "1. Missing necessary local installation files" + echo -e "2. Network unavailable, cannot download installation files" + echo -e "Please perform one of the following:" + echo -e "- Ensure network connection and retry" + echo -e "- Or pre-place the following files in $TOOLS_DIR directory:" + echo -e " - $bin_name" + echo -e " - $image_name" + echo -e " - k3s-install.sh (optional)" + return 1 + fi + fi +} + +function check_local_helm_file { + local version="${1:-v3.15.0}" + local helm_version="$version" + + # Auto-complete v prefix + if [[ $helm_version != v* ]]; then + helm_version="v$helm_version" + fi + + local file_name="helm-${helm_version}-linux-${ARCH}.tar.gz" + + # Check if local file exists + if [[ -f "$TOOLS_DIR/$file_name" ]]; then + echo -e "\033[32m[Info] Local Helm installation file detected, using local file\033[0m" + return 0 + else + echo -e "\033[33m[Info] Local Helm installation file not found, attempting online download\033[0m" + return 1 + fi +} + +function install_helm { + local version="${1:-v3.15.0}" + local use_mirror="$2" + + # Auto-complete v prefix + if [[ $version != v* ]]; then + version="v$version" + fi + local helm_version="$version" + + local file_name="helm-${helm_version}-linux-${ARCH}.tar.gz" + + # First check if local file exists + if check_local_helm_file "$version"; then + echo -e "\033[33m[Info] Entering offline Helm installation mode\033[0m" + echo -e "[Info] Installing using local package..." + cp "$TOOLS_DIR/$file_name" . + else + # Local file not found, check network + if check_network; then + echo -e "\033[32m[Info] Starting online Helm installation\033[0m" + + local base_url="https://get.helm.sh" + if [[ $use_mirror == "cn" ]]; then + local helm_version_without_v="${helm_version#v}" + base_url="https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts/helm/${helm_version_without_v}" + fi + + echo -e "[Info] Downloading Helm..." + if ! curl -L "$base_url/$file_name" -o "$file_name"; then + echo -e "\033[31m[Error] Download failed\033[0m" + return 1 + fi + else + # Neither local file nor network connection available + echo -e "\033[31m[Error] Cannot install Helm:\033[0m" + echo -e "1. Missing necessary local installation file" + echo -e "2. Network unavailable, cannot download installation file" + echo -e "Please perform one of the following:" + echo -e "- Ensure network connection and retry" + echo -e "- Or pre-place the following file in $TOOLS_DIR directory:" + echo -e " - $file_name" + return 1 + fi + fi + + echo -e "[Info] Extracting and installing..." + tar -zxvf "$file_name" --strip-components 1 -C /usr/local/bin "linux-$ARCH/helm" + chmod +x /usr/local/bin/helm + rm -f "$file_name" + + echo -e "\033[32m[Success] Helm installation completed\033[0m" + return 0 +} + +function check_k3s_status() { + local STATUS=$(systemctl is-active k3s) + + if [ "$STATUS" = "active" ]; then + echo -e "[Info] k3s service is currently active." + else + echo -e "[Info] k3s service is not active, current status: $STATUS. Attempting to start service..." + # Try to start k3s service + systemctl start k3s.service + + # Check service status again + STATUS=$(systemctl is-active k3s.service) + if [ "$STATUS" = "active" ]; then + echo -e "[Info] k3s service successfully started and running." + else + echo -e "\033[31m[Error] Unable to start k3s service, please check logs or configuration\033[0m" + fi + fi +} + +function main { + # Create tools directory + mkdir -p "$TOOLS_DIR" + + check_user + check_arch || exit 1 + install_basic_tools + + local use_mirror="$MIRROR" + local k3s_version="${K3S_VERSION:-v1.30.2+k3s1}" + local helm_version="${HELM_VERSION:-v3.15.0}" + + # Install K3s (if not already installed) + if ! command -v k3s &> /dev/null; then + install_k3s "$k3s_version" "$use_mirror" || exit 1 + else + echo -e "[Info] K3s already installed, skipping installation" + fi + # Check network first + if check_network; then + echo -e "\033[32m[Info] Online environment, skipping image import\033[0m" + else + echo -e "\033[33m[Info] Offline environment, starting local image import, ensure all image files exist in local directory\033[0m" + bash "$IMPORT_SCRIPT/9-other-script/import_images.sh" -v "$eulercopilot_version" + fi + + # Install Helm (if not already installed) + if ! command -v helm &> /dev/null; then + install_helm "$helm_version" "$use_mirror" || exit 1 + else + echo -e "[Info] Helm already installed, skipping installation" + fi + mkdir -p ~/.kube + ln -sf /etc/rancher/k3s/k3s.yaml ~/.kube/config + check_k3s_status + + echo -e "\n\033[32m=== All tools installation completed ===\033[0m" + echo -e "K3s version: $(k3s --version | head -n1)" + echo -e "Helm version: $(helm version --short)" +} + +# Execute main function +main diff --git a/deploy/scripts/2-install-tools/install_tools.sh b/deploy/scripts/2-install-tools/install_tools_zh.sh old mode 100755 new mode 100644 similarity index 100% rename from deploy/scripts/2-install-tools/install_tools.sh rename to deploy/scripts/2-install-tools/install_tools_zh.sh diff --git a/deploy/scripts/3-install-ollama/install_ollama_en.sh b/deploy/scripts/3-install-ollama/install_ollama_en.sh new file mode 100644 index 000000000..8aedaf8d2 --- /dev/null +++ b/deploy/scripts/3-install-ollama/install_ollama_en.sh @@ -0,0 +1,337 @@ +#!/bin/bash + +MAGENTA='\e[35m' +CYAN='\e[36m' +BLUE='\e[34m' +GREEN='\e[32m' +YELLOW='\e[33m' +RED='\e[31m' +RESET='\e[0m' + +# Initialize global variables +OS_ID="" +ARCH="" +OLLAMA_BIN_PATH="/usr/bin/ollama" +OLLAMA_LIB_DIR="/usr/lib/ollama" +OLLAMA_DATA_DIR="/var/lib/ollama" +SERVICE_FILE="/etc/systemd/system/ollama.service" +LOCAL_DIR="/home/eulercopilot/tools" +LOCAL_TGZ="ollama-linux-${ARCH}.tgz" + +# Output function with timestamp +log() { + local level=$1 + shift + local color + case "$level" in + "INFO") color=${BLUE} ;; + "SUCCESS") color=${GREEN} ;; + "WARNING") color=${YELLOW} ;; + "ERROR") color=${RED} ;; + *) color=${RESET} ;; + esac + echo -e "${color}[$(date '+%Y-%m-%d %H:%M:%S')] $level: $*${RESET}" +} + +# Network connection check +check_network() { + local install_url=$(get_ollama_url) + local domain=$(echo "$install_url" | awk -F/ '{print $3}') + local test_url="http://$domain" + + log "INFO" "Checking network connection ($domain)..." + if curl --silent --head --fail --connect-timeout 5 --max-time 10 "$test_url" >/dev/null 2>&1; then + log "INFO" "Network connection normal" + return 0 + else + log "WARNING" "Unable to connect to internet" + return 1 + fi +} + +# Operating system detection +detect_os() { + log "INFO" "Step 1/8: Detecting operating system and architecture..." + if [ -f /etc/os-release ]; then + . /etc/os-release + OS_ID="${ID}" + log "INFO" "Detected operating system: ${PRETTY_NAME}" + else + log "ERROR" "Unable to detect operating system type" + exit 1 + fi + + ARCH=$(uname -m) + case "$ARCH" in + x86_64) ARCH="amd64" ;; + aarch64) ARCH="arm64" ;; + armv7l) ARCH="armv7" ;; + *) log "ERROR" "Unsupported architecture: $ARCH"; exit 1 ;; + esac + LOCAL_TGZ="ollama-linux-${ARCH}.tgz" + log "INFO" "System architecture: $ARCH" +} + +# Install system dependencies +install_dependencies() { + log "INFO" "Step 2/8: Installing system dependencies..." + local deps=(curl wget tar gzip jq) + + case "$OS_ID" in + ubuntu|debian) + if ! apt-get update; then + log "ERROR" "APT source update failed" + exit 1 + fi + if ! DEBIAN_FRONTEND=noninteractive apt-get install -y "${deps[@]}"; then + log "ERROR" "APT dependency installation failed" + exit 1 + fi + ;; + centos|rhel|fedora|openEuler|kylin|uos) + if ! yum install -y "${deps[@]}"; then + log "ERROR" "YUM dependency installation failed" + exit 1 + fi + ;; + *) + log "ERROR" "Unsupported distribution: $OS_ID" + exit 1 + ;; + esac + log "SUCCESS" "System dependencies installation completed" +} + +# Get Ollama download URL +get_ollama_url() { + echo "https://repo.oepkgs.net/openEuler/rpm/openEuler-22.03-LTS/contrib/eulercopilot/tools/$ARCH/ollama-linux-$ARCH.tgz" +} + +install_ollama() { + log "INFO" "Step 3/8: Installing Ollama core..." + local install_url=$(get_ollama_url) + local tmp_file="/tmp/ollama-${ARCH}.tgz" + # Enhanced cleanup logic + if [ -x "$OLLAMA_BIN_PATH" ] || [ -x "/usr/local/bin/ollama" ]; then + log "WARNING" "Found existing Ollama installation, version: $($OLLAMA_BIN_PATH --version)" + read -p "Reinstall? [y/N] " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + log "WARNING" "Found existing Ollama installation, cleaning up..." + systemctl stop ollama 2>/dev/null || true + systemctl disable ollama 2>/dev/null || true + rm -rf ${SERVICE_FILE} 2>/dev/null + rm $(which ollama) 2>/dev/null + rm -rf ${OLLAMA_LIB_DIR} 2>/dev/null + rm -rf ${OLLAMA_DATA_DIR} 2>/dev/null + rm -rf /run/ollama 2>/dev/null + userdel ollama 2>/dev/null || true + groupdel ollama 2>/dev/null || true + else + return 0 + fi + fi + # Enhanced installation package handling + local actual_tgz_path="" + if [ -f "${LOCAL_DIR}/${LOCAL_TGZ}" ]; then + log "INFO" "Using local installation package: ${LOCAL_DIR}/${LOCAL_TGZ}" + actual_tgz_path="${LOCAL_DIR}/${LOCAL_TGZ}" + else + if ! check_network; then + log "ERROR" "Network unavailable and no local installation package found" + log "INFO" "Please pre-download ${LOCAL_TGZ} and place in ${LOCAL_DIR}" + exit 1 + fi + log "INFO" "Downloading installation package: ${install_url}" + if ! wget --show-progress -q -O "${tmp_file}" "${install_url}"; then + log "ERROR" "Download failed, exit code: $?" + exit 1 + fi + actual_tgz_path="${tmp_file}" + fi + + log "INFO" "Extracting files to system directory /usr..." + if ! tar -xzvf "$actual_tgz_path" -C /usr/; then + log "ERROR" "Extraction failed, possible reasons:\n1. File corrupted\n2. Insufficient disk space\n3. Permission issues" + exit 1 + fi + + chmod +x "$OLLAMA_BIN_PATH" + if [ ! -x "$OLLAMA_BIN_PATH" ]; then + log "ERROR" "Post-installation verification failed: executable file does not exist" + exit 1 + fi + log "SUCCESS" "Ollama core installation completed, version: $($OLLAMA_BIN_PATH --version || echo 'unknown')" + # New: Create compatibility symbolic link + if [ ! -L "/usr/local/bin/ollama" ]; then + ln -sf "$OLLAMA_BIN_PATH" "/usr/local/bin/ollama" + log "INFO" "Created symbolic link: /usr/local/bin/ollama → $OLLAMA_BIN_PATH" + fi + + # Set library path + echo "${OLLAMA_LIB_DIR}" > /etc/ld.so.conf.d/ollama.conf + ldconfig +} + +fix_user() { + log "INFO" "Step 4/8: Fixing user configuration..." + + # Terminate all processes using ollama user + if pgrep -u ollama >/dev/null; then + log "WARNING" "Found running ollama processes, terminating..." + pkill -9 -u ollama || true + sleep 2 + if pgrep -u ollama >/dev/null; then + log "ERROR" "Unable to terminate ollama user processes" + exit 1 + fi + fi + + # Clean up old user + if id ollama &>/dev/null; then + # Check if user is locked + if passwd -S ollama | grep -q 'L'; then + log "INFO" "Found locked ollama user, unlocking and setting random password..." + random_pass=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 16) + usermod -p "$(openssl passwd -1 "$random_pass")" ollama + fi + + # Delete user and home directory + if ! userdel -r ollama; then + log "WARNING" "Unable to delete ollama user, attempting force delete..." + if ! userdel -f -r ollama; then + log "ERROR" "Force delete user failed, attempting manual cleanup..." + sed -i '/^ollama:/d' /etc/passwd /etc/shadow /etc/group + rm -rf /var/lib/ollama + log "WARNING" "Manually cleaned up ollama user information" + fi + fi + log "INFO" "Deleted old ollama user" + fi + + # Check if group exists + if getent group ollama >/dev/null; then + log "INFO" "ollama group already exists, will use existing group" + existing_group=true + else + existing_group=false + fi + + # Create system user + if ! useradd -r -g ollama -d /var/lib/ollama -s /bin/false ollama; then + log "ERROR" "User creation failed, attempting manual creation..." + + # Create group if it doesn't exist + if ! $existing_group; then + if ! groupadd -r ollama; then + log "ERROR" "Unable to create ollama group" + exit 1 + fi + fi + + # Try creating user again + if ! useradd -r -g ollama -d /var/lib/ollama -s /bin/false ollama; then + log "ERROR" "Manual user creation failed, please check:" + log "ERROR" "1. Whether /etc/passwd and /etc/group files are writable" + log "ERROR" "2. Whether there are conflicting users/groups in the system" + log "ERROR" "3. System user limits (/etc/login.defs)" + exit 1 + fi + fi + + # Create directory structure + mkdir -p /var/lib/ollama/.ollama/{models,bin} + chown -R ollama:ollama /var/lib/ollama + chmod -R 755 /var/lib/ollama + log "SUCCESS" "User configuration fix completed" +} + +fix_service() { + log "INFO" "Step 5/8: Configuring system service..." + cat > "${SERVICE_FILE}" </dev/null; then + log "ERROR" "Ollama not properly installed" + exit 1 + fi + if ! ollama list &>/dev/null; then + log "ERROR" "Service connection failed, please check:\n1.Service status: systemctl status ollama\n2.Port listening: ss -tuln | grep 11434" + exit 1 + fi + + log "SUCCESS" "Verification passed, you can perform the following operations:\n ollama list # View model list\n ollama run llama2 # Run example model" +} + +### Main execution flow ### +main() { + if [[ $EUID -ne 0 ]]; then + log "ERROR" "Please run this script with sudo" + exit 1 + fi + + detect_os + install_dependencies + echo -e "${MAGENTA}=== Starting Ollama Installation ===${RESET}" + install_ollama + fix_user + fix_service + restart_service + if final_check; then + echo -e "${MAGENTA}=== Ollama Installation Successful ===${RESET}" + else + echo -e "${MAGENTA}=== Ollama Installation Failed ===${RESET}" + fi +} + +main diff --git a/deploy/scripts/3-install-ollama/install_ollama.sh b/deploy/scripts/3-install-ollama/install_ollama_zh.sh old mode 100755 new mode 100644 similarity index 100% rename from deploy/scripts/3-install-ollama/install_ollama.sh rename to deploy/scripts/3-install-ollama/install_ollama_zh.sh diff --git a/deploy/scripts/4-deploy-deepseek/deploy_deepseek_en.sh b/deploy/scripts/4-deploy-deepseek/deploy_deepseek_en.sh new file mode 100644 index 000000000..eaff68287 --- /dev/null +++ b/deploy/scripts/4-deploy-deepseek/deploy_deepseek_en.sh @@ -0,0 +1,252 @@ +#!/bin/bash +set -euo pipefail + +# Color definitions +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # Reset color + +# Configuration parameters +readonly MODEL_NAME="deepseek-llm-7b-chat" +readonly MODEL_URL="https://repo.oepkgs.net/openEuler/rpm/openEuler-22.03-LTS/contrib/eulercopilot/models/deepseek-llm-7b-chat-Q4_K_M.gguf" +readonly MODEL_FILE="deepseek-llm-7b-chat-Q4_K_M.gguf" +readonly MODEL_DIR="/home/eulercopilot/models" +readonly MODELLEFILE="Modelfile" +readonly TIMEOUT_DURATION=45 + +# Initialize working directory +readonly WORK_DIR=$(pwd) +mkdir -p "$MODEL_DIR" + +check_service() { + echo -e "${BLUE}Step 1/5: Checking service status...${NC}" + if ! systemctl is-active --quiet ollama; then + echo -e "${RED}Ollama service not running${NC}" + echo -e "${YELLOW}Please run ollama-install.sh to install service first${NC}" + exit 1 + fi + echo -e "${GREEN}Service status normal${NC}" +} + +check_network() { + local url_to_check=$(echo "$MODEL_URL" | awk -F/ '{print $1 "//" $3}') + echo -e "${BLUE}Step 2/5: Checking network connection...${NC}" + if curl --silent --head --fail --max-time 5 "$url_to_check" >/dev/null 2>&1; then + echo -e "${GREEN}Model repository accessible${NC}" + return 0 + else + echo -e "${RED}[ERROR] Unable to connect to model repository${NC}" + return 1 + fi +} + +show_progress() { + local pid=$1 + local cols=$(tput cols) + local bar_width=$((cols - 20)) + + while kill -0 "$pid" 2>/dev/null; do + local current_size=$(du -b "${MODEL_DIR}/${MODEL_FILE}" 2>/dev/null | awk '{print $1}') + local percent=$((current_size * 100 / EXPECTED_SIZE)) + [ $percent -gt 100 ] && percent=100 + + local filled=$((percent * bar_width / 100)) + local empty=$((bar_width - filled)) + + printf "\r[%-*s] %3d%%" "$bar_width" "$(printf '%0.s=' {1..$filled})$(printf '%0.s ' {1..$empty})" "$percent" + sleep 1 + done +} + +detect_gpu() { + echo -e "${BLUE}Detecting GPU devices...${NC}" + + # Check if NVIDIA GPU hardware exists + if lspci | grep -i nvidia || [ -c /dev/nvidia0 ]; then + echo -e "${GREEN}Detected NVIDIA GPU device${NC}" + + # Check if NVIDIA driver is installed + if command -v nvidia-smi &> /dev/null; then + echo -e "${GREEN}NVIDIA driver installed${NC}" + return 0 + else + echo -e "${YELLOW}GPU detected but NVIDIA driver not installed, will use CPU mode${NC}" + return 1 + fi + else + echo -e "${YELLOW}No GPU device detected, will use CPU mode${NC}" + return 1 + fi +} + +handle_model() { + echo -e "${BLUE}Step 3/5: Processing model file...${NC}" + local model_path="${MODEL_DIR}/${MODEL_FILE}" + + # Check local model + if [[ -f "$model_path" ]]; then + echo -e "${GREEN}Detected local model file ${model_path}${NC}" + return 0 + fi + + # Check network when download is needed + if ! check_network; then + echo -e "${RED}[ERROR] Unable to download model: network connection unavailable${NC}" + exit 1 + fi + + # Online download mode + echo -e "${YELLOW}Starting online model download...${NC}" + + # Get expected file size + EXPECTED_SIZE=$(curl -sLI "$MODEL_URL" | grep -i 'Content-Length' | awk '{print $2}' | tr -d '\r') + EXPECTED_SIZE=${EXPECTED_SIZE:-0} + + # Start download process + wget --tries=3 --content-disposition -O "$model_path" "$MODEL_URL" --progress=dot:binary >/dev/null 2>&1 & + local wget_pid=$! + + # Show progress bar + show_progress $wget_pid + + # Wait for download to complete + if wait $wget_pid; then + echo -e "\n${GREEN}[SUCCESS] Model download completed (file size: $(du -h "$model_path" | awk '{print $1}'))${NC}" + else + echo -e "\n${RED}[ERROR] Model download failed${NC}" + echo -e "${YELLOW}Possible reasons:" + echo "1. URL expired (current URL: $MODEL_URL)" + echo "2. Network connection issue" + echo -e "3. Insufficient disk space (current available: $(df -h ${MODEL_DIR} | awk 'NR==2 {print $4}'))${NC}" + exit 1 + fi +} + +create_modelfile() { + echo -e "${BLUE}Step 4/5: Creating model configuration...${NC}" + + # GPU parameter configuration + local gpu_param="" + if detect_gpu; then + gpu_param="PARAMETER num_gpu -1" + echo -e "${GREEN}GPU acceleration mode enabled${NC}" + else + echo -e "${YELLOW}Using CPU mode${NC}" + gpu_param="PARAMETER num_gpu 0" + fi + + cat > "${WORK_DIR}/${MODELLEFILE}" < /dev/null; then + echo -e "${YELLOW}Note: jq not installed, response parsing may be limited, recommend installing jq for better output.${NC}" + fi + + local retries=3 + local interval=5 + local attempt=1 + + if ! ollama list | grep -qw "${MODEL_NAME}"; then + echo -e "${RED}Basic verification failed - model ${MODEL_NAME} not found${NC}" + exit 1 + fi + echo -e "${GREEN}Basic verification passed - detected model: ${MODEL_NAME}${NC}" + + echo -e "${YELLOW}Executing API test (timeout ${TIMEOUT_DURATION} seconds)...${NC}" + + while [ $attempt -le $retries ]; do + echo -e "${BLUE}Attempt $attempt: Sending test request...${NC}" + + response=$(timeout ${TIMEOUT_DURATION} curl -s http://localhost:11434/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer sk-123456" \ + -d '{ + "model": "'"${MODEL_NAME}"'", + "messages": [ + {"role": "system", "content": "You are an AI assistant"}, + {"role": "user", "content": "Hello, please recite a Chinese ancient poem"} + ], + "stream": false + }') + + if [[ $? -eq 0 ]] && [[ -n "$response" ]]; then + echo -e "${GREEN}Test response successful, received valid output:" + if jq -e .choices[0].message.content <<< "$response" &> /dev/null; then + jq .choices[0].message.content <<< "$response" + else + echo "$response" + fi + return 0 + else + echo -e "${YELLOW}Request did not receive valid response, retrying...${NC}" + ((attempt++)) + sleep $interval + fi + done + + echo -e "${RED}Verification failed: No valid response received after ${retries} retries${NC}" + return 1 +} + +### Main execution flow ### +echo -e "${BLUE}=== Starting Model Deployment ===${NC}" +{ + check_service + handle_model + create_modelfile + create_model + verify_deployment || true +} + +echo -e "${GREEN}=== Model Deployment Successful ===${NC}" + +echo -e "${YELLOW}Usage Instructions:${NC}" +echo -e "${YELLOW}1. Start interactive mode: ollama run $MODEL_NAME${NC}" +echo -e "${BLUE}2. API access example:${NC}" +cat << EOF +curl http://localhost:11434/v1/chat/completions \\ +-H "Content-Type: application/json" \\ +-H "Authorization: Bearer sk-123456" \\ +-d '{ + "model": "$MODEL_NAME", + "messages": [ + {"role": "system", "content": "You are an AI assistant"}, + {"role": "user", "content": "Hello"} + ], + "stream": false, + "n": 1, + "max_tokens": 2048 +}' +EOF + +echo -e "${BLUE}3. Streaming conversation mode:${NC}" +echo -e "${BLUE}Change "stream": false to "stream": true in the above request${NC}" diff --git a/deploy/scripts/4-deploy-deepseek/deploy_deepseek.sh b/deploy/scripts/4-deploy-deepseek/deploy_deepseek_zh.sh old mode 100755 new mode 100644 similarity index 100% rename from deploy/scripts/4-deploy-deepseek/deploy_deepseek.sh rename to deploy/scripts/4-deploy-deepseek/deploy_deepseek_zh.sh diff --git a/deploy/scripts/5-deploy-embedding/deploy-embedding_en.sh b/deploy/scripts/5-deploy-embedding/deploy-embedding_en.sh new file mode 100644 index 000000000..3158c95d9 --- /dev/null +++ b/deploy/scripts/5-deploy-embedding/deploy-embedding_en.sh @@ -0,0 +1,252 @@ +#!/bin/bash +set -euo pipefail + +# Color definitions +RED='\e[31m' +GREEN='\e[32m' +YELLOW='\e[33m' +BLUE='\e[34m' +NC='\e[0m' # Reset color + +# Configuration parameters +readonly MODEL_NAME="bge-m3" +readonly MODEL_URL="https://modelscope.cn/models/gpustack/bge-m3-GGUF/resolve/master/bge-m3-Q4_K_M.gguf" +readonly MODEL_FILE="bge-m3-Q4_K_M.gguf" +readonly MODELLEFILE="Modelfile" +readonly TIMEOUT_DURATION=45 +readonly MODEL_DIR="/home/eulercopilot/models" + +# Initialize working directory +readonly WORK_DIR=$(pwd) +mkdir -p "$MODEL_DIR" + +# Network check function (unchanged) +check_network() { + echo -e "${BLUE}Step 1/5: Checking network connection...${NC}" + local test_url="https://modelscope.cn" + if curl --silent --head --fail --max-time 5 "$test_url" >/dev/null 2>&1; then + echo -e "${GREEN}[SUCCESS] Network connection normal${NC}" + return 0 + else + echo -e "${YELLOW}[WARNING] Unable to connect to network, switching to offline mode${NC}" + return 1 + fi +} + +# Service check (unchanged) +check_service() { + echo -e "${BLUE}Step 2/5: Checking service status...${NC}" + if ! systemctl is-active --quiet ollama; then + echo -e "${RED}[ERROR] Ollama service not running${NC}" + echo -e "${YELLOW}Possible reasons:" + echo "1. Service not installed" + echo "2. System service not enabled" + echo -e "Please run ollama-install.sh to install service first${NC}" + exit 1 + fi +} + +show_progress() { + local pid=$1 + local cols=$(tput cols) + local bar_width=$((cols - 20)) + + while kill -0 "$pid" 2>/dev/null; do + local current_size=$(du -b "${MODEL_DIR}/${MODEL_FILE}" 2>/dev/null | awk '{print $1}') + local percent=$((current_size * 100 / EXPECTED_SIZE)) + [ $percent -gt 100 ] && percent=100 + + local filled=$((percent * bar_width / 100)) + local empty=$((bar_width - filled)) + + printf "\r[%-*s] %3d%%" "$bar_width" "$(printf '%0.s=' {1..$filled})$(printf '%0.s ' {1..$empty})" "$percent" + sleep 1 + done +} + +detect_gpu() { + echo -e "${BLUE}Detecting GPU devices...${NC}" + + # Check if NVIDIA GPU hardware exists + if lspci | grep -i nvidia || [ -c /dev/nvidia0 ]; then + echo -e "${GREEN}Detected NVIDIA GPU device${NC}" + + # Check if NVIDIA driver is installed + if command -v nvidia-smi &> /dev/null; then + echo -e "${GREEN}NVIDIA driver installed${NC}" + return 0 + else + echo -e "${YELLOW}GPU detected but NVIDIA driver not installed, will use CPU mode${NC}" + return 1 + fi + else + echo -e "${YELLOW}No GPU device detected, will use CPU mode${NC}" + return 1 + fi +} + +handle_model() { + echo -e "${BLUE}Step 3/5: Processing model file...${NC}" + local model_path="${MODEL_DIR}/${MODEL_FILE}" + + # Check local model + if [[ -f "$model_path" ]]; then + echo -e "${GREEN}Detected local model file ${model_path}${NC}" + return 0 + fi + + # Check network when download is needed + if ! check_network; then + echo -e "${RED}[ERROR] Unable to download model: network connection unavailable${NC}" + echo -e "${YELLOW}Solutions:" + echo -e "1. Please check network connection" + echo -e "2. You can manually place model file at: ${MODEL_DIR}" + exit 1 + fi + + # Online download mode + echo -e "${YELLOW}Starting online model download...${NC}" + echo -e "${YELLOW}Download URL: ${MODEL_URL}${NC}" + + # Create temporary file to record wget output + local wget_output=$(mktemp) + + # Execute download and show dynamic progress bar + ( + wget --tries=3 --content-disposition -O "$model_path" "$MODEL_URL" --progress=dot:binary 2>&1 | \ + while IFS= read -r line; do + # Extract percentage + if [[ "$line" =~ ([0-9]{1,3})% ]]; then + local percent=${BASH_REMATCH[1]} + # Calculate progress bar length (based on terminal width - 20) + local cols=$(tput cols) + local bar_width=$((cols - 20)) + local filled=$((percent * bar_width / 100)) + local empty=$((bar_width - filled)) + + # Build progress bar + local progress_bar=$(printf "%${filled}s" | tr ' ' '=') + local remaining_bar=$(printf "%${empty}s" | tr ' ' ' ') + + # Show progress (use carriage return to overwrite) + printf "\r[%s%s] %3d%%" "$progress_bar" "$remaining_bar" "$percent" + fi + done + echo # New line + ) | tee "$wget_output" + + # Check download result + if grep -q "100%" "$wget_output"; then + echo -e "${GREEN}[SUCCESS] Model download completed (file size: $(du -h "$model_path" | awk '{print $1}'))${NC}" + echo -e "${GREEN}Storage path: ${model_path}${NC}" + rm -f "$wget_output" + else + echo -e "${RED}[ERROR] Model download failed${NC}" + echo -e "${YELLOW}Possible reasons:" + echo "1. URL expired (current URL: $MODEL_URL)" + echo "2. Network connection issue" + echo -e "3. Insufficient disk space (current available: $(df -h ${MODEL_DIR} | awk 'NR==2 {print $4}'))${NC}" + rm -f "$wget_output" + exit 1 + fi +} + +create_modelfile() { + echo -e "${BLUE}Step 4/5: Creating model configuration...${NC}" + + # GPU parameter configuration + local gpu_param="" + if detect_gpu; then + gpu_param="PARAMETER num_gpu -1" + echo -e "${GREEN}GPU acceleration mode enabled${NC}" + else + echo -e "${YELLOW}Using CPU mode${NC}" + gpu_param="PARAMETER num_gpu 0" + fi + + cat > "${WORK_DIR}/${MODELLEFILE}" </dev/null 2>&1 + pwd +)/$(basename "${BASH_SOURCE[0]}")" + +CHART_DIR="$( + canonical_path=$(readlink -f "$SCRIPT_PATH" 2>/dev/null || echo "$SCRIPT_PATH") + dirname "$(dirname "$(dirname "$canonical_path")")" +)/chart" + +# Get system architecture +get_architecture() { + arch=$(uname -m) + case "$arch" in + x86_64) + arch="x86" + ;; + aarch64) + arch="arm" + ;; + *) + echo -e "${RED}Error: Unsupported architecture $arch${NC}" + exit 1 + ;; + esac + echo -e "${GREEN}Detected system architecture: $(uname -m)${NC}" +} + +create_namespace() { + echo -e "${BLUE}==> Checking namespace euler-copilot...${NC}" + if ! kubectl get namespace euler-copilot &> /dev/null; then + kubectl create namespace euler-copilot || { + echo -e "${RED}Namespace creation failed!${NC}" + return 1 + } + echo -e "${GREEN}Namespace created successfully${NC}" + else + echo -e "${YELLOW}Namespace already exists, skipping creation${NC}" + fi +} + +uninstall_databases() { + echo -e "${BLUE}==> Cleaning up existing resources...${NC}" + + local helm_releases + helm_releases=$(helm list -n euler-copilot -q --filter '^databases' 2>/dev/null || true) + + if [ -n "$helm_releases" ]; then + echo -e "${YELLOW}Found the following Helm Releases, starting cleanup...${NC}" + while IFS= read -r release; do + echo -e "${BLUE}Deleting Helm Release: ${release}${NC}" + if ! helm uninstall "$release" -n euler-copilot --wait --timeout 2m; then + echo -e "${RED}Error: Failed to delete Helm Release ${release}!${NC}" >&2 + return 1 + fi + done <<< "$helm_releases" + else + echo -e "${YELLOW}No Helm Releases found to clean${NC}" + fi + + # Modified: Only filter specific PVC names + local pvc_list + pvc_list=$(kubectl get pvc -n euler-copilot -o jsonpath='{.items[*].metadata.name}' 2>/dev/null \ + | tr ' ' '\n' \ + | grep -E '^(opengauss-storage|mongo-storage|minio-storage)$' || true) # Exact match for three specified names + + if [ -n "$pvc_list" ]; then + echo -e "${YELLOW}Found the following PVCs, starting cleanup...${NC}" + while IFS= read -r pvc; do + echo -e "${BLUE}Deleting PVC: $pvc${NC}" + if ! kubectl delete pvc "$pvc" -n euler-copilot --force --grace-period=0; then + echo -e "${RED}Error: Failed to delete PVC $pvc!${NC}" >&2 + return 1 + fi + done <<< "$pvc_list" + else + echo -e "${YELLOW}No PVCs found to clean${NC}" + fi + + # New: Delete euler-copilot-database Secret + local secret_name="euler-copilot-database" + if kubectl get secret "$secret_name" -n euler-copilot &>/dev/null; then + echo -e "${YELLOW}Found Secret: ${secret_name}, starting cleanup...${NC}" + if ! kubectl delete secret "$secret_name" -n euler-copilot; then + echo -e "${RED}Error: Failed to delete Secret ${secret_name}!${NC}" >&2 + return 1 + fi + else + echo -e "${YELLOW}No Secret found to clean: ${secret_name}${NC}" + fi + + echo -e "${BLUE}Waiting for resource cleanup to complete (10 seconds)...${NC}" + sleep 10 + + echo -e "${GREEN}Resource cleanup completed${NC}" +} + +helm_install() { + echo -e "${BLUE}==> Entering deployment directory...${NC}" + [ ! -d "$CHART_DIR" ] && { + echo -e "${RED}Error: Deployment directory does not exist $CHART_DIR${NC}" + return 1 + } + cd "$CHART_DIR" + + echo -e "${BLUE}Installing databases...${NC}" + helm upgrade --install databases --set globals.arch=$arch -n euler-copilot ./databases || { + echo -e "${RED}Helm installation of databases failed!${NC}" + return 1 + } +} + +check_pods_status() { + echo -e "${BLUE}==> Waiting for initialization to complete (30 seconds)...${NC}" + sleep 30 + + local timeout=300 + local start_time=$(date +%s) + + echo -e "${BLUE}Starting pod status monitoring (total timeout 300 seconds)...${NC}" + + while true; do + local current_time=$(date +%s) + local elapsed=$((current_time - start_time)) + + if [ $elapsed -gt $timeout ]; then + echo -e "${RED}Error: Deployment timeout!${NC}" + kubectl get pods -n euler-copilot + return 1 + fi + + local not_running=$(kubectl get pods -n euler-copilot -o jsonpath='{range .items[*]}{.metadata.name} {.status.phase}{"\n"}{end}' | grep -v "Running") + + if [ -z "$not_running" ]; then + echo -e "${GREEN}All pods are running normally!${NC}" + kubectl get pods -n euler-copilot + return 0 + else + echo "Waiting for pods to be ready (waited ${elapsed} seconds)..." + echo "Current abnormal pods:" + echo "$not_running" | awk '{print " - " $1 " (" $2 ")"}' + sleep 10 + fi + done +} + +main() { + get_architecture + create_namespace + uninstall_databases + helm_install + check_pods_status + + echo -e "\n${GREEN}=========================" + echo "Database deployment completed!" + echo -e "=========================${NC}" +} + +trap 'echo -e "${RED}Operation interrupted!${NC}"; exit 1' INT +main "$@" diff --git a/deploy/scripts/6-install-databases/install_databases.sh b/deploy/scripts/6-install-databases/install_databases_zh.sh old mode 100755 new mode 100644 similarity index 100% rename from deploy/scripts/6-install-databases/install_databases.sh rename to deploy/scripts/6-install-databases/install_databases_zh.sh diff --git a/deploy/scripts/7-install-authhub/install_authhub_en.sh b/deploy/scripts/7-install-authhub/install_authhub_en.sh new file mode 100644 index 000000000..9ccfb805d --- /dev/null +++ b/deploy/scripts/7-install-authhub/install_authhub_en.sh @@ -0,0 +1,240 @@ +#!/bin/bash + +set -eo pipefail + +RED='\033[31m' +GREEN='\033[32m' +YELLOW='\033[33m' +BLUE='\033[34m' +NC='\033[0m' + +SCRIPT_PATH="$( + cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 + pwd +)/$(basename "${BASH_SOURCE[0]}")" + +CHART_DIR="$( + canonical_path=$(readlink -f "$SCRIPT_PATH" 2>/dev/null || echo "$SCRIPT_PATH") + dirname "$(dirname "$(dirname "$canonical_path")")" +)/chart" + +# Print help information +print_help() { + echo -e "${GREEN}Usage: $0 [options]" + echo -e "Options:" + echo -e " --help Show help information" + echo -e " --authhub_address
Specify Authhub access address (e.g.: http://myhost:30081)" + echo -e "" + echo -e "Example:" + echo -e " $0 --authhub_address http://myhost:30081${NC}" + exit 0 +} + +# Get system architecture +get_architecture() { + local arch=$(uname -m) + case "$arch" in + x86_64) + arch="x86" + ;; + aarch64) + arch="arm" + ;; + *) + echo -e "${RED}Error: Unsupported architecture $arch${NC}" >&2 + return 1 + ;; + esac + echo -e "${GREEN}Detected system architecture: $(uname -m)${NC}" >&2 + echo "$arch" +} + +create_namespace() { + echo -e "${BLUE}==> Checking namespace euler-copilot...${NC}" + if ! kubectl get namespace euler-copilot &> /dev/null; then + kubectl create namespace euler-copilot || { + echo -e "${RED}Namespace creation failed!${NC}" + return 1 + } + echo -e "${GREEN}Namespace created successfully${NC}" + else + echo -e "${YELLOW}Namespace already exists, skipping creation${NC}" + fi +} + +uninstall_authhub() { + echo -e "${BLUE}==> Cleaning up existing resources...${NC}" + + local RELEASES + RELEASES=$(helm list -n euler-copilot --short | grep authhub || true) + + if [ -n "$RELEASES" ]; then + echo -e "${YELLOW}Found Helm Releases, starting cleanup...${NC}" + for release in $RELEASES; do + echo -e "${BLUE}Deleting Helm Release: ${release}${NC}" + helm uninstall "$release" -n euler-copilot || echo -e "${RED}Failed to delete Helm Release, continuing...${NC}" + done + else + echo -e "${YELLOW}No Helm Releases found to clean${NC}" + fi + + local pvc_name + pvc_name=$(kubectl get pvc -n euler-copilot | grep 'mysql-pvc' 2>/dev/null || true) + + if [ -n "$pvc_name" ]; then + echo -e "${YELLOW}Found PVCs, starting cleanup...${NC}" + kubectl delete pvc mysql-pvc -n euler-copilot --force --grace-period=0 || echo -e "${RED}PVC deletion failed, continuing...${NC}" + else + echo -e "${YELLOW}No PVCs found to clean${NC}" + fi + + # New: Delete authhub-secret + local authhub_secret="authhub-secret" + if kubectl get secret "$authhub_secret" -n euler-copilot &>/dev/null; then + echo -e "${YELLOW}Found Secret: ${authhub_secret}, starting cleanup...${NC}" + if ! kubectl delete secret "$authhub_secret" -n euler-copilot; then + echo -e "${RED}Error: Failed to delete Secret ${authhub_secret}!${NC}" >&2 + return 1 + fi + else + echo -e "${YELLOW}No Secret found to clean: ${authhub_secret}${NC}" + fi + + echo -e "${GREEN}Resource cleanup completed${NC}" +} + +get_authhub_address() { + local default_address="http://127.0.0.1:30081" + + echo -e "${BLUE}Enter Authhub access address (IP or domain)${NC}" + read -p "Authhub address: " authhub_address + + # Handle empty input + if [[ -z "$authhub_address" ]]; then + authhub_address="$default_address" + echo -e "${GREEN}Using default address: ${authhub_address}${NC}" + else + echo -e "${GREEN}Input address: ${authhub_address}${NC}" + fi + + return 0 +} + +helm_install() { + local arch="$1" + echo -e "${BLUE}==> Entering deployment directory...${NC}" + [ ! -d "${CHART_DIR}" ] && { + echo -e "${RED}Error: Deployment directory does not exist ${CHART_DIR} ${NC}" + return 1 + } + cd "${CHART_DIR}" + + echo -e "${BLUE}Installing authhub...${NC}" + helm upgrade --install authhub -n euler-copilot ./authhub \ + --set globals.arch="$arch" \ + --set domain.authhub="${authhub_address}" || { + echo -e "${RED}Helm installation of authhub failed!${NC}" + return 1 + } +} + +check_pods_status() { + echo -e "${BLUE}==> Waiting for initialization (30 seconds)...${NC}" >&2 + sleep 30 + + local timeout=300 + local start_time=$(date +%s) + + echo -e "${BLUE}Monitoring pod status (total timeout 300 seconds)...${NC}" >&2 + + while true; do + local current_time=$(date +%s) + local elapsed=$((current_time - start_time)) + + if [ $elapsed -gt $timeout ]; then + echo -e "${YELLOW}Warning: Deployment timeout! Please check the following resources:${NC}" >&2 + kubectl get pods -n euler-copilot -o wide + echo -e "\n${YELLOW}Suggestions:${NC}" + echo "1. Check logs of unready pods: kubectl logs -n euler-copilot " + echo "2. Check PVC status: kubectl get pvc -n euler-copilot" + echo "3. Check Service status: kubectl get svc -n euler-copilot" + return 1 + fi + + local not_running=$(kubectl get pods -n euler-copilot -o jsonpath='{range .items[*]}{.metadata.name} {.status.phase} {.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}' \ + | awk '$2 != "Running" || $3 != "True" {print $1 " " $2}') + + if [ -z "$not_running" ]; then + echo -e "${GREEN}All pods are running normally!${NC}" >&2 + kubectl get pods -n euler-copilot -o wide + return 0 + else + echo "Waiting for pods to be ready (waited ${elapsed} seconds)..." + echo "Current unready pods:" + echo "$not_running" | awk '{print " - " $1 " (" $2 ")"}' + sleep 10 + fi + done +} + +deploy() { + local arch + arch=$(get_architecture) || exit 1 + create_namespace || exit 1 + uninstall_authhub || exit 1 + + # If address not provided via parameter, prompt user + if [ -z "$authhub_address" ]; then + echo -e "${YELLOW}--authhub_address parameter not provided, need manual input${NC}" + get_authhub_address || exit 1 + else + echo -e "${GREEN}Using parameter-specified Authhub address: $authhub_address${NC}" + fi + + helm_install "$arch" || exit 1 + check_pods_status || { + echo -e "${RED}Deployment failed: Pod status check not passed!${NC}" + exit 1 + } + + echo -e "\n${GREEN}=========================" + echo -e "Authhub deployment completed!" + echo -e "Check pod status: kubectl get pod -n euler-copilot" + echo -e "Authhub login address: $authhub_address" + echo -e "Default credentials: administrator/changeme" + echo -e "=========================${NC}" +} + +# Parse command line arguments +parse_args() { + while [[ $# -gt 0 ]]; do + case "$1" in + --help) + print_help + exit 0 + ;; + --authhub_address) + if [ -n "$2" ]; then + authhub_address="$2" + shift 2 + else + echo -e "${RED}Error: --authhub_address requires a parameter${NC}" >&2 + exit 1 + fi + ;; + *) + echo -e "${RED}Unknown parameter: $1${NC}" >&2 + print_help + exit 1 + ;; + esac + done +} + +main() { + parse_args "$@" + deploy +} + +trap 'echo -e "${RED}Operation interrupted!${NC}"; exit 1' INT +main "$@" diff --git a/deploy/scripts/7-install-authhub/install_authhub.sh b/deploy/scripts/7-install-authhub/install_authhub_zh.sh old mode 100755 new mode 100644 similarity index 100% rename from deploy/scripts/7-install-authhub/install_authhub.sh rename to deploy/scripts/7-install-authhub/install_authhub_zh.sh diff --git a/deploy/scripts/8-install-EulerCopilot/install_eulercopilot_en.sh b/deploy/scripts/8-install-EulerCopilot/install_eulercopilot_en.sh new file mode 100644 index 000000000..5095d1f77 --- /dev/null +++ b/deploy/scripts/8-install-EulerCopilot/install_eulercopilot_en.sh @@ -0,0 +1,480 @@ +#!/bin/bash + +set -eo pipefail + +# Color definitions +RED='\e[31m' +GREEN='\e[32m' +YELLOW='\e[33m' +BLUE='\e[34m' +NC='\e[0m' # Reset color + +NAMESPACE="euler-copilot" +PLUGINS_DIR="/var/lib/eulercopilot" + +# Global variables +client_id="" +client_secret="" +eulercopilot_address="" +authhub_address="" + +SCRIPT_PATH="$( + cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 + pwd +)/$(basename "${BASH_SOURCE[0]}")" + +DEPLOY_DIR="$( + canonical_path=$(readlink -f "$SCRIPT_PATH" 2>/dev/null || echo "$SCRIPT_PATH") + dirname "$(dirname "$(dirname "$canonical_path")")" +)" + +# Show help information +show_help() { + echo -e "${GREEN}Usage: $0 [options]" + echo -e "Options:" + echo -e " --help Show this help message" + echo -e " --eulercopilot_address Specify EulerCopilot frontend access URL" + echo -e " --authhub_address Specify Authhub frontend access URL" + echo -e "" + echo -e "Example:" + echo -e " $0 --eulercopilot_address http://myhost:30080 --authhub_address http://myhost:30081${NC}" + exit 0 +} + +# Parse command line arguments +parse_arguments() { + while [[ $# -gt 0 ]]; do + case "$1" in + --help) + show_help + ;; + --eulercopilot_address) + if [ -n "$2" ]; then + eulercopilot_address="$2" + shift + else + echo -e "${RED}Error: --eulercopilot_address requires a value${NC}" >&2 + exit 1 + fi + ;; + --authhub_address) + if [ -n "$2" ]; then + authhub_address="$2" + shift + else + echo -e "${RED}Error: --authhub_address requires a value${NC}" >&2 + exit 1 + fi + ;; + *) + echo -e "${RED}Unknown option: $1${NC}" >&2 + show_help + exit 1 + ;; + esac + shift + done +} + +# Get system architecture +get_architecture() { + local arch=$(uname -m) + case "$arch" in + x86_64) arch="x86" ;; + aarch64) arch="arm" ;; + *) + echo -e "${RED}Error: Unsupported architecture $arch${NC}" >&2 + return 1 + ;; + esac + echo -e "${GREEN}Detected system architecture: ${arch} (original: $(uname -m))${NC}" >&2 + echo "$arch" +} + +# Auto-detect business network interface +get_network_ip() { + echo -e "${BLUE}Auto-detecting business network interface IP address...${NC}" >&2 + local timeout=20 + local start_time=$(date +%s) + local interface="" + local host="" + + # Find available network interfaces + while [ $(( $(date +%s) - start_time )) -lt $timeout ]; do + # Get all non-virtual interfaces (exclude lo, docker, veth, etc.) + interfaces=$(ip -o link show | awk -F': ' '{print $2}' | grep -vE '^lo$|docker|veth|br-|virbr|tun') + + for intf in $interfaces; do + # Check if interface status is UP + if ip link show "$intf" | grep -q 'state UP'; then + # Get IPv4 address + ip_addr=$(ip addr show "$intf" | grep -w inet | awk '{print $2}' | cut -d'/' -f1) + if [ -n "$ip_addr" ]; then + interface=$intf + host=$ip_addr + break 2 # Break two levels + fi + fi + done + sleep 1 + done + + if [ -z "$interface" ]; then + echo -e "${RED}Error: No available business network interface found${NC}" >&2 + exit 1 + fi + + echo -e "${GREEN}Using network interface: ${interface}, IP address: ${host}${NC}" >&2 + echo "$host" +} + +get_address_input() { + # If addresses already provided via command line, use them directly + if [ -n "$eulercopilot_address" ] && [ -n "$authhub_address" ]; then + echo -e "${GREEN}Using command line parameters:" + echo "EulerCopilot address: $eulercopilot_address" + echo "Authhub address: $authhub_address" + return + fi + + # Read from environment variables or use defaults + eulercopilot_address=${EULERCOPILOT_ADDRESS:-"http://127.0.0.1:30080"} + authhub_address=${AUTHHUB_ADDRESS:-"http://127.0.0.1:30081"} + + # Non-interactive mode uses defaults directly + if [ -t 0 ]; then # Only show prompts in interactive terminal + echo -e "${BLUE}Enter EulerCopilot frontend access URL (default: $eulercopilot_address):${NC}" + read -p "> " input_euler + [ -n "$input_euler" ] && eulercopilot_address=$input_euler + + echo -e "${BLUE}Enter Authhub frontend access URL (default: $authhub_address):${NC}" + read -p "> " input_auth + [ -n "$input_auth" ] && authhub_address=$input_auth + fi + + echo -e "${GREEN}Using configuration:" + echo "EulerCopilot address: $eulercopilot_address" + echo "Authhub address: $authhub_address" +} + +get_client_info_auto() { + # Get user input addresses + get_address_input + # Create temporary file + local temp_file + temp_file=$(mktemp) + + # Directly call Python script and pass domain parameters + python3 "${DEPLOY_DIR}/scripts/9-other-script/get_client_id_and_secret.py" "${eulercopilot_address}" > "$temp_file" 2>&1 + + # Check Python script execution result + if [ $? -ne 0 ]; then + echo -e "${RED}Error: Python script execution failed${NC}" + cat "$temp_file" + rm -f "$temp_file" + return 1 + fi + + # Extract credential information + client_id=$(grep "client_id: " "$temp_file" | awk '{print $2}') + client_secret=$(grep "client_secret: " "$temp_file" | awk '{print $2}') + rm -f "$temp_file" + + # Verify results + if [ -z "$client_id" ] || [ -z "$client_secret" ]; then + echo -e "${RED}Error: Unable to get valid client credentials${NC}" >&2 + return 1 + fi + + # Output results + echo -e "${GREEN}==============================${NC}" + echo -e "${GREEN}Client ID: ${client_id}${NC}" + echo -e "${GREEN}Client Secret: ${client_secret}${NC}" + echo -e "${GREEN}==============================${NC}" +} + +get_client_info_manual() { + # Non-interactive mode uses defaults directly + if [ -t 0 ]; then # Only show prompts in interactive terminal + echo -e "${BLUE}Enter Client ID: domain (endpoint info: Client ID): ${NC}" + read -p "> " input_id + [ -n "$input_id" ] && client_id=$input_id + + echo -e "${BLUE}Enter Client Secret: domain (endpoint info: Client Secret):${NC}" + read -p "> " input_secret + [ -n "$input_secret" ] && client_secret=$input_secret + fi + + # Unified domain format verification + echo -e "${GREEN}Using configuration:" + echo "Client ID: $client_id" + echo "Client Secret: $client_secret" +} + +check_directories() { + echo -e "${BLUE}Checking if semantic interface directory exists...${NC}" >&2 + + # Define parent directory and subdirectory list + local REQUIRED_OWNER="root:root" + + # Check and create parent directory + if [ -d "${PLUGINS_DIR}" ]; then + echo -e "${GREEN}Directory exists: ${PLUGINS_DIR}${NC}" >&2 + # Check current permissions + local current_owner=$(stat -c "%u:%g" "${PLUGINS_DIR}" 2>/dev/null) + if [ "$current_owner" != "$REQUIRED_OWNER" ]; then + echo -e "${YELLOW}Current directory permissions: ${current_owner}, modifying to ${REQUIRED_OWNER}...${NC}" >&2 + if chown root:root "${PLUGINS_DIR}"; then + echo -e "${GREEN}Directory permissions successfully modified to ${REQUIRED_OWNER}${NC}" >&2 + else + echo -e "${RED}Error: Unable to modify directory permissions to ${REQUIRED_OWNER}${NC}" >&2 + exit 1 + fi + else + echo -e "${GREEN}Directory permissions correct (${REQUIRED_OWNER})${NC}" >&2 + fi + else + if mkdir -p "${PLUGINS_DIR}"; then + echo -e "${GREEN}Directory created: ${PLUGINS_DIR}${NC}" >&2 + chown root:root "${PLUGINS_DIR}" # Set parent directory owner + else + echo -e "${RED}Error: Unable to create directory ${PLUGINS_DIR}${NC}" >&2 + exit 1 + fi + fi +} + +uninstall_eulercopilot() { + echo -e "${YELLOW}Checking if EulerCopilot is already deployed...${NC}" >&2 + + # Delete Helm Release: euler-copilot + if helm list -n euler-copilot --short | grep -q '^euler-copilot$'; then + echo -e "${GREEN}Found Helm Release: euler-copilot, starting cleanup...${NC}" + if ! helm uninstall euler-copilot -n euler-copilot; then + echo -e "${RED}Error: Failed to delete Helm Release euler-copilot!${NC}" >&2 + return 1 + fi + else + echo -e "${YELLOW}No Helm Release found to clean: euler-copilot${NC}" + fi + + # Delete PVC: framework-semantics-claim + local pvc_name="framework-semantics-claim" + if kubectl get pvc "$pvc_name" -n euler-copilot &>/dev/null; then + echo -e "${GREEN}Found PVC: ${pvc_name}, starting cleanup...${NC}" + if ! kubectl delete pvc "$pvc_name" -n euler-copilot --force --grace-period=0; then + echo -e "${RED}Error: Failed to delete PVC ${pvc_name}!${NC}" >&2 + return 1 + fi + else + echo -e "${YELLOW}No PVC found to clean: ${pvc_name}${NC}" + fi + + # Delete Secret: euler-copilot-system + local secret_name="euler-copilot-system" + if kubectl get secret "$secret_name" -n euler-copilot &>/dev/null; then + echo -e "${GREEN}Found Secret: ${secret_name}, starting cleanup...${NC}" + if ! kubectl delete secret "$secret_name" -n euler-copilot; then + echo -e "${RED}Error: Failed to delete Secret ${secret_name}!${NC}" >&2 + return 1 + fi + else + echo -e "${YELLOW}No Secret found to clean: ${secret_name}${NC}" + fi + + echo -e "${GREEN}Resource cleanup completed${NC}" +} + +modify_yaml() { + local host=$1 + local preserve_models=$2 # New parameter, indicates whether to preserve model configuration + echo -e "${BLUE}Starting YAML configuration file modification...${NC}" >&2 + + # Build parameter array + local set_args=() + + # Add other required parameters + set_args+=( + "--set" "login.client.id=${client_id}" + "--set" "login.client.secret=${client_secret}" + "--set" "domain.euler_copilot=${eulercopilot_address}" + "--set" "domain.authhub=${authhub_address}" + ) + + # If model configuration doesn't need to be preserved, add model-related parameters + if [[ "$preserve_models" != [Yy]* ]]; then + set_args+=( + "--set" "models.answer.endpoint=http://$host:11434/v1" + "--set" "models.answer.key=sk-123456" + "--set" "models.answer.name=deepseek-llm-7b-chat:latest" + "--set" "models.functionCall.backend=ollama" + "--set" "models.functionCall.endpoint=http://$host:11434" + "--set" "models.embedding.type=openai" + "--set" "models.embedding.endpoint=http://$host:11434/v1" + "--set" "models.embedding.key=sk-123456" + "--set" "models.embedding.name=bge-m3:latest" + ) + fi + + # Call Python script, pass all parameters + python3 "${DEPLOY_DIR}/scripts/9-other-script/modify_eulercopilot_yaml.py" \ + "${DEPLOY_DIR}/chart/euler_copilot/values.yaml" \ + "${DEPLOY_DIR}/chart/euler_copilot/values.yaml" \ + "${set_args[@]}" || { + echo -e "${RED}Error: YAML file modification failed${NC}" >&2 + exit 1 + } + echo -e "${GREEN}YAML file modified successfully!${NC}" >&2 +} + +# Check directory +enter_chart_directory() { + echo -e "${BLUE}Entering Chart directory...${NC}" >&2 + cd "${DEPLOY_DIR}/chart/" || { + echo -e "${RED}Error: Unable to enter Chart directory ${DEPLOY_DIR}/chart/${NC}" >&2 + exit 1 + } +} + +pre_install_checks() { + # Check if kubectl and helm are available + command -v kubectl >/dev/null 2>&1 || error_exit "kubectl not installed" + command -v helm >/dev/null 2>&1 || error_exit "helm not installed" + + # Check Kubernetes cluster connection + kubectl cluster-info >/dev/null 2>&1 || error_exit "Unable to connect to Kubernetes cluster" + + # Check necessary storage classes + kubectl get storageclasses >/dev/null 2>&1 || error_exit "Unable to get storage class information" +} + +# Execute installation +execute_helm_install() { + local arch=$1 + echo -e "${BLUE}Starting EulerCopilot deployment (architecture: $arch)...${NC}" >&2 + + enter_chart_directory + helm upgrade --install $NAMESPACE -n $NAMESPACE ./euler_copilot --set globals.arch=$arch --create-namespace || { + echo -e "${RED}Helm installation of EulerCopilot failed!${NC}" >&2 + exit 1 + } + echo -e "${GREEN}Helm installation of EulerCopilot successful!${NC}" >&2 +} + +# Check pod status +check_pods_status() { + echo -e "${BLUE}==> Waiting for initialization (30 seconds)...${NC}" >&2 + sleep 30 + + local timeout=300 + local start_time=$(date +%s) + + echo -e "${BLUE}Starting pod status monitoring (total timeout 300 seconds)...${NC}" >&2 + + while true; do + local current_time=$(date +%s) + local elapsed=$((current_time - start_time)) + + if [ $elapsed -gt $timeout ]; then + echo -e "${YELLOW}Warning: Deployment timeout! Please check the following resources:${NC}" >&2 + kubectl get pods -n $NAMESPACE -o wide + echo -e "\n${YELLOW}Suggested checks:${NC}" + echo "1. Check logs of unready pods: kubectl logs -n $NAMESPACE " + echo "2. Check PVC status: kubectl get pvc -n $NAMESPACE" + echo "3. Check Service status: kubectl get svc -n $NAMESPACE" + return 1 + fi + + local not_running=$(kubectl get pods -n $NAMESPACE -o jsonpath='{range .items[*]}{.metadata.name} {.status.phase} {.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}' \ + | awk '$2 != "Running" || $3 != "True" {print $1 " " $2}') + + if [ -z "$not_running" ]; then + echo -e "${GREEN}All pods are running normally!${NC}" >&2 + kubectl get pods -n $NAMESPACE -o wide + return 0 + else + echo "Waiting for pods to be ready (waited ${elapsed} seconds)..." + echo "Current unready pods:" + echo "$not_running" | awk '{print " - " $1 " (" $2 ")"}' + sleep 10 + fi + done +} + +# Modify main function +main() { + parse_arguments "$@" + + pre_install_checks + + local arch host + arch=$(get_architecture) || exit 1 + host=$(get_network_ip) || exit 1 + + uninstall_eulercopilot + + if ! get_client_info_auto; then + get_client_info_manual + fi + + check_directories + + # Interactive prompt optimization + if [ -t 0 ]; then + echo -e "${YELLOW}Keep existing model configuration?${NC}" + echo -e " ${BLUE}Y) Keep existing configuration${NC}" + echo -e " ${BLUE}n) Use default configuration${NC}" + while true; do + read -p "Please choose (Y/N): " input_preserve + case "${input_preserve:-Y}" in + [YyNn]) preserve_models=${input_preserve:-Y}; break ;; + *) echo -e "${RED}Invalid input, please choose Y or n${NC}" ;; + esac + done + else + preserve_models="N" + fi + + echo -e "${BLUE}Starting YAML configuration modification...${NC}" + modify_yaml "$host" "$preserve_models" + + echo -e "${BLUE}Starting Helm installation...${NC}" + execute_helm_install "$arch" + + if check_pods_status; then + echo -e "${GREEN}All components are ready!${NC}" + show_success_message "$host" "$arch" + else + echo -e "${YELLOW}Some components are not ready, recommended to investigate!${NC}" + fi +} + +# Add installation success message display function +show_success_message() { + local host=$1 + local arch=$2 + + echo -e "\n${GREEN}==================================================${NC}" + echo -e "${GREEN} EulerCopilot Deployment Completed! ${NC}" + echo -e "${GREEN}==================================================${NC}" + + echo -e "${YELLOW}Access Information:${NC}" + echo -e "EulerCopilot UI: ${eulercopilot_address}" + echo -e "AuthHub Admin UI: ${authhub_address}" + + echo -e "\n${YELLOW}System Information:${NC}" + echo -e "Internal IP: ${host}" + echo -e "System Arch: $(uname -m) (identified as: ${arch})" + echo -e "Plugins Dir: ${PLUGINS_DIR}" + echo -e "Chart Dir: ${DEPLOY_DIR}/chart/" + + echo -e "${BLUE}Operation Guide:${NC}" + echo -e "1. Check cluster status: kubectl get pod -n $NAMESPACE" + echo -e "2. View real-time logs: kubectl logs -f -n $NAMESPACE " + echo -e " Example: kubectl logs -f framework-deploy-5577c87b6-h82g8 -n euler-copilot" + echo -e "3. Check POD status: kubectl get pods -n $NAMESPACE" + + +} + +main "$@" diff --git a/deploy/scripts/8-install-EulerCopilot/install_eulercopilot.sh b/deploy/scripts/8-install-EulerCopilot/install_eulercopilot_zh.sh old mode 100755 new mode 100644 similarity index 100% rename from deploy/scripts/8-install-EulerCopilot/install_eulercopilot.sh rename to deploy/scripts/8-install-EulerCopilot/install_eulercopilot_zh.sh diff --git a/deploy/scripts/9-other-script/backup_databases.sh b/deploy/scripts/9-other-script/backup_databases.sh index b254267bb..1de4f101a 100644 --- a/deploy/scripts/9-other-script/backup_databases.sh +++ b/deploy/scripts/9-other-script/backup_databases.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -# 颜色定义 +# Color definitions RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' @@ -10,7 +10,7 @@ PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color -# 备份目录 +# Backup directories BACKUP_BASE="/home/dump" MYSQL_BACKUP_DIR="$BACKUP_BASE/mysql" OPENGAUSS_BACKUP_DIR="$BACKUP_BASE/opengauss" @@ -23,14 +23,12 @@ MYSQL_TABLE_NAME="user" GS_USERNAME="postgres" GS_DB="postgres" - - -# 时间戳函数 +# Timestamp function timestamp() { echo -n "$(date '+%Y-%m-%d %H:%M:%S')" } -# 日志函数 +# Log functions log_info() { echo -e "$(timestamp) ${BLUE}=== $1 ${NC}" } @@ -51,11 +49,11 @@ log_step() { echo -e "$(timestamp) ${PURPLE} $1 ${NC}" } -# 打印横幅 +# Print banner print_banner() { echo -e "${GREEN}" echo "================================================================" - echo " Euler Copilot 数据备份脚本" + echo " Euler Copilot Data Backup Script" echo " MySQL + OpenGauss + MinIO" echo "================================================================" echo -e "${NC}" @@ -64,12 +62,12 @@ print_banner() { print_completion_banner() { echo -e "${GREEN}" echo "================================================================" - echo " MySQL + OpenGauss + MinIO 数据备份已完成!" + echo " MySQL + OpenGauss + MinIO Data Backup Completed!" echo "================================================================" echo -e "${NC}" } -# 检查命令执行结果 +# Check command execution result check_command() { if [ $? -eq 0 ]; then log_success "$1" @@ -79,213 +77,213 @@ check_command() { fi } -# 创建备份目录 +# Create backup directories create_backup_directories() { - log_step "创建备份目录" - + log_step "Creating backup directories" + mkdir -p "$MYSQL_BACKUP_DIR" "$OPENGAUSS_BACKUP_DIR" "$MINIO_BACKUP_DIR" - check_command "备份目录创建完成" "备份目录创建失败" - - log_info "MySQL备份目录: $MYSQL_BACKUP_DIR" - log_info "OpenGauss备份目录: $OPENGAUSS_BACKUP_DIR" - log_info "MinIO备份目录: $MINIO_BACKUP_DIR" + check_command "Backup directories created" "Failed to create backup directories" + + log_info "MySQL backup directory: $MYSQL_BACKUP_DIR" + log_info "OpenGauss backup directory: $OPENGAUSS_BACKUP_DIR" + log_info "MinIO backup directory: $MINIO_BACKUP_DIR" } -# 备份MySQL数据 +# Backup MySQL data backup_mysql() { - log_step "开始备份MySQL数据" - - # 获取MySQL Pod名称 - log_info "查找MySQL Pod..." + log_step "Starting MySQL data backup" + + # Get MySQL Pod name + log_info "Finding MySQL Pod..." local pod_name=$(kubectl get pod -n euler-copilot | grep mysql | awk '{print $1}') if [ -z "$pod_name" ]; then - log_error "未找到MySQL Pod" + log_error "MySQL Pod not found" return 1 fi - log_success "找到Pod: $pod_name" - - # 获取MySQL密码 - log_info "获取MySQL密码..." + log_success "Found Pod: $pod_name" + + # Get MySQL password + log_info "Getting MySQL password..." local mysql_password=$(kubectl get secret authhub-secret -n euler-copilot -o jsonpath='{.data.mysql-password}' | base64 --decode) if [ -z "$mysql_password" ]; then - log_error "获取MySQL密码失败" + log_error "Failed to get MySQL password" return 1 fi - log_success "密码获取成功" - - # 导出user表 - log_info "导出user表数据..." + log_success "Password obtained successfully" + + # Export user table + log_info "Exporting user table data..." kubectl exec $pod_name -n euler-copilot -- bash -c "mysqldump -u${MYSQL_USER} -p${mysql_password} --no-tablespaces ${MYSQL_DB_NAME} ${MYSQL_TABLE_NAME} > ${MYSQL_DATA_PATH}" - check_command "user表导出完成" "user表导出失败" - - # 拷贝备份文件到本地 - log_info "拷贝备份文件到本地..." + check_command "User table export completed" "User table export failed" + + # Copy backup file to local + log_info "Copying backup file to local..." kubectl cp $pod_name:${MYSQL_DATA_PATH} $MYSQL_BACKUP_DIR/mysql.sql -n euler-copilot - check_command "MySQL备份文件拷贝完成" "MySQL备份文件拷贝失败" - - # 验证备份文件 + check_command "MySQL backup file copy completed" "MySQL backup file copy failed" + + # Verify backup file if [ -f "$MYSQL_BACKUP_DIR/mysql.sql" ]; then local file_size=$(du -h "$MYSQL_BACKUP_DIR/mysql.sql" | cut -f1) - log_success "MySQL备份完成,文件大小: $file_size" + log_success "MySQL backup completed, file size: $file_size" else - log_error "MySQL备份文件未找到" + log_error "MySQL backup file not found" return 1 fi } -# 备份OpenGauss数据 +# Backup OpenGauss data backup_opengauss() { - log_step "开始备份OpenGauss数据" - - # 获取OpenGauss Pod名称 - log_info "查找OpenGauss Pod..." + log_step "Starting OpenGauss data backup" + + # Get OpenGauss Pod name + log_info "Finding OpenGauss Pod..." local pod_name=$(kubectl get pod -n euler-copilot | grep opengauss | awk '{print $1}') if [ -z "$pod_name" ]; then - log_error "未找到OpenGauss Pod" + log_error "OpenGauss Pod not found" return 1 fi - log_success "找到Pod: $pod_name" - - # 获取OpenGauss密码 - log_info "获取OpenGauss密码..." + log_success "Found Pod: $pod_name" + + # Get OpenGauss password + log_info "Getting OpenGauss password..." local gauss_password=$(kubectl get secret euler-copilot-database -n euler-copilot -o jsonpath='{.data.gauss-password}' | base64 --decode) if [ -z "$gauss_password" ]; then - log_error "获取OpenGauss密码失败" + log_error "Failed to get OpenGauss password" return 1 fi - log_success "密码获取成功" - - # 导出数据库 - log_info "导出OpenGauss数据库..." + log_success "Password obtained successfully" + + # Export database + log_info "Exporting OpenGauss database..." kubectl exec -it "$pod_name" -n euler-copilot -- /bin/sh -c "su - omm -c 'source ~/.bashrc && gs_dump -U ${GS_USERNAME} -f ${OPENGAUSS_DATA_PATH} -p 5432 ${GS_DB} -F p -W \"${gauss_password}\"'" - check_command "OpenGauss数据库导出完成" "OpenGauss数据库导出失败" - - # 拷贝备份文件到本地 - log_info "拷贝备份文件到本地..." + check_command "OpenGauss database export completed" "OpenGauss database export failed" + + # Copy backup file to local + log_info "Copying backup file to local..." kubectl cp $pod_name:${OPENGAUSS_DATA_PATH} $OPENGAUSS_BACKUP_DIR/opengauss.sql -n euler-copilot - check_command "OpenGauss备份文件拷贝完成" "OpenGauss备份文件拷贝失败" - - # 验证备份文件 + check_command "OpenGauss backup file copy completed" "OpenGauss backup file copy failed" + + # Verify backup file if [ -f "$OPENGAUSS_BACKUP_DIR/opengauss.sql" ]; then local file_size=$(du -h "$OPENGAUSS_BACKUP_DIR/opengauss.sql" | cut -f1) - log_success "OpenGauss备份完成,文件大小: $file_size" + log_success "OpenGauss backup completed, file size: $file_size" else - log_error "OpenGauss备份文件未找到" + log_error "OpenGauss backup file not found" return 1 fi } -# 备份MinIO数据 +# Backup MinIO data backup_minio() { - log_step "开始备份MinIO数据" - - # 获取PV名称 - log_info "查找MinIO PV..." + log_step "Starting MinIO data backup" + + # Get PV name + log_info "Finding MinIO PV..." local pv_name=$(kubectl get pv -n euler-copilot | grep minio | awk '{print $1}') if [ -z "$pv_name" ]; then - log_error "未找到MinIO PV" + log_error "MinIO PV not found" return 1 fi - log_success "找到PV: $pv_name" - - # MinIO数据目录 + log_success "Found PV: $pv_name" + + # MinIO data directory local minio_storage_dir="/var/lib/rancher/k3s/storage/${pv_name}_euler-copilot_minio-storage/" - - # 检查源目录是否存在 + + # Check if source directory exists if [ ! -d "$minio_storage_dir" ]; then - log_error "MinIO存储目录不存在: $minio_storage_dir" + log_error "MinIO storage directory does not exist: $minio_storage_dir" return 1 fi - - # 备份MinIO数据 - log_info "开始备份MinIO数据..." + + # Backup MinIO data + log_info "Starting MinIO data backup..." cp -r "$minio_storage_dir"* "$MINIO_BACKUP_DIR"/ - check_command "MinIO数据备份完成" "MinIO数据备份失败" - - # 验证备份 + check_command "MinIO data backup completed" "MinIO data backup failed" + + # Verify backup local source_count=$(find "$minio_storage_dir" -type f 2>/dev/null | wc -l) local backup_count=$(find "$MINIO_BACKUP_DIR" -type f 2>/dev/null | wc -l) - - log_info "源文件数: $source_count, 备份文件数: $backup_count" - + + log_info "Source file count: $source_count, Backup file count: $backup_count" + if [ "$source_count" -eq "$backup_count" ]; then - log_success "MinIO备份验证成功" + log_success "MinIO backup verification successful" else - log_warning "文件数量不一致,但备份已完成" + log_warning "File count mismatch, but backup completed" fi } -# 显示备份摘要 +# Show backup summary show_backup_summary() { - log_step "备份摘要" - + log_step "Backup Summary" + echo -e "${CYAN}" - echo "备份位置: $BACKUP_BASE" + echo "Backup Location: $BACKUP_BASE" echo "----------------------------------------" - - # MySQL备份信息 + + # MySQL backup information if [ -f "$MYSQL_BACKUP_DIR/mysql.sql" ]; then local mysql_size=$(du -h "$MYSQL_BACKUP_DIR/mysql.sql" | cut -f1) echo "MySQL: $MYSQL_BACKUP_DIR/mysql.sql ($mysql_size)" else - echo "MySQL: 备份失败" + echo "MySQL: Backup failed" fi - - # OpenGauss备份信息 + + # OpenGauss backup information if [ -f "$OPENGAUSS_BACKUP_DIR/opengauss.sql" ]; then local gauss_size=$(du -h "$OPENGAUSS_BACKUP_DIR/opengauss.sql" | cut -f1) echo "OpenGauss: $OPENGAUSS_BACKUP_DIR/opengauss.sql ($gauss_size)" else - echo "OpenGauss: 备份失败" + echo "OpenGauss: Backup failed" fi - - # MinIO备份信息 + + # MinIO backup information if [ -d "$MINIO_BACKUP_DIR" ]; then - local minio_size=$(du -sh "$MINIO_BACKUP_DIR" 2>/dev/null | cut -f1 || echo "未知") + local minio_size=$(du -sh "$MINIO_BACKUP_DIR" 2>/dev/null | cut -f1 || echo "Unknown") local minio_count=$(find "$MINIO_BACKUP_DIR" -type f 2>/dev/null | wc -l) - echo "MinIO: $MINIO_BACKUP_DIR/ ($minio_size, $minio_count 个文件)" + echo "MinIO: $MINIO_BACKUP_DIR/ ($minio_size, $minio_count files)" else - echo "MinIO: 备份失败" + echo "MinIO: Backup failed" fi echo -e "${NC}" } -# 主函数 +# Main function main() { print_banner - - log_step "开始数据备份流程" - - # 创建备份目录 + + log_step "Starting data backup process" + + # Create backup directories create_backup_directories - - # 备份MySQL + + # Backup MySQL if backup_mysql; then - log_success "MySQL备份成功" + log_success "MySQL backup successful" else - log_error "MySQL备份失败" + log_error "MySQL backup failed" fi - - # 备份OpenGauss + + # Backup OpenGauss if backup_opengauss; then - log_success "OpenGauss备份成功" + log_success "OpenGauss backup successful" else - log_error "OpenGauss备份失败" + log_error "OpenGauss backup failed" fi - - # 备份MinIO + + # Backup MinIO if backup_minio; then - log_success "MinIO备份成功" + log_success "MinIO backup successful" else - log_error "MinIO备份失败" + log_error "MinIO backup failed" fi - - # 显示备份摘要 + + # Show backup summary show_backup_summary - + print_completion_banner - log_success "数据备份流程已完成" + log_success "Data backup process completed" } -# 执行主函数 +# Execute main function main "$@" diff --git a/deploy/scripts/9-other-script/get_client_id_and_secret.py b/deploy/scripts/9-other-script/get_client_id_and_secret.py index 901856c69..cb71e116f 100755 --- a/deploy/scripts/9-other-script/get_client_id_and_secret.py +++ b/deploy/scripts/9-other-script/get_client_id_and_secret.py @@ -1,5 +1,5 @@ """ -获取认证信息 +Get Authentication Information """ import json import sys @@ -16,14 +16,14 @@ def get_service_cluster_ip(namespace, service_name): if result.returncode != 0: error_msg = result.stderr.decode().strip() - print(f"获取服务信息失败: [命名空间: {namespace}] [服务名: {service_name}]") - print(f"Kubectl错误详情: {error_msg}") + print(f"Failed to get service info: [Namespace: {namespace}] [Service: {service_name}]") + print(f"Kubectl error details: {error_msg}") if "NotFound" in error_msg: - print("→ 请检查:") - print(f" 1. 服务是否部署完成(kubectl get pods -n {namespace})") - print(f" 2. 服务名称是否拼写正确") - print(f" 3. 是否在正确的Kubernetes上下文环境中") + print("→ Please check:") + print(f" 1. Whether the service is deployed (kubectl get pods -n {namespace})") + print(f" 2. Whether the service name is spelled correctly") + print(f" 3. Whether you are in the correct Kubernetes context") sys.exit(1) service_info = json.loads(result.stdout.decode()) @@ -70,10 +70,10 @@ def find_existing_app(authhub_web_url, user_token, client_name): def register_or_update_app(authhub_web_url, user_token, client_name, client_url, redirect_urls): client_id = find_existing_app(authhub_web_url, user_token, client_name) - + if client_id: - # 更新现有应用 - print(f"发现已存在应用 [名称: {client_name}], 正在更新...") + # Update existing application + print(f"Found existing application [Name: {client_name}], updating...") url = f"{authhub_web_url}/oauth2/applications/{client_id}" response = requests.put( url, @@ -94,8 +94,8 @@ def register_or_update_app(authhub_web_url, user_token, client_name, client_url, response.raise_for_status() return response.json()["data"] else: - # 注册新应用 - print(f"未找到已存在应用 [名称: {client_name}], 正在注册新应用...") + # Register new application + print(f"No existing application found [Name: {client_name}], registering new application...") response = requests.post( authhub_web_url + "/oauth2/applications/register", json={ @@ -130,43 +130,43 @@ def get_client_secret(authhub_web_url, user_token, client_id): } if __name__ == "__main__": - # 解析命令行参数 + # Parse command line arguments parser = argparse.ArgumentParser() - parser.add_argument("eulercopilot_address", help="EulerCopilot前端地址(默认:http://172.0.0.1:30080)") + parser.add_argument("eulercopilot_address", help="EulerCopilot frontend address (default:http://172.0.0.1:30080)") args = parser.parse_args() - # 获取服务信息 + # Get service information namespace = "euler-copilot" service_name = "authhub-web-service" - print(f"正在查询服务信息: [命名空间: {namespace}] [服务名: {service_name}]") + print(f"Querying service info: [Namespace: {namespace}] [Service: {service_name}]") cluster_ip = get_service_cluster_ip(namespace, service_name) authhub_web_url = f"http://{cluster_ip}:8000" - # 生成固定URL + # Generate fixed URLs client_url = f"{args.eulercopilot_address}" redirect_urls = [f"{args.eulercopilot_address}/api/auth/login"] - client_name = "EulerCopilot" # 设置固定默认值 + client_name = "EulerCopilot" # Set fixed default value - # 认证流程 + # Authentication process try: - print("\n正在获取用户令牌...") + print("\nGetting user token...") user_token = get_user_token(authhub_web_url) - print("✓ 用户令牌获取成功") + print("✓ User token obtained successfully") - print(f"\n正在处理应用 [名称: {client_name}]...") + print(f"\nProcessing application [Name: {client_name}]...") app_info = register_or_update_app(authhub_web_url, user_token, client_name, client_url, redirect_urls) - print("✓ 应用处理成功") + print("✓ Application processed successfully") - print(f"\n正在查询客户端凭证 [ID: {app_info['client_info']['client_id']}]...") + print(f"\nQuerying client credentials [ID: {app_info['client_info']['client_id']}]...") client_info = get_client_secret(authhub_web_url, user_token, app_info["client_info"]["client_id"]) - print("\n✓ 认证信息获取成功:") + print("\n✓ Authentication information obtained successfully:") print(f"client_id: {client_info['client_id']}") print(f"client_secret: {client_info['client_secret']}") except requests.exceptions.HTTPError as e: - print(f"\nHTTP 错误: {e.response.status_code} - {e.response.text}") + print(f"\nHTTP Error: {e.response.status_code} - {e.response.text}") sys.exit(1) except Exception as e: - print(f"\n错误: {str(e)}") + print(f"\nError: {str(e)}") sys.exit(1) diff --git a/deploy/scripts/9-other-script/get_log.sh b/deploy/scripts/9-other-script/get_log.sh index 3b02f9636..32eef6451 100755 --- a/deploy/scripts/9-other-script/get_log.sh +++ b/deploy/scripts/9-other-script/get_log.sh @@ -1,40 +1,37 @@ #!/bin/bash function help { - echo -e "用法:./get_log.sh [命名空间] [日志时间]"; - echo -e "示例:./get_log.sh euler-copilot 1h"; + echo -e "Usage: ./get_log.sh [namespace] [log_time]"; + echo -e "Example: ./get_log.sh euler-copilot 1h"; } - function main { - echo -e "[Info]开始收集各Pod日志"; - time=$(date -u +"%s"); - echo -e "[Info]当前命名空间:$1,当前时间戳:$time" - filename="logs_$1_$time"; - - mkdir $filename; - echo $time > $filename/timestamp; - - echo "[Info]开始收集日志"; - kubectl -n $1 events > $filename/events.log; - - pod_names=$(kubectl -n $1 get pods -o name); - while IFS= read -r line || [[ -n $line ]]; do - mkdir -p $filename/$line; - kubectl -n $1 describe $line > $filename/$line/details.log; - kubectl -n $1 logs --previous --since $2 --all-containers=true --ignore-errors=true $line > $filename/$line/previous.log; - kubectl -n $1 logs --since $2 --all-containers=true --ignore-errors=true $line > $filename/$line/current.log; - done < <(printf '%s' "$pod_names"); - - tar -czf $filename.tar.gz $filename/; - rm -rf $filename; - - echo -e "[Info]收集日志结束,请将$filename.tar.gz提供给我们进行分析"; -} + echo -e "[Info] Starting to collect pod logs"; + time=$(date -u +"%s"); + echo -e "[Info] Current namespace: $1, Current timestamp: $time" + filename="logs_$1_$time"; + + mkdir $filename; + echo $time > $filename/timestamp; + + echo "[Info] Starting log collection"; + kubectl -n $1 events > $filename/events.log; + pod_names=$(kubectl -n $1 get pods -o name); + while IFS= read -r line || [[ -n $line ]]; do + mkdir -p $filename/$line; + kubectl -n $1 describe $line > $filename/$line/details.log; + kubectl -n $1 logs --previous --since $2 --all-containers=true --ignore-errors=true $line > $filename/$line/previous.log; + kubectl -n $1 logs --since $2 --all-containers=true --ignore-errors=true $line > $filename/$line/current.log; + done < <(printf '%s' "$pod_names"); + + tar -czf $filename.tar.gz $filename/; + rm -rf $filename; + + echo -e "[Info] Log collection completed, please provide $filename.tar.gz to us for analysis"; +} if [[ $# -lt 2 ]]; then - help + help else - main $1 $2; + main $1 $2; fi - \ No newline at end of file diff --git a/deploy/scripts/9-other-script/import_images.sh b/deploy/scripts/9-other-script/import_images.sh index e5b97706a..df8523380 100755 --- a/deploy/scripts/9-other-script/import_images.sh +++ b/deploy/scripts/9-other-script/import_images.sh @@ -1,37 +1,37 @@ #!/bin/bash -# 颜色定义 +# Color definitions RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' MAGENTA='\033[0;35m' CYAN='\033[0;36m' -NC='\033[0m' # 恢复默认颜色 +NC='\033[0m' # Reset color -# 默认配置 +# Default configuration DEFAULT_VERSION="0.9.5" IMAGE_BASE_DIR="/home/eulercopilot/images" -# 显示帮助信息 +# Show help information show_help() { - echo -e "${YELLOW}使用说明:${NC}" - echo -e " $0 [选项] [参数]" - echo -e "${YELLOW}选项:${NC}" - echo -e " -v, --version <版本>\t指定镜像版本 (默认: ${DEFAULT_VERSION})" - echo -e " -i, --import <文件>\t导入单个镜像文件" - echo -e " -d, --delete <镜像>\t删除指定镜像 (格式: repo/image:tag)" - echo -e " --delete-all\t\t删除所有neocopilot镜像" - echo -e " -h, --help\t\t显示帮助信息" - echo -e "${YELLOW}示例:${NC}" - echo -e " $0 -v 0.9.4\t\t导入0.9.4版本的镜像" - echo -e " $0 -i $IMAGE_BASE_DIR/$DEFAULT_VERSION/myimage.tar\t导入单个镜像文件" - echo -e " $0 -d hub.oepkgs.net/neocopilot/authhub:0.9.3-arm\t删除指定镜像" - echo -e " $0 --delete-all\t删除所有neocopilot镜像" + echo -e "${YELLOW}Usage:${NC}" + echo -e " $0 [options] [parameters]" + echo -e "${YELLOW}Options:${NC}" + echo -e " -v, --version \tSpecify image version (default: ${DEFAULT_VERSION})" + echo -e " -i, --import \t\tImport single image file" + echo -e " -d, --delete \t\tDelete specified image (format: repo/image:tag)" + echo -e " --delete-all\t\t\tDelete all neocopilot images" + echo -e " -h, --help\t\t\tShow help information" + echo -e "${YELLOW}Examples:${NC}" + echo -e " $0 -v 0.9.4\t\t\tImport version 0.9.4 images" + echo -e " $0 -i $IMAGE_BASE_DIR/$DEFAULT_VERSION/myimage.tar\tImport single image file" + echo -e " $0 -d hub.oepkgs.net/neocopilot/authhub:0.9.3-arm\tDelete specified image" + echo -e " $0 --delete-all\t\tDelete all neocopilot images" exit 0 } -# 参数解析 +# Parameter parsing parse_args() { while [[ $# -gt 0 ]]; do case "$1" in @@ -55,7 +55,7 @@ parse_args() { show_help ;; *) - echo -e "${RED}未知参数: $1${NC}" + echo -e "${RED}Unknown parameter: $1${NC}" show_help exit 1 ;; @@ -63,7 +63,7 @@ parse_args() { done } -# 系统架构检测 +# System architecture detection detect_architecture() { ARCH=$(uname -m) case $ARCH in @@ -74,61 +74,61 @@ detect_architecture() { ARCH_SUFFIX="arm" ;; *) - echo -e "${RED}不支持的架构: $ARCH${NC}" + echo -e "${RED}Unsupported architecture: $ARCH${NC}" exit 1 ;; esac } -# 删除指定镜像 +# Delete specified image delete_image() { local image=$1 - echo -e "${YELLOW}正在删除镜像: $image${NC}" + echo -e "${YELLOW}Deleting image: $image${NC}" if sudo k3s ctr -n=k8s.io images rm "$image"; then - echo -e "${GREEN} 删除成功${NC}" + echo -e "${GREEN} Deletion successful${NC}" else - echo -e "${RED} 删除失败${NC}" + echo -e "${RED} Deletion failed${NC}" fi } -# 删除所有neocopilot镜像 +# Delete all neocopilot images delete_all_neocopilot_images() { - echo -e "${YELLOW}正在删除所有neocopilot镜像...${NC}" + echo -e "${YELLOW}Deleting all neocopilot images...${NC}" sudo k3s crictl images | grep neocopilot | awk '{print $1":"$2}' | while read -r image; do delete_image "$image" done } -# 导入单个镜像文件 +# Import single image file import_single_image() { local file=$1 - echo -e "${CYAN}正在导入单个镜像: $file${NC}" - + echo -e "${CYAN}Importing single image: $file${NC}" + if [[ ! -f "$file" ]]; then - echo -e "${RED}错误: 文件不存在 $file${NC}" + echo -e "${RED}Error: File does not exist $file${NC}" exit 1 fi if sudo k3s ctr -n=k8s.io images import "$file"; then - echo -e "${GREEN} 导入成功${NC}" + echo -e "${GREEN} Import successful${NC}" else - echo -e "${RED} 导入失败${NC}" + echo -e "${RED} Import failed${NC}" exit 1 fi } -# 批量导入镜像 +# Batch import images batch_import_images() { local version=$1 local image_dir="$IMAGE_BASE_DIR/$version" - + if [[ ! -d "$image_dir" ]]; then - echo -e "${RED}错误:镜像目录不存在 $image_dir${NC}" + echo -e "${RED}Error: Image directory does not exist $image_dir${NC}" exit 1 fi - echo -e "${CYAN}正在扫描目录: $image_dir${NC}" - echo -e "${CYAN}找到以下TAR文件:${NC}" + echo -e "${CYAN}Scanning directory: $image_dir${NC}" + echo -e "${CYAN}Found the following TAR files:${NC}" ls -1 "$image_dir"/*.tar local success_count=0 @@ -137,30 +137,30 @@ batch_import_images() { for tar_file in "$image_dir"/*.tar; do [[ -f "$tar_file" ]] || continue - echo -e "\n${BLUE}正在导入 $tar_file...${NC}" + echo -e "\n${BLUE}Importing $tar_file...${NC}" if sudo k3s ctr -n=k8s.io images import "$tar_file"; then ((success_count++)) - echo -e "${GREEN} 导入成功${NC}" + echo -e "${GREEN} Import successful${NC}" else ((fail_count++)) - echo -e "${RED} 导入失败${NC}" + echo -e "${RED} Import failed${NC}" fi done - echo -e "\n${CYAN}导入结果:${NC}" - echo -e "${GREEN}成功: $success_count 个${NC}" - echo -e "${RED}失败: $fail_count 个${NC}" - + echo -e "\n${CYAN}Import results:${NC}" + echo -e "${GREEN}Successful: $success_count${NC}" + echo -e "${RED}Failed: $fail_count${NC}" + return $fail_count } -# 镜像完整性检查 +# Image integrity check check_images() { local version=$1 local missing_count=0 - # 基础镜像列表(使用版本变量) + # Base image list (using version variable) local base_images=( "hub.oepkgs.net/neocopilot/euler-copilot-framework:${version}-arm" "hub.oepkgs.net/neocopilot/euler-copilot-web:${version}-arm" @@ -176,7 +176,7 @@ check_images() { "hub.oepkgs.net/neocopilot/secret_inject:dev-arm" ) - # 根据架构调整预期镜像标签 + # Adjust expected image tags based on architecture local expected_images=() for image in "${base_images[@]}"; do if [[ "$ARCH_SUFFIX" == "x86" ]]; then @@ -187,34 +187,34 @@ check_images() { expected_images+=("$expected_image") done - echo -e "\n${MAGENTA}开始镜像完整性检查:${NC}" + echo -e "\n${MAGENTA}Starting image integrity check:${NC}" for image in "${expected_images[@]}"; do if sudo k3s ctr -n=k8s.io images ls | grep -q "$image"; then - echo -e "${GREEN}[存在] $image${NC}" + echo -e "${GREEN}[Exists] $image${NC}" else - echo -e "${RED}[缺失] $image${NC}" + echo -e "${RED}[Missing] $image${NC}" ((missing_count++)) fi done - echo -e "\n${MAGENTA}使用crictl检查镜像:${NC}" + echo -e "\n${MAGENTA}Checking images with crictl:${NC}" sudo k3s crictl images | grep neocopilot if [[ $missing_count -gt 0 ]]; then - echo -e "\n${RED}警告:缺少 $missing_count 个必需镜像${NC}" + echo -e "\n${RED}Warning: Missing $missing_count required images${NC}" return 1 else - echo -e "\n${GREEN}所有必需镜像已就绪${NC}" + echo -e "\n${GREEN}All required images are ready${NC}" return 0 fi } -# 主函数 +# Main function main() { parse_args "$@" detect_architecture - # 处理删除操作 + # Handle delete operations if [[ -n "$image_to_delete" ]]; then delete_image "$image_to_delete" exit 0 @@ -225,19 +225,19 @@ main() { exit 0 fi - # 处理单个镜像导入 + # Handle single image import if [[ -n "$single_image_file" ]]; then import_single_image "$single_image_file" exit 0 fi - # 默认批量导入模式 + # Default batch import mode local version=${eulercopilot_version:-$DEFAULT_VERSION} - + echo -e "${YELLOW}==============================${NC}" - echo -e "${CYAN}架构检测\t: ${ARCH_SUFFIX}${NC}" - echo -e "${CYAN}目标版本\t: ${version}${NC}" - echo -e "${CYAN}镜像目录\t: ${IMAGE_BASE_DIR}/${version}${NC}" + echo -e "${CYAN}Architecture\t: ${ARCH_SUFFIX}${NC}" + echo -e "${CYAN}Target version\t: ${version}${NC}" + echo -e "${CYAN}Image directory\t: ${IMAGE_BASE_DIR}/${version}${NC}" echo -e "${YELLOW}==============================${NC}" batch_import_images "$version" @@ -246,13 +246,13 @@ main() { if [[ $import_result -eq 0 ]]; then check_images "$version" || exit 1 else - echo -e "${RED}存在导入失败的镜像,跳过完整性检查${NC}" + echo -e "${RED}Some images failed to import, skipping integrity check${NC}" exit 1 fi - echo -e "${GREEN}系统准备就绪,所有镜像可用${NC}" + echo -e "${GREEN}System ready, all images available${NC}" } -# 执行主函数 +# Execute main function main "$@" exit 0 diff --git a/deploy/scripts/9-other-script/migrate_minio_database.sh b/deploy/scripts/9-other-script/migrate_minio_database.sh index 26f1128cd..bc17e8b96 100644 --- a/deploy/scripts/9-other-script/migrate_minio_database.sh +++ b/deploy/scripts/9-other-script/migrate_minio_database.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -# 颜色定义 +# Color definitions RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' @@ -10,14 +10,14 @@ PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color -# 日志函数 +# Log functions log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_step() { echo -e "${PURPLE}[STEP]${NC} $1"; } -# 全局变量 +# Global variables PV_NAME="" POD_NAME="" STORAGE_DIR="" @@ -28,12 +28,12 @@ MINIO_HOST="" MINIO_PORT="" source_dir="/home/dump/minio" -# 打印横幅 +# Print banner print_banner() { echo -e "${GREEN}" echo "====================================================================" - echo " MINIO数据导入脚本" - echo " Euler Copilot 项目专用" + echo " MINIO Data Import Script" + echo " Euler Copilot Project Specific" echo "====================================================================" echo -e "${NC}" } @@ -41,28 +41,28 @@ print_banner() { print_completion_banner() { echo -e "${GREEN}" echo "====================================================================" - echo " MINIO数据导入已完成!" + echo " MINIO Data Import Completed!" echo "====================================================================" echo -e "${NC}" } -# 用户确认 +# User confirmation confirm_execution() { - echo -e "${YELLOW}警告: 此操作将清空现有MinIO数据并导入新数据!${NC}" - read -p "确认执行MinIO数据导入操作?(y/N): " -n 1 -r + echo -e "${YELLOW}Warning: This operation will clear existing MinIO data and import new data!${NC}" + read -p "Confirm execution of MinIO data import operation? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then - log_info "操作已取消" + log_info "Operation cancelled" exit 0 fi } -# 清除颜色代码和特殊字符 +# Remove color codes and special characters clean_output() { echo "$1" | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g" | tr -d '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' } -# 检查命令执行结果 +# Check command execution result check_command() { if [ $? -eq 0 ]; then log_success "$1" @@ -72,173 +72,173 @@ check_command() { fi } -# 检查前置条件 +# Check prerequisites check_prerequisites() { - log_step "检查前置条件..." - - # 检查kubectl是否可用 + log_step "Checking prerequisites..." + + # Check if kubectl is available kubectl cluster-info &> /dev/null - check_command "kubectl连接正常" "无法连接到Kubernetes集群" - - # 检查命名空间是否存在 + check_command "kubectl connection normal" "Unable to connect to Kubernetes cluster" + + # Check if namespace exists if ! kubectl get namespace euler-copilot &> /dev/null; then - log_error "命名空间 euler-copilot 不存在" + log_error "Namespace euler-copilot does not exist" exit 1 fi - log_success "命名空间 euler-copilot 存在" + log_success "Namespace euler-copilot exists" } -# 获取K8s资源信息 +# Get Kubernetes resources get_kubernetes_resources() { - log_step "获取Kubernetes资源信息..." - - # 获取PV名称 + log_step "Getting Kubernetes resource information..." + + # Get PV name PV_NAME=$(kubectl get pv -n euler-copilot | grep minio | awk '{print $1}') if [ -z "$PV_NAME" ]; then - log_error "未找到MinIO的PV" + log_error "No MinIO PV found" exit 1 fi - log_info "PV名称: $PV_NAME" - - # 获取Pod名称 + log_info "PV name: $PV_NAME" + + # Get Pod name POD_NAME=$(kubectl get pods -n euler-copilot | grep minio | grep Running | awk '{print $1}') POD_NAME=$(clean_output "$POD_NAME") if [ -z "$POD_NAME" ]; then - log_error "未找到运行的MinIO Pod" + log_error "No running MinIO Pod found" exit 1 fi - log_info "Pod名称: $POD_NAME" - - # 设置存储目录 + log_info "Pod name: $POD_NAME" + + # Set storage directory STORAGE_DIR="/var/lib/rancher/k3s/storage/${PV_NAME}_euler-copilot_minio-storage/" - log_info "存储目录: $STORAGE_DIR" + log_info "Storage directory: $STORAGE_DIR" } -# 复制数据 +# Copy data copy_data() { - log_step "复制数据..." - + log_step "Copying data..." + if [ -d "$source_dir" ]; then - # 检查源数据 + # Check source data local source_count=$(find "$source_dir" -type f 2>/dev/null | wc -l) if [ "$source_count" -eq 0 ]; then - log_warning "源目录为空,跳过复制" + log_warning "Source directory is empty, skipping copy" return 0 fi - - log_info "源目录文件数: $source_count" + + log_info "Source directory file count: $source_count" cp -r "$source_dir"/* "$STORAGE_DIR" - check_command "数据复制完成" "数据复制失败" - - # 验证复制结果 + check_command "Data copy completed" "Data copy failed" + + # Verify copy result local new_count=$(find "$STORAGE_DIR" -type f 2>/dev/null | wc -l) - log_info "复制后文件数量: $new_count" - + log_info "File count after copy: $new_count" + if [ "$source_count" -eq "$new_count" ]; then - log_success "文件数量验证成功" + log_success "File count verification successful" else - log_warning "文件数量不一致: 源=$source_count, 目标=$new_count" + log_warning "File count mismatch: source=$source_count, target=$new_count" fi else - log_error "源目录 $source_dir 不存在" + log_error "Source directory $source_dir does not exist" exit 1 fi } -# 重启Pod +# Restart Pod restart_pod() { - log_step "重启Pod..." - + log_step "Restarting Pod..." + kubectl delete pod "$POD_NAME" -n euler-copilot - check_command "Pod删除命令执行成功" "Pod删除失败" - - # 等待Pod重启 - log_info "等待Pod重启..." + check_command "Pod deletion command executed successfully" "Pod deletion failed" + + # Wait for Pod restart + log_info "Waiting for Pod restart..." local timeout=60 local counter=0 - + while [ $counter -lt $timeout ]; do NEW_POD_NAME=$(kubectl get pods -n euler-copilot | grep minio | grep Running | awk '{print $1}') NEW_POD_NAME=$(clean_output "$NEW_POD_NAME") - + if [ -n "$NEW_POD_NAME" ]; then - log_success "Pod重启成功: $NEW_POD_NAME" + log_success "Pod restarted successfully: $NEW_POD_NAME" return 0 fi - + counter=$((counter + 5)) sleep 5 echo -n "." done - - log_error "Pod未在指定时间内重启成功" + + log_error "Pod did not restart within specified time" return 1 } -# 获取MinIO配置 +# Get MinIO configuration get_minio_config() { - log_step "获取MinIO配置..." - + log_step "Getting MinIO configuration..." + MINIO_PASSWORD=$(kubectl get secret euler-copilot-database -n euler-copilot -o jsonpath='{.data.minio-password}' 2>/dev/null | base64 --decode) if [ $? -ne 0 ] || [ -z "$MINIO_PASSWORD" ]; then - log_error "获取MinIO密码失败" + log_error "Failed to get MinIO password" exit 1 fi - + MINIO_HOST=$(kubectl get svc -n euler-copilot | grep minio-service | awk '{print $3}') MINIO_PORT=$(kubectl get svc -n euler-copilot | grep minio-service | awk '{split($5, a, "/"); print a[1]}') - - log_info "MinIO配置:" - log_info " 主机: $MINIO_HOST" - log_info " 端口: $MINIO_PORT" - log_info " 用户: $MINIO_ROOT_USER" + + log_info "MinIO configuration:" + log_info " Host: $MINIO_HOST" + log_info " Port: $MINIO_PORT" + log_info " User: $MINIO_ROOT_USER" } -# 验证MinIO数据 +# Verify MinIO data verify_minio_data() { - log_step "验证MinIO数据..." - - # 设置mc客户端 + log_step "Verifying MinIO data..." + + # Set up mc client kubectl exec -it "$NEW_POD_NAME" -n euler-copilot -- mc alias set myminio "http://${MINIO_HOST}:${MINIO_PORT}" "$MINIO_ROOT_USER" "$MINIO_PASSWORD" - check_command "MinIO客户端设置成功" "MinIO客户端设置失败" - - # 列出buckets - log_info "MinIO Buckets列表:" + check_command "MinIO client setup successful" "MinIO client setup failed" + + # List buckets + log_info "MinIO Buckets list:" kubectl exec -it "$NEW_POD_NAME" -n euler-copilot -- mc ls myminio if [ $? -eq 0 ]; then - log_success "MinIO连接正常" + log_success "MinIO connection normal" else - log_error "MinIO连接失败" + log_error "MinIO connection failed" exit 1 fi - - # 检查具体bucket内容 - log_info "检查witchaind-doc bucket:" + + # Check specific bucket content + log_info "Checking witchaind-doc bucket:" kubectl exec -it "$NEW_POD_NAME" -n euler-copilot -- mc ls myminio/witchaind-doc if [ $? -eq 0 ]; then - log_success "witchaind-doc bucket访问成功" + log_success "witchaind-doc bucket access successful" else - log_warning "witchaind-doc bucket不存在或为空" + log_warning "witchaind-doc bucket does not exist or is empty" fi } -# 主函数 +# Main function main() { print_banner confirm_execution - - # 执行各个步骤 + + # Execute each step check_prerequisites get_kubernetes_resources copy_data restart_pod get_minio_config verify_minio_data - + print_completion_banner - log_success "MinIO数据导入流程已全部完成" - log_info "请验证业务功能是否正常" + log_success "MINIO data import process fully completed" + log_info "Please verify if business functions are working normally" } -# 执行主函数 +# Execute main function main "$@" diff --git a/deploy/scripts/9-other-script/migrate_mysql_database.sh b/deploy/scripts/9-other-script/migrate_mysql_database.sh index aa45b4d86..36720984d 100644 --- a/deploy/scripts/9-other-script/migrate_mysql_database.sh +++ b/deploy/scripts/9-other-script/migrate_mysql_database.sh @@ -1,11 +1,11 @@ #!/bin/bash -# MySQL数据库恢复脚本 -# 描述:用于Euler Copilot项目的MySQL数据库恢复 +# MySQL Database Recovery Script +# Description: Used for Euler Copilot project MySQL database recovery -set -e # 遇到错误立即退出 +set -e # Exit immediately on error -# 颜色定义 +# Color definitions RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' @@ -14,7 +14,7 @@ PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color -# 打印函数 +# Print functions print_color() { local color=$1 shift @@ -30,11 +30,11 @@ info() { } warning() { - print_color "${YELLOW}" "[$(date '+%Y-%m-%d %H:%M:%S')] 警告: $1" + print_color "${YELLOW}" "[$(date '+%Y-%m-%d %H:%M:%S')] Warning: $1" } error() { - print_color "${RED}" "[$(date '+%Y-%m-%d %H:%M:%S')] 错误: $1" >&2 + print_color "${RED}" "[$(date '+%Y-%m-%d %H:%M:%S')] Error: $1" >&2 exit 1 } @@ -43,7 +43,7 @@ step() { print_color "${PURPLE}" "[$(date '+%Y-%m-%d %H:%M:%S')] === $1 ===" } -# 配置变量 +# Configuration variables NAMESPACE="euler-copilot" SECRET_NAME="authhub-secret" PASSWORD_KEY="mysql-password" @@ -52,183 +52,183 @@ DB_NAME="oauth2" BACKUP_FILE="/home/dump/mysql/mysql.sql" POD_BACKUP_PATH="/home/mysql.sql" -# 显示横幅 +# Show banner show_banner() { echo print_color "${PURPLE}" "================================================" - print_color "${PURPLE}" " MySQL 数据库恢复脚本" - print_color "${PURPLE}" " Euler Copilot 项目专用" + print_color "${PURPLE}" " MySQL Database Recovery Script" + print_color "${PURPLE}" " Euler Copilot Project Specific" print_color "${PURPLE}" "================================================" echo } -# 检查必要工具 +# Check required tools check_dependencies() { - step "检查必要工具" - command -v kubectl >/dev/null 2>&1 || error "kubectl 未安装" - command -v base64 >/dev/null 2>&1 || error "base64 未安装" - log "依赖检查通过" + step "Checking required tools" + command -v kubectl >/dev/null 2>&1 || error "kubectl not installed" + command -v base64 >/dev/null 2>&1 || error "base64 not installed" + log "Dependency check passed" } -# 获取MySQL Pod名称 +# Get MySQL Pod name get_mysql_pod() { - step "查找MySQL Pod" + step "Finding MySQL Pod" POD_NAME=$(kubectl get pod -n $NAMESPACE 2>/dev/null | grep mysql | grep Running | awk '{print $1}') - + if [ -z "$POD_NAME" ]; then - error "未找到运行的MySQL Pod" + error "No running MySQL Pod found" fi - log "找到Pod: $POD_NAME" + log "Found Pod: $POD_NAME" } -# 获取MySQL密码 +# Get MySQL password get_mysql_password() { - step "获取MySQL密码" + step "Getting MySQL password" MYSQL_PASSWORD=$(kubectl get secret $SECRET_NAME -n $NAMESPACE -o jsonpath="{.data.$PASSWORD_KEY}" 2>/dev/null | base64 --decode) - + if [ -z "$MYSQL_PASSWORD" ]; then - error "无法获取MySQL密码,请检查secret是否存在" + error "Unable to get MySQL password, please check if secret exists" fi - log "密码获取成功" + log "Password obtained successfully" } -# 检查备份文件是否存在 +# Check if backup file exists check_backup_file() { - step "检查备份文件" + step "Checking backup file" if [ ! -f "$BACKUP_FILE" ]; then - error "备份文件 $BACKUP_FILE 不存在" + error "Backup file $BACKUP_FILE does not exist" fi - - # 显示文件信息 + + # Display file information local file_size=$(du -h "$BACKUP_FILE" | cut -f1) - local file_lines=$(wc -l < "$BACKUP_FILE" 2>/dev/null || echo "未知") - info "文件路径: $BACKUP_FILE" - info "文件大小: $file_size" - info "文件行数: $file_lines" - - log "备份文件检查通过" + local file_lines=$(wc -l < "$BACKUP_FILE" 2>/dev/null || echo "Unknown") + info "File path: $BACKUP_FILE" + info "File size: $file_size" + info "File lines: $file_lines" + + log "Backup file check passed" } -# 拷贝备份文件到Pod +# Copy backup file to Pod copy_backup_to_pod() { - step "拷贝备份文件到Pod" - info "从本地拷贝到Pod: $BACKUP_FILE -> $POD_NAME:$POD_BACKUP_PATH" - + step "Copying backup file to Pod" + info "Copying from local to Pod: $BACKUP_FILE -> $POD_NAME:$POD_BACKUP_PATH" + kubectl cp "$BACKUP_FILE" "$POD_NAME:$POD_BACKUP_PATH" -n $NAMESPACE - + if [ $? -eq 0 ]; then - log "备份文件拷贝完成" + log "Backup file copy completed" else - error "文件拷贝失败" + error "File copy failed" fi } -# 验证数据库连接 +# Verify database connection test_database_connection() { - step "测试数据库连接" - info "测试用户 $DB_USER 连接到数据库 $DB_NAME" - + step "Testing database connection" + info "Testing user $DB_USER connection to database $DB_NAME" + kubectl exec $POD_NAME -n $NAMESPACE -- bash -c " mysql -u$DB_USER -p'$MYSQL_PASSWORD' -e 'SELECT 1;' $DB_NAME 2>/dev/null " >/dev/null 2>&1 - + if [ $? -eq 0 ]; then - log "数据库连接测试成功" + log "Database connection test successful" else - error "数据库连接失败,请检查密码和网络连接" + error "Database connection failed, please check password and network connection" fi } -# 执行数据库恢复 +# Execute database recovery restore_database() { - step "执行数据库恢复" - warning "此操作将覆盖现有数据库数据!" - - info "开始恢复数据库..." + step "Executing database recovery" + warning "This operation will overwrite existing database data!" + + info "Starting database recovery..." kubectl exec $POD_NAME -n $NAMESPACE -- bash -c " mysql -u$DB_USER -p'$MYSQL_PASSWORD' $DB_NAME < $POD_BACKUP_PATH " - + local restore_status=$? - + if [ $restore_status -eq 0 ]; then - log "数据库恢复成功" + log "Database recovery successful" else - error "数据库恢复失败,退出码: $restore_status" + error "Database recovery failed, exit code: $restore_status" fi } -# 验证恢复结果 +# Verify recovery result verify_restore() { - step "验证恢复结果" - info "检查数据库表信息..." - + step "Verifying recovery result" + info "Checking database table information..." + local table_count=$(kubectl exec $POD_NAME -n $NAMESPACE -- bash -c " mysql -u$DB_USER -p'$MYSQL_PASSWORD' -N -e \\ \"SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '$DB_NAME';\" 2>/dev/null " 2>/dev/null) - + if [ -n "$table_count" ] && [ "$table_count" -gt 0 ]; then - log "恢复验证成功,数据库包含 $table_count 张表" - - # 显示部分表名 - info "数据库表列表:" + log "Recovery verification successful, database contains $table_count tables" + + # Display some table names + info "Database table list:" kubectl exec $POD_NAME -n $NAMESPACE -- bash -c " mysql -u$DB_USER -p'$MYSQL_PASSWORD' -e \\ \"SELECT table_name FROM information_schema.tables WHERE table_schema = '$DB_NAME' LIMIT 10;\" 2>/dev/null " 2>/dev/null else - warning "无法获取表信息,但恢复操作已完成" + warning "Unable to get table information, but recovery operation completed" fi } -# 清理临时文件 +# Clean up temporary files cleanup() { - step "清理临时文件" - info "删除Pod内的备份文件: $POD_BACKUP_PATH" - + step "Cleaning up temporary files" + info "Deleting backup file in Pod: $POD_BACKUP_PATH" + kubectl exec $POD_NAME -n $NAMESPACE -- rm -f "$POD_BACKUP_PATH" 2>/dev/null || true - - log "清理完成" + + log "Cleanup completed" } -# 显示使用说明 +# Show usage instructions usage() { show_banner - print_color "${YELLOW}" "用法: $0" + print_color "${YELLOW}" "Usage: $0" echo - print_color "${CYAN}" "说明: 该脚本用于恢复Euler Copilot项目的MySQL数据库" + print_color "${CYAN}" "Description: This script is used to recover MySQL database for Euler Copilot project" echo - print_color "${CYAN}" "前提条件:" - print_color "${WHITE}" " 1. kubectl已配置并可访问集群" - print_color "${WHITE}" " 2. mysql.sql文件存在于当前目录" - print_color "${WHITE}" " 3. 具有足够的集群权限" + print_color "${CYAN}" "Prerequisites:" + print_color "${WHITE}" " 1. kubectl configured and able to access cluster" + print_color "${WHITE}" " 2. mysql.sql file exists in current directory" + print_color "${WHITE}" " 3. Has sufficient cluster permissions" echo - print_color "${RED}" "警告: 此操作将覆盖现有数据库数据!" + print_color "${RED}" "Warning: This operation will overwrite existing database data!" echo } -# 确认操作 +# Confirm operation confirm_operation() { - print_color "${YELLOW}" "警告: 此操作将清空现有数据库数据并导入新数据!" + print_color "${YELLOW}" "Warning: This operation will clear existing database data and import new data!" echo - read -p "$(print_color "${YELLOW}" "确认执行数据库恢复操作?(y/N): ")" confirm + read -p "$(print_color "${YELLOW}" "Confirm execution of database recovery operation? (y/N): ")" confirm case $confirm in [yY] | [yY][eE][sS]) return 0 ;; *) - warning "操作已取消" + warning "Operation cancelled" exit 0 ;; esac } -# 主函数 +# Main function main() { show_banner - step "开始MySQL数据库恢复流程" - + step "Starting MySQL database recovery process" + check_dependencies get_mysql_pod get_mysql_password @@ -239,21 +239,21 @@ main() { restore_database verify_restore cleanup - + echo print_color "${GREEN}" "================================================" - print_color "${GREEN}" " Mysql数据恢复已完成!" + print_color "${GREEN}" " MySQL Data Recovery Completed!" print_color "${GREEN}" "================================================" echo - print_color "${GREEN}" "✓ 备份文件检查完成" - print_color "${GREEN}" "✓ 数据库连接测试通过" - print_color "${GREEN}" "✓ 数据恢复执行成功" - print_color "${GREEN}" "✓ 临时文件清理完成" + print_color "${GREEN}" "✓ Backup file check completed" + print_color "${GREEN}" "✓ Database connection test passed" + print_color "${GREEN}" "✓ Data recovery executed successfully" + print_color "${GREEN}" "✓ Temporary files cleanup completed" echo - print_color "${BLUE}" "提示: 建议检查应用运行状态以确保数据恢复成功。" + print_color "${BLUE}" "Tip: It is recommended to check application running status to ensure data recovery success." } -# 脚本入口 +# Script entry point if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then usage exit 0 diff --git a/deploy/scripts/9-other-script/migrate_opengauss_database.sh b/deploy/scripts/9-other-script/migrate_opengauss_database.sh index bf80d987a..e535bbea9 100644 --- a/deploy/scripts/9-other-script/migrate_opengauss_database.sh +++ b/deploy/scripts/9-other-script/migrate_opengauss_database.sh @@ -1,11 +1,11 @@ #!/bin/bash -# OpenGauss数据库导入脚本 -# 描述:用于Euler Copilot项目的数据库数据导入 +# OpenGauss Database Import Script +# Description: Used for Euler Copilot project database data import -set -e # 遇到错误立即退出 +set -e # Exit immediately on error -# 颜色定义 +# Color definitions RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' @@ -14,7 +14,7 @@ PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color -# 打印函数 +# Print functions log() { echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}" } @@ -24,11 +24,11 @@ info() { } warning() { - echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] 警告: $1${NC}" + echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] Warning: $1${NC}" } error() { - echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] 错误: $1${NC}" >&2 + echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] Error: $1${NC}" >&2 exit 1 } @@ -36,115 +36,115 @@ step() { echo -e "${PURPLE}[$(date '+%Y-%m-%d %H:%M:%S')] === $1 ===${NC}" } -# 配置变量 +# Configuration variables NAMESPACE="euler-copilot" SECRET_NAME="euler-copilot-database" PASSWORD_KEY="gauss-password" BACKUP_FILE="/home/dump/opengauss/opengauss.sql" POD_BACKUP_PATH="/home/omm/opengauss.sql" -# 检查必要工具 +# Check required tools check_dependencies() { - step "检查必要工具" - command -v kubectl >/dev/null 2>&1 || error "kubectl 未安装" - command -v base64 >/dev/null 2>&1 || error "base64 未安装" - log "依赖检查通过" + step "Checking required tools" + command -v kubectl >/dev/null 2>&1 || error "kubectl not installed" + command -v base64 >/dev/null 2>&1 || error "base64 not installed" + log "Dependency check passed" } -# 获取数据库密码 +# Get database password get_database_password() { - step "获取数据库密码" + step "Getting database password" PASSWORD=$(kubectl get secret $SECRET_NAME -n $NAMESPACE -o jsonpath="{.data.$PASSWORD_KEY}" 2>/dev/null | base64 --decode) - + if [ -z "$PASSWORD" ]; then - error "无法获取数据库密码,请检查secret是否存在" + error "Unable to get database password, please check if secret exists" fi - log "密码获取成功" + log "Password obtained successfully" } -# 获取OpenGauss Pod名称 +# Get OpenGauss Pod name get_opengauss_pod() { - step "查找OpenGauss Pod" + step "Finding OpenGauss Pod" POD_NAME=$(kubectl get pod -n $NAMESPACE 2>/dev/null | grep opengauss | grep Running | awk '{print $1}') - + if [ -z "$POD_NAME" ]; then - error "未找到运行的OpenGauss Pod" + error "No running OpenGauss Pod found" fi - log "找到Pod: $POD_NAME" + log "Found Pod: $POD_NAME" } -# 检查备份文件是否存在 +# Check if backup file exists check_backup_file() { - step "检查备份文件" + step "Checking backup file" if [ ! -f "$BACKUP_FILE" ]; then - error "备份文件 $BACKUP_FILE 不存在" + error "Backup file $BACKUP_FILE does not exist" fi - log "备份文件检查通过: $BACKUP_FILE" + log "Backup file check passed: $BACKUP_FILE" } -# 拷贝备份文件到Pod +# Copy backup file to Pod copy_backup_to_pod() { - step "拷贝备份文件到Pod" + step "Copying backup file to Pod" kubectl cp "$BACKUP_FILE" "$POD_NAME:$POD_BACKUP_PATH" -n $NAMESPACE kubectl exec -it "$POD_NAME" -n $NAMESPACE -- bash -c "chown omm:omm $POD_BACKUP_PATH" - log "备份文件拷贝完成" + log "Backup file copy completed" } -# 执行数据库导入 +# Execute database import import_database() { - step "执行数据库导入操作" - - info "步骤1: 禁用外键约束..." + step "Executing database import operation" + + info "Step 1: Disabling foreign key constraints..." kubectl exec -it "$POD_NAME" -n $NAMESPACE -- su - omm -s /bin/bash -c \ "gsql -d postgres -U postgres -W '$PASSWORD' -c \"SET session_replication_role = replica;\"" - log "外键约束已禁用" - - info "步骤2: 清空表数据..." + log "Foreign key constraints disabled" + + info "Step 2: Clearing table data..." kubectl exec -it "$POD_NAME" -n $NAMESPACE -- su - omm -s /bin/bash -c \ "gsql -d postgres -U postgres -W '$PASSWORD' -c \" -TRUNCATE TABLE - action, team, knowledge_base, document, chunk, document_type, +TRUNCATE TABLE + action, team, knowledge_base, document, chunk, document_type, role, role_action, users, task, task_report, team_user, user_role, - dataset, dataset_doc, image, qa, task_queue, team_message, + dataset, dataset_doc, image, qa, task_queue, team_message, testcase, testing, user_message CASCADE;\"" - log "表数据清空完成" - - info "步骤3: 导入数据..." + log "Table data cleared" + + info "Step 3: Importing data..." kubectl exec -it "$POD_NAME" -n $NAMESPACE -- su - omm -s /bin/bash -c \ "gsql -d postgres -U postgres -f $POD_BACKUP_PATH -W '$PASSWORD'" - log "数据导入完成" - - info "步骤4: 启用外键约束..." + log "Data import completed" + + info "Step 4: Enabling foreign key constraints..." kubectl exec -it "$POD_NAME" -n $NAMESPACE -- su - omm -s /bin/bash -c \ "gsql -d postgres -U postgres -W '$PASSWORD' -c \"SET session_replication_role = origin;\"" - log "外键约束已启用" - - log "数据库导入操作全部完成" + log "Foreign key constraints enabled" + + log "Database import operation fully completed" } -# 清理临时文件 +# Clean up temporary files cleanup() { - step "清理临时文件" + step "Cleaning up temporary files" kubectl exec -it "$POD_NAME" -n $NAMESPACE -- rm -f "$POD_BACKUP_PATH" 2>/dev/null || true - log "清理完成" + log "Cleanup completed" } -# 显示横幅 +# Show banner show_banner() { echo -e "${PURPLE}" echo "================================================================" - echo " OpenGauss 数据库导入脚本" - echo " Euler Copilot 项目专用" + echo " OpenGauss Database Import Script" + echo " Euler Copilot Project Specific" echo "================================================================" echo -e "${NC}" } -# 主函数 +# Main function main() { show_banner - step "开始OpenGauss数据库导入流程" - + step "Starting OpenGauss database import process" + check_dependencies get_database_password get_opengauss_pod @@ -152,51 +152,51 @@ main() { copy_backup_to_pod import_database cleanup - + echo -e "${GREEN}" echo "================================================================" - echo " OpenGauss数据导入已完成!" + echo " OpenGauss Data Import Completed!" echo "================================================================" echo -e "${NC}" - - echo -e "${GREEN}✓ 外键约束已禁用${NC}" - echo -e "${GREEN}✓ 表数据已清空${NC}" - echo -e "${GREEN}✓ 新数据已导入${NC}" - echo -e "${GREEN}✓ 外键约束已重新启用${NC}" + + echo -e "${GREEN}✓ Foreign key constraints disabled${NC}" + echo -e "${GREEN}✓ Table data cleared${NC}" + echo -e "${GREEN}✓ New data imported${NC}" + echo -e "${GREEN}✓ Foreign key constraints re-enabled${NC}" echo "" - echo -e "${BLUE}提示: 建议检查应用运行状态以确保数据导入成功。${NC}" + echo -e "${BLUE}Tip: It is recommended to check application running status to ensure data import success.${NC}" } -# 显示使用说明 +# Show usage instructions usage() { show_banner - echo -e "${YELLOW}用法: $0${NC}" + echo -e "${YELLOW}Usage: $0${NC}" echo "" - echo -e "说明: 该脚本用于导入Euler Copilot项目的OpenGauss数据库数据" + echo -e "Description: This script is used to import OpenGauss database data for Euler Copilot project" echo "" - echo -e "${CYAN}前提条件:${NC}" - echo -e " 1. kubectl已配置并可访问集群" - echo -e " 2. opengauss.sql文件存在于当前目录" - echo -e " 3. 具有足够的集群权限" + echo -e "${CYAN}Prerequisites:${NC}" + echo -e " 1. kubectl configured and able to access cluster" + echo -e " 2. opengauss.sql file exists in current directory" + echo -e " 3. Has sufficient cluster permissions" echo "" - echo -e "${RED}警告: 此操作将清空现有数据库数据并导入新数据!${NC}" + echo -e "${RED}Warning: This operation will clear existing database data and import new data!${NC}" } -# 脚本入口 +# Script entry point if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then usage exit 0 fi -# 修复颜色显示问题 -echo -e "${YELLOW}警告: 此操作将清空现有数据库数据并导入新数据!${NC}" +# Fix color display issue +echo -e "${YELLOW}Warning: This operation will clear existing database data and import new data!${NC}" -# 方法1:使用临时变量 -yellow_text="${YELLOW}确认执行数据库导入操作?(y/N): ${NC}" +# Method 1: Use temporary variable +yellow_text="${YELLOW}Confirm execution of database import operation? (y/N): ${NC}" read -p "$(echo -e "$yellow_text")" confirm -# 方法2:或者直接使用echo -e(备选方案) -# echo -e "${YELLOW}确认执行数据库导入操作?(y/N): ${NC}\c" +# Method 2: Or use echo -e directly (alternative) +# echo -e "${YELLOW}Confirm execution of database import operation? (y/N): ${NC}\c" # read confirm case $confirm in @@ -204,7 +204,7 @@ case $confirm in main ;; *) - warning "操作已取消" + warning "Operation cancelled" exit 0 ;; esac diff --git a/deploy/scripts/9-other-script/modify_eulercopilot_yaml.py b/deploy/scripts/9-other-script/modify_eulercopilot_yaml.py index 4f7ac2479..856f51070 100755 --- a/deploy/scripts/9-other-script/modify_eulercopilot_yaml.py +++ b/deploy/scripts/9-other-script/modify_eulercopilot_yaml.py @@ -2,32 +2,32 @@ import sys import argparse from typing import Union -# 版本标记和依赖检测 +# Version marker and dependency detection try: from ruamel.yaml import YAML from ruamel.yaml.comments import CommentedMap USING_RUAMEL = True except ImportError: try: - import yaml # PyYAML 回退 + import yaml # PyYAML fallback USING_RUAMEL = False except ImportError as e: - sys.stderr.write("错误:需要 YAML 处理库\n") - sys.stderr.write("请选择以下方式之一安装:\n") - sys.stderr.write("1. (推荐) ruamel.yaml: pip install ruamel.yaml\n") + sys.stderr.write("Error: YAML processing library required\n") + sys.stderr.write("Please install one of the following:\n") + sys.stderr.write("1. (Recommended) ruamel.yaml: pip install ruamel.yaml\n") sys.stderr.write("2. PyYAML: pip install PyYAML\n") sys.exit(1) def parse_value(value: str) -> Union[str, int, float, bool]: - """智能转换值的类型""" + """Intelligently convert value types""" value = value.strip() lower_val = value.lower() - + if lower_val in {'true', 'false'}: return lower_val == 'true' if lower_val in {'null', 'none'}: return None - + try: return int(value) except ValueError: @@ -35,78 +35,78 @@ def parse_value(value: str) -> Union[str, int, float, bool]: return float(value) except ValueError: pass - - # 处理引号包裹的字符串 + + # Handle quoted strings if len(value) > 1 and value[0] == value[-1] and value[0] in {'"', "'"}: return value[1:-1] - + return value def set_nested_value(data: dict, key_path: str, value: str) -> None: - """递归设置嵌套字典的值""" + """Recursively set nested dictionary values""" keys = key_path.split('.') current = data - + try: for key in keys[:-1]: - # 自动创建不存在的层级 + # Automatically create missing levels if key not in current: current[key] = CommentedMap() if USING_RUAMEL else {} current = current[key] - + final_key = keys[-1] current[final_key] = parse_value(value) except TypeError as e: - raise ValueError(f"路径 {key_path} 中存在非字典类型的中间节点") from e + raise ValueError(f"Non-dictionary type intermediate node found in path {key_path}") from e def main(): parser = argparse.ArgumentParser( - description='YAML 配置文件修改工具', + description='YAML configuration file modification tool', formatter_class=argparse.ArgumentDefaultsHelpFormatter ) - parser.add_argument('input', help='输入YAML文件路径') - parser.add_argument('output', help='输出YAML文件路径') - parser.add_argument('--set', + parser.add_argument('input', help='Input YAML file path') + parser.add_argument('output', help='Output YAML file path') + parser.add_argument('--set', action='append', required=True, - help='格式: path.to.key=value (可多次使用)', + help='Format: path.to.key=value (can be used multiple times)', metavar='KEY_PATH=VALUE') args = parser.parse_args() - # 初始化 YAML 处理器 + # Initialize YAML processor if USING_RUAMEL: yaml_processor = YAML() yaml_processor.preserve_quotes = True yaml_processor.indent(mapping=2, sequence=4, offset=2) else: - yaml_processor = yaml # 使用 PyYAML 模块 + yaml_processor = yaml # Use PyYAML module - # 读取文件(修正后的部分) + # Read file (corrected section) try: - with open(args.input, 'r') as f: # 确保这行正确闭合 + with open(args.input, 'r') as f: # Ensure this line is properly closed if USING_RUAMEL: data = yaml_processor.load(f) else: data = yaml.safe_load(f) except Exception as e: - raise SystemExit(f"读取文件失败: {str(e)}") + raise SystemExit(f"Failed to read file: {str(e)}") - # 处理修改参数 + # Process modification parameters for item in args.set: if '=' not in item: - raise ValueError(f"无效格式: {item},应使用 KEY_PATH=VALUE 格式") - + raise ValueError(f"Invalid format: {item}, should use KEY_PATH=VALUE format") + key_path, value = item.split('=', 1) if not key_path: - raise ValueError("键路径不能为空") - + raise ValueError("Key path cannot be empty") + try: set_nested_value(data, key_path, value) except Exception as e: - raise SystemExit(f"设置 {key_path} 时出错: {str(e)}") + raise SystemExit(f"Error setting {key_path}: {str(e)}") - # 写入文件 + # Write file try: with open(args.output, 'w') as f: if USING_RUAMEL: @@ -114,7 +114,7 @@ def main(): else: yaml.dump(data, f, default_flow_style=False, indent=2) except Exception as e: - raise SystemExit(f"写入文件失败: {str(e)}") + raise SystemExit(f"Failed to write file: {str(e)}") if __name__ == '__main__': main() diff --git a/deploy/scripts/9-other-script/prepare_docker.sh b/deploy/scripts/9-other-script/prepare_docker.sh index 2ae2e1181..4b429dc73 100755 --- a/deploy/scripts/9-other-script/prepare_docker.sh +++ b/deploy/scripts/9-other-script/prepare_docker.sh @@ -1,60 +1,60 @@ #!/bin/bash function stop_docker { - echo -e "[Info]检查是否已安装Docker"; - if ! [[ -x $(command -v docker) ]]; then - echo -e "[Info]未安装Docker"; - return 0; - fi + echo -e "[Info] Checking if Docker is installed"; + if ! [[ -x $(command -v docker) ]]; then + echo -e "[Info] Docker not installed"; + return 0; + fi - echo -e "\033[33m[Warning]即将停止Docker服务,确定继续吗?\033[0m"; + echo -e "\033[33m[Warning] About to stop Docker service, confirm to continue?\033[0m"; read -p "(Y/n): " choice; case $choice in [Yy]) systemctl stop docker if [[ $? -ne 0 ]]; then - echo -e "\033[31m[Error]停止Docker服务错误,中止运行\033[0m" + echo -e "\033[31m[Error] Failed to stop Docker service, aborting\033[0m" return 1 else - echo -e "\033[32m[Success]停止Docker服务成功\033[0m" + echo -e "\033[32m[Success] Docker service stopped successfully\033[0m" fi ;; [Nn]) - echo -e "\033[31m[Error]操作取消\033[0m" + echo -e "\033[31m[Error] Operation cancelled\033[0m" return 1 ;; *) - echo -e "\033[31m[Error]无效输入,操作取消\033[0m" + echo -e "\033[31m[Error] Invalid input, operation cancelled\033[0m" return 1 ;; esac - echo -e "\033[33m[Warning]即将尝试卸载旧版本Docker,确定继续吗?\033[0m"; - read -p "(Y/n): " choice2; + echo -e "\033[33m[Warning] About to attempt to uninstall old Docker version, confirm to continue?\033[0m"; + read -p "(Y/n): " choice2; case $choice2 in [Yy]) yum remove -y docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine if [[ $? -ne 0 ]]; then - echo -e "\033[31m[Error]Docker旧版本卸载失败\033[0m" + echo -e "\033[31m[Error] Failed to uninstall old Docker version\033[0m" return 1 else - echo -e "\033[32m[Success]Docker旧版本已卸载\033[0m" + echo -e "\033[32m[Success] Old Docker version uninstalled\033[0m" fi ;; [Nn]) - echo -e "\033[31m[Error]操作取消\033[0m" + echo -e "\033[31m[Error] Operation cancelled\033[0m" return 1 ;; *) - echo -e "\033[31m[Error]无效输入,操作取消\033[0m" + echo -e "\033[31m[Error] Invalid input, operation cancelled\033[0m" return 1 ;; esac - return 0; + return 0; } function setup_docker_repo { - echo -e "[Info]设置Docker RPM Repo"; + echo -e "[Info] Setting up Docker RPM Repo"; basearch=$(arch) cat > /etc/yum.repos.d/docker-ce.repo <<-EOF [docker-ce-stable] @@ -64,100 +64,100 @@ enabled=1 gpgcheck=1 gpgkey=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/gpg EOF - echo -e "[Info]更新yum软件包列表"; + echo -e "[Info] Updating yum package list"; yum makecache if [[ $? -ne 0 ]]; then - echo -e "\033[31m[Error]更新yum软件包列表失败\033[0m"; + echo -e "\033[31m[Error] Failed to update yum package list\033[0m"; return 1; else - echo -e "\033[32m[Success]yum软件包列表更新成功\033[0m"; + echo -e "\033[32m[Success] yum package list updated successfully\033[0m"; fi return 0; } function install_docker { - echo -e "[Info]安装Docker"; - yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; - if [[ $? -ne 0 ]]; then - echo -e "\033[31m[Error]安装Docker失败\033[0m"; - return 1; - else - echo -e "\033[32m[Success]安装Docker成功\033[0m"; - fi - systemctl enable docker; - - echo -e "[Info]设置DockerHub镜像"; - if ! [[ -d "/etc/docker" ]]; then - mkdir /etc/docker; - fi - - if [[ -f "/etc/docker/daemon.json" ]]; then - echo -e "\033[31m[Error]daemon.json已存在,请手动配置DockerHub镜像\033[0m"; - else - cat > /etc/docker/daemon.json <<-EOF + echo -e "[Info] Installing Docker"; + yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; + if [[ $? -ne 0 ]]; then + echo -e "\033[31m[Error] Failed to install Docker\033[0m"; + return 1; + else + echo -e "\033[32m[Success] Docker installed successfully\033[0m"; + fi + systemctl enable docker; + + echo -e "[Info] Setting up DockerHub mirror"; + if ! [[ -d "/etc/docker" ]]; then + mkdir /etc/docker; + fi + + if [[ -f "/etc/docker/daemon.json" ]]; then + echo -e "\033[31m[Error] daemon.json already exists, please manually configure DockerHub mirror\033[0m"; + else + cat > /etc/docker/daemon.json <<-EOF { - "registry-mirrors": [ - "https://docker.anyhub.us.kg", - "https://docker.1panel.live", - "https://dockerhub.icu", - "https://docker.ckyl.me", - "https://docker.awsl9527.cn", - "https://dhub.kubesre.xyz", + "registry-mirrors": [ + "https://docker.anyhub.us.kg", + "https://docker.1panel.live", + "https://dockerhub.icu", + "https://docker.ckyl.me", + "https://docker.awsl9527.cn", + "https://dhub.kubesre.xyz", "https://gg3gwnry.mirror.aliyuncs.com" - ] + ] } EOF - fi - systemctl restart docker; - if [[ $? -ne 0 ]]; then - echo -e "\033[31m[Error]Docker启动失败\033[0m"; - return 1; - else - echo -e "\033[32m[Success]Docker启动成功\033[0m"; - return 0; - fi + fi + systemctl restart docker; + if [[ $? -ne 0 ]]; then + echo -e "\033[31m[Error] Docker startup failed\033[0m"; + return 1; + else + echo -e "\033[32m[Success] Docker started successfully\033[0m"; + return 0; + fi } function login_docker { - echo -e "[Info]登录Docker私仓"; - read -p "仓库地址:" url; - read -p "用户名:" username; - read -p "密码:" password; - - docker login -u $username -p $password $url; - if [[ $? -ne 0 ]]; then - echo -e "\033[31m[Error]Docker登录失败\033[0m"; - return 1; - else - echo -e "\033[32m[Success]Docker登录成功\033[0m"; - return 0; - fi + echo -e "[Info] Logging into Docker private registry"; + read -p "Registry URL: " url; + read -p "Username: " username; + read -p "Password: " password; + + docker login -u $username -p $password $url; + if [[ $? -ne 0 ]]; then + echo -e "\033[31m[Error] Docker login failed\033[0m"; + return 1; + else + echo -e "\033[32m[Success] Docker login successful\033[0m"; + return 0; + fi } function main { - echo -e "[Info]正在更新Docker"; - - stop_docker; - if [[ $? -ne 0 ]]; then - return 1; - fi - - setup_docker_repo; - if [[ $? -ne 0 ]]; then - return 1; - fi - - install_docker; - if [[ $? -ne 0 ]]; then - return 1; - fi - - login_docker; - if [[ $? -ne 0 ]]; then - return 1; - fi - - return 0; + echo -e "[Info] Updating Docker"; + + stop_docker; + if [[ $? -ne 0 ]]; then + return 1; + fi + + setup_docker_repo; + if [[ $? -ne 0 ]]; then + return 1; + fi + + install_docker; + if [[ $? -ne 0 ]]; then + return 1; + fi + + login_docker; + if [[ $? -ne 0 ]]; then + return 1; + fi + + return 0; } main diff --git a/deploy/scripts/9-other-script/save_images.sh b/deploy/scripts/9-other-script/save_images.sh index 489560bd6..000e0b58b 100755 --- a/deploy/scripts/9-other-script/save_images.sh +++ b/deploy/scripts/9-other-script/save_images.sh @@ -1,34 +1,34 @@ #!/bin/bash -# 颜色定义 +# Color definitions RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' -NC='\033[0m' # 恢复默认颜色 +NC='\033[0m' # Reset color -# 默认配置 +# Default configuration eulercopilot_version="0.10.0" ARCH_SUFFIX="" OUTPUT_DIR="/home/eulercopilot/images/${eulercopilot_version}" -# 显示帮助信息 +# Show help information show_help() { - echo -e "${YELLOW}使用说明:${NC}" - echo -e " $0 [选项]" + echo -e "${YELLOW}Usage:${NC}" + echo -e " $0 [options]" echo -e "" - echo -e "${YELLOW}选项:${NC}" - echo -e " --help 显示此帮助信息" - echo -e " --version <版本> 指定 EulerCopilot 版本 (默认: ${eulercopilot_version})" - echo -e " --arch <架构> 指定系统架构 (arm/x86, 默认自动检测)" + echo -e "${YELLOW}Options:${NC}" + echo -e " --help Show this help message" + echo -e " --version Specify EulerCopilot version (default: ${eulercopilot_version})" + echo -e " --arch Specify system architecture (arm/x86, default: auto-detect)" echo -e "" - echo -e "${YELLOW}示例:${NC}" + echo -e "${YELLOW}Examples:${NC}" echo -e " $0 --version ${eulercopilot_version} --arch arm" echo -e " $0 --help" exit 0 } -# 解析命令行参数 +# Parse command line arguments while [[ $# -gt 0 ]]; do case "$1" in --help) @@ -40,7 +40,7 @@ while [[ $# -gt 0 ]]; do OUTPUT_DIR="/home/eulercopilot/images/${eulercopilot_version}" shift else - echo -e "${RED}错误: --version 需要指定一个版本号${NC}" + echo -e "${RED}Error: --version requires a version number${NC}" exit 1 fi ;; @@ -51,25 +51,25 @@ while [[ $# -gt 0 ]]; do ARCH_SUFFIX="$2" ;; *) - echo -e "${RED}错误: 不支持的架构 '$2',必须是 arm 或 x86${NC}" + echo -e "${RED}Error: Unsupported architecture '$2', must be arm or x86${NC}" exit 1 ;; esac shift else - echo -e "${RED}错误: --arch 需要指定一个架构 (arm/x86)${NC}" + echo -e "${RED}Error: --arch requires an architecture (arm/x86)${NC}" exit 1 fi ;; *) - echo -e "${RED}未知参数: $1${NC}" + echo -e "${RED}Unknown parameter: $1${NC}" show_help ;; esac shift done -# 自动检测架构(如果未通过参数指定) +# Auto-detect architecture (if not specified via parameter) if [ -z "$ARCH_SUFFIX" ]; then ARCH=$(uname -m) case $ARCH in @@ -80,7 +80,7 @@ if [ -z "$ARCH_SUFFIX" ]; then ARCH_SUFFIX="arm" ;; *) - echo -e "${RED}不支持的架构: $ARCH${NC}" + echo -e "${RED}Unsupported architecture: $ARCH${NC}" exit 1 ;; esac @@ -88,7 +88,7 @@ fi mkdir -p "$OUTPUT_DIR" -# 镜像列表(使用版本变量) +# Image list (using version variable) BASE_IMAGES=( "hub.oepkgs.net/neocopilot/euler-copilot-framework:${eulercopilot_version}-arm" "hub.oepkgs.net/neocopilot/euler-copilot-web:${eulercopilot_version}-arm" @@ -104,7 +104,7 @@ BASE_IMAGES=( "hub.oepkgs.net/neocopilot/secret_inject:dev-arm" ) -# 预定义文件名列表(与BASE_IMAGES顺序严格对应) +# Predefined filename list (strictly corresponding to BASE_IMAGES order) FILE_NAMES=( "euler-copilot-framework.tar" "euler-copilot-web.tar" @@ -120,53 +120,53 @@ FILE_NAMES=( "secret_inject.tar" ) -# 校验列表一致性 +# Validate list consistency if [ ${#BASE_IMAGES[@]} -ne ${#FILE_NAMES[@]} ]; then - echo -e "${RED}错误:镜像列表与文件名列表数量不匹配${NC}" + echo -e "${RED}Error: Image list and filename list count mismatch${NC}" exit 1 fi -# 初始化计数器 +# Initialize counters total=${#BASE_IMAGES[@]} success=0 fail=0 -# 镜像处理函数 +# Image processing function process_image() { local raw_image=$1 local filename=$2 - # 调整架构标签 + # Adjust architecture tag local adjusted_image="${raw_image/-arm/-${ARCH_SUFFIX}}" local output_path="${OUTPUT_DIR}/${filename}" - echo -e "\n${BLUE}正在处理:${adjusted_image}${NC}" + echo -e "\n${BLUE}Processing: ${adjusted_image}${NC}" - # 拉取镜像 + # Pull image if ! docker pull "$adjusted_image"; then - echo -e "${RED}拉取失败:${adjusted_image}${NC}" + echo -e "${RED}Pull failed: ${adjusted_image}${NC}" return 1 fi - # 保存镜像 + # Save image if docker save -o "$output_path" "$adjusted_image"; then - echo -e "${GREEN}镜像已保存到:${output_path}${NC}" + echo -e "${GREEN}Image saved to: ${output_path}${NC}" return 0 else - echo -e "${RED}保存失败:${output_path}${NC}" + echo -e "${RED}Save failed: ${output_path}${NC}" return 1 fi } -# 打印执行信息 +# Print execution information echo -e "${BLUE}==============================${NC}" -echo -e "${YELLOW}架构\t: ${ARCH_SUFFIX}${NC}" -echo -e "${YELLOW}版本\t: ${eulercopilot_version}${NC}" -echo -e "${YELLOW}存储目录\t: ${OUTPUT_DIR}${NC}" -echo -e "${YELLOW}镜像数量\t: ${total}${NC}" +echo -e "${YELLOW}Architecture\t: ${ARCH_SUFFIX}${NC}" +echo -e "${YELLOW}Version\t\t: ${eulercopilot_version}${NC}" +echo -e "${YELLOW}Storage directory\t: ${OUTPUT_DIR}${NC}" +echo -e "${YELLOW}Image count\t: ${total}${NC}" echo -e "${BLUE}==============================${NC}" -# 遍历处理所有镜像 +# Process all images for index in "${!BASE_IMAGES[@]}"; do if process_image "${BASE_IMAGES[$index]}" "${FILE_NAMES[$index]}"; then ((success++)) @@ -175,13 +175,13 @@ for index in "${!BASE_IMAGES[@]}"; do fi done -# 输出最终结果 +# Output final result echo -e "\n${BLUE}==============================${NC}" -echo -e "${GREEN}操作完成!${NC}" +echo -e "${GREEN}Operation completed!${NC}" echo -e "${BLUE}==============================${NC}" -echo -e "${GREEN}成功\t: ${success} 个${NC}" -echo -e "${RED}失败\t: ${fail} 个${NC}" +echo -e "${GREEN}Success\t: ${success}${NC}" +echo -e "${RED}Failed\t: ${fail}${NC}" echo -e "${BLUE}==============================${NC}" -# 返回状态码 +# Return status code exit $((fail > 0 ? 1 : 0)) diff --git a/deploy/scripts/deploy.sh b/deploy/scripts/deploy.sh index 1b4d69cee..e62b59cd6 100755 --- a/deploy/scripts/deploy.sh +++ b/deploy/scripts/deploy.sh @@ -1,126 +1,297 @@ #!/bin/bash +# 语言设置 +LANGUAGE="zh" +COLOR_RED='\033[31m' +COLOR_GREEN='\033[32m' +COLOR_YELLOW='\033[33m' +COLOR_BLUE='\033[34m' +COLOR_NC='\033[0m' -# 顶层菜单 -show_top_menu() { +# 语言选择函数 +select_language() { clear echo "==============================" - echo " 主部署菜单 " + echo " Language Selection / 语言选择" echo "==============================" - echo "0) 一键自动部署" - echo "1) 手动分步部署" - echo "2) 重启服务" - echo "3) 卸载所有组件并清除数据" - echo "4) 退出程序" + echo "1) English (en)" + echo "2) 中文 (zh)" echo "==============================" - echo -n "请输入选项编号(0-3): " + echo -n "请选择语言 / Please select language (1/2): " + read -r lang_choice + + case $lang_choice in + 1) LANGUAGE="en" ;; + 2) LANGUAGE="zh" ;; + *) + echo "无效选择,默认使用中文 / Invalid selection, using Chinese by default" + LANGUAGE="zh" + sleep 1 + ;; + esac +} + +# 获取对应语言的脚本路径 +get_localized_script() { + local base_script="$1" + local script_dir=$(dirname "$base_script") + local script_name=$(basename "$base_script") + local name_without_ext="${script_name%.*}" + local ext="${script_name##*.}" + + # 构建本地化脚本路径 + local localized_script="${script_dir}/${name_without_ext}_${LANGUAGE}.${ext}" + + # 如果本地化脚本存在,则返回本地化脚本路径,否则返回原脚本路径 + if [[ -f "$localized_script" ]]; then + echo "$localized_script" + else + echo "$base_script" + fi +} + +# 文本翻译函数 +t() { + local zh_text="$1" + local en_text="$2" + + if [[ "$LANGUAGE" == "zh" ]]; then + echo "$zh_text" + else + echo "$en_text" + fi +} + +# 顶层菜单 +show_top_menu() { + clear + if [[ "$LANGUAGE" == "zh" ]]; then + echo "==============================" + echo " 主部署菜单 " + echo "==============================" + echo "0) 一键自动部署" + echo "1) 手动分步部署" + echo "2) 重启服务" + echo "3) 卸载所有组件并清除数据" + echo "4) 退出程序" + echo "==============================" + echo -n "请输入选项编号(0-4): " + else + echo "==============================" + echo " Main Deployment Menu " + echo "==============================" + echo "0) One-click Auto Deployment" + echo "1) Manual Step-by-step Deployment" + echo "2) Restart Services" + echo "3) Uninstall All Components and Clear Data" + echo "4) Exit" + echo "==============================" + echo -n "Please enter option number (0-4): " + fi } # 安装选项菜单(手动部署子菜单) show_sub_menu() { clear - echo "==============================" - echo " 手动分步部署菜单 " - echo "==============================" - echo "1) 执行环境检查脚本" - echo "2) 安装k3s和helm" - echo "3) 安装Ollama" - echo "4) 部署Deepseek模型" - echo "5) 部署Embedding模型" - echo "6) 安装数据库" - echo "7) 安装AuthHub" - echo "8) 安装EulerCopilot" - echo "9) 返回主菜单" - echo "==============================" - echo -n "请输入选项编号(0-9): " + if [[ "$LANGUAGE" == "zh" ]]; then + echo "==============================" + echo " 手动分步部署菜单 " + echo "==============================" + echo "1) 执行环境检查脚本" + echo "2) 安装k3s和helm" + echo "3) 安装Ollama" + echo "4) 部署Deepseek模型" + echo "5) 部署Embedding模型" + echo "6) 安装数据库" + echo "7) 安装AuthHub" + echo "8) 安装EulerCopilot" + echo "9) 返回主菜单" + echo "==============================" + echo -n "请输入选项编号(1-9): " + else + echo "==============================" + echo " Manual Deployment Menu " + echo "==============================" + echo "1) Execute Environment Check Script" + echo "2) Install k3s and helm" + echo "3) Install Ollama" + echo "4) Deploy Deepseek Model" + echo "5) Deploy Embedding Model" + echo "6) Install Databases" + echo "7) Install AuthHub" + echo "8) Install EulerCopilot" + echo "9) Return to Main Menu" + echo "==============================" + echo -n "Please enter option number (1-9): " + fi } show_restart_menu() { clear - echo "==============================" - echo " 服务重启菜单 " - echo "==============================" - echo "可重启的服务列表:" - echo "1) authhub-backend" - echo "2) authhub" - echo "3) framework" - echo "4) minio" - echo "5) mongo" - echo "6) mysql" - echo "7) opengauss" - echo "8) rag" - echo "9) rag-web" - echo "10) redis" - echo "11) web" - echo "12) 返回主菜单" - echo "==============================" - echo -n "请输入要重启的服务编号(1-12): " + if [[ "$LANGUAGE" == "zh" ]]; then + echo "==============================" + echo " 服务重启菜单 " + echo "==============================" + echo "可重启的服务列表:" + echo "1) authhub-backend" + echo "2) authhub" + echo "3) framework" + echo "4) minio" + echo "5) mongo" + echo "6) mysql" + echo "7) opengauss" + echo "8) rag" + echo "9) rag-web" + echo "10) redis" + echo "11) web" + echo "12) 返回主菜单" + echo "==============================" + echo -n "请输入要重启的服务编号(1-12): " + else + echo "==============================" + echo " Service Restart Menu " + echo "==============================" + echo "Available services to restart:" + echo "1) authhub-backend" + echo "2) authhub" + echo "3) framework" + echo "4) minio" + echo "5) mongo" + echo "6) mysql" + echo "7) opengauss" + echo "8) rag" + echo "9) rag-web" + echo "10) redis" + echo "11) web" + echo "12) Return to Main Menu" + echo "==============================" + echo -n "Please enter service number to restart (1-12): " + fi } - # 带错误检查的脚本执行函数 run_script_with_check() { local script_path=$1 local script_name=$2 - + + # 获取对应语言的脚本路径 + local localized_script=$(get_localized_script "$script_path") + echo "--------------------------------------------------" - echo "开始执行:$script_name" - "$script_path" || { - echo -e "\n\033[31m$script_name 执行失败!\033[0m" - exit 1 + if [[ "$LANGUAGE" == "zh" ]]; then + echo "开始执行:$script_name" + echo "脚本路径:$localized_script" + else + echo "Starting: $script_name" + echo "Script path: $localized_script" + fi + + # 检查脚本是否存在 + if [[ ! -f "$localized_script" ]]; then + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "\n${COLOR_RED}错误:脚本文件不存在: $localized_script${COLOR_NC}" + else + echo -e "\n${COLOR_RED}Error: Script file not found: $localized_script${COLOR_NC}" + fi + return 1 + fi + + # 执行脚本 + "$localized_script" || { + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "\n${COLOR_RED}$script_name 执行失败!${COLOR_NC}" + else + echo -e "\n${COLOR_RED}$script_name execution failed!${COLOR_NC}" + fi + return 1 } - echo -e "\n\033[32m$script_name 执行成功!\033[0m" + + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "\n${COLOR_GREEN}$script_name 执行成功!${COLOR_NC}" + else + echo -e "\n${COLOR_GREEN}$script_name executed successfully!${COLOR_NC}" + fi echo "--------------------------------------------------" } # 执行子菜单对应脚本 run_sub_script() { + local base_script_path="" + local script_description="" + case $1 in 1) - run_script_with_check "./1-check-env/check_env.sh" "环境检查脚本" + base_script_path="./1-check-env/check_env.sh" + script_description=$(t "环境检查脚本" "Environment Check Script") ;; 2) - run_script_with_check "./2-install-tools/install_tools.sh" "k3s和helm安装脚本" + base_script_path="./2-install-tools/install_tools.sh" + script_description=$(t "k3s和helm安装脚本" "k3s and helm Installation Script") ;; 3) - run_script_with_check "./3-install-ollama/install_ollama.sh" "Ollama安装脚本" + base_script_path="./3-install-ollama/install_ollama.sh" + script_description=$(t "Ollama安装脚本" "Ollama Installation Script") ;; 4) - run_script_with_check "./4-deploy-deepseek/deploy_deepseek.sh" "Deepseek部署脚本" + base_script_path="./4-deploy-deepseek/deploy_deepseek.sh" + script_description=$(t "Deepseek部署脚本" "Deepseek Deployment Script") ;; 5) - run_script_with_check "./5-deploy-embedding/deploy-embedding.sh" "Embedding部署脚本" + base_script_path="./5-deploy-embedding/deploy-embedding.sh" + script_description=$(t "Embedding部署脚本" "Embedding Deployment Script") ;; 6) - run_script_with_check "./6-install-databases/install_databases.sh" "数据库安装脚本" + base_script_path="./6-install-databases/install_databases.sh" + script_description=$(t "数据库安装脚本" "Database Installation Script") ;; 7) - run_script_with_check "./7-install-authhub/install_authhub.sh" "AuthHub安装脚本" + base_script_path="./7-install-authhub/install_authhub.sh" + script_description=$(t "AuthHub安装脚本" "AuthHub Installation Script") ;; 8) - run_script_with_check "./8-install-EulerCopilot/install_eulercopilot.sh" "EulerCopilot安装脚本" + base_script_path="./8-install-EulerCopilot/install_eulercopilot.sh" + script_description=$(t "EulerCopilot安装脚本" "EulerCopilot Installation Script") ;; 9) - echo "正在返回主菜单..." - echo "按任意键继续..." + if [[ "$LANGUAGE" == "zh" ]]; then + echo "正在返回主菜单..." + else + echo "Returning to main menu..." + fi + echo "$(t "按任意键继续..." "Press any key to continue...")" read -r -n 1 -s return 2 # 特殊返回码表示返回上级菜单 ;; *) - echo -e "\033[31m无效的选项,请输入0-9之间的数字\033[0m" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}无效的选项,请输入1-9之间的数字${COLOR_NC}" + else + echo -e "${COLOR_RED}Invalid option, please enter a number between 1-9${COLOR_NC}" + fi return 1 ;; esac - return 0 + + run_script_with_check "$base_script_path" "$script_description" + return $? } # 卸载所有组件 uninstall_all() { - echo -e "\033[31m警告:此操作将永久删除所有组件和数据!\033[0m" - read -p "确认要继续吗?(y/n) " confirm + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}警告:此操作将永久删除所有组件和数据!${COLOR_NC}" + read -p "确认要继续吗?(y/n) " confirm + else + echo -e "${COLOR_RED}Warning: This operation will permanently delete all components and data!${COLOR_NC}" + read -p "Are you sure you want to continue? (y/n) " confirm + fi if [[ $confirm != "y" && $confirm != "Y" ]]; then - echo "取消卸载操作" + if [[ "$LANGUAGE" == "zh" ]]; then + echo "取消卸载操作" + else + echo "Uninstall operation cancelled" + fi return fi @@ -129,20 +300,36 @@ uninstall_all() { local PVC_DELETE_TIMEOUT=120 local FORCE_DELETE=false - echo "开始卸载所有Helm Release..." + if [[ "$LANGUAGE" == "zh" ]]; then + echo "开始卸载所有Helm Release..." + else + echo "Starting to uninstall all Helm Releases..." + fi local RELEASES RELEASES=$(helm list -n euler-copilot --short) # 删除所有关联的Helm Release if [ -n "$RELEASES" ]; then - echo -e "${YELLOW}找到以下Helm Release,开始清理...${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_YELLOW}找到以下Helm Release,开始清理...${COLOR_NC}" + else + echo -e "${COLOR_YELLOW}Found the following Helm Releases, starting cleanup...${COLOR_NC}" + fi for release in $RELEASES; do - echo -e "${BLUE}正在删除Helm Release: ${release}${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_BLUE}正在删除Helm Release: ${release}${COLOR_NC}" + else + echo -e "${COLOR_BLUE}Deleting Helm Release: ${release}${COLOR_NC}" + fi if ! helm uninstall "$release" -n euler-copilot \ --wait \ --timeout ${HELM_TIMEOUT}s \ --no-hooks; then - echo -e "${RED}警告:Helm Release ${release} 删除异常,尝试强制删除...${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}警告:Helm Release ${release} 删除异常,尝试强制删除...${COLOR_NC}" + else + echo -e "${COLOR_RED}Warning: Helm Release ${release} deletion abnormal, attempting forced deletion...${COLOR_NC}" + fi FORCE_DELETE=true helm uninstall "$release" -n euler-copilot \ --timeout 10s \ @@ -151,7 +338,11 @@ uninstall_all() { fi done else - echo -e "${YELLOW}未找到需要清理的Helm Release${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_YELLOW}未找到需要清理的Helm Release${COLOR_NC}" + else + echo -e "${COLOR_YELLOW}No Helm Releases found to clean up${COLOR_NC}" + fi fi # 等待资源释放 @@ -163,7 +354,11 @@ uninstall_all() { # 删除PVC(带重试机制) if [ -n "$pvc_list" ]; then - echo -e "${YELLOW}找到以下PVC,开始清理...${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_YELLOW}找到以下PVC,开始清理...${COLOR_NC}" + else + echo -e "${COLOR_YELLOW}Found the following PVCs, starting cleanup...${COLOR_NC}" + fi local start_time=$(date +%s) local end_time=$((start_time + PVC_DELETE_TIMEOUT)) @@ -176,55 +371,92 @@ uninstall_all() { # 检查是否超时 if [ $(date +%s) -ge $end_time ]; then - echo -e "${RED}错误:PVC删除超时,尝试强制清理...${NC}" - + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}错误:PVC删除超时,尝试强制清理...${COLOR_NC}" + else + echo -e "${COLOR_RED}Error: PVC deletion timeout, attempting forced cleanup...${COLOR_NC}" + fi + # 移除Finalizer强制删除 kubectl patch $pvc -n euler-copilot \ --type json \ --patch='[ { "op": "remove", "path": "/metadata/finalizers" } ]' 2>/dev/null || true - + # 强制删除 kubectl delete $pvc -n euler-copilot \ --force \ --grace-period=0 2>/dev/null && break || true - + # 最终确认 if ! kubectl get $pvc -n euler-copilot &>/dev/null; then break fi - echo -e "${RED}严重错误:无法删除PVC ${pvc}${NC}" >&2 + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}严重错误:无法删除PVC ${pvc}${COLOR_NC}" >&2 + else + echo -e "${COLOR_RED}Critical error: Unable to delete PVC ${pvc}${COLOR_NC}" >&2 + fi return 1 fi # 等待后重试 sleep 5 - echo -e "${YELLOW}重试删除PVC: ${pvc}...${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_YELLOW}重试删除PVC: ${pvc}...${COLOR_NC}" + else + echo -e "${COLOR_YELLOW}Retrying deletion of PVC: ${pvc}...${COLOR_NC}" + fi done done else - echo -e "${YELLOW}未找到需要清理的PVC${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_YELLOW}未找到需要清理的PVC${COLOR_NC}" + else + echo -e "${COLOR_YELLOW}No PVCs found to clean up${COLOR_NC}" + fi fi # 删除指定的 Secrets local secret_list=("authhub-secret" "euler-copilot-database" "euler-copilot-system") for secret in "${secret_list[@]}"; do if kubectl get secret "$secret" -n euler-copilot &>/dev/null; then - echo -e "${YELLOW}找到Secret: ${secret},开始清理...${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_YELLOW}找到Secret: ${secret},开始清理...${COLOR_NC}" + else + echo -e "${COLOR_YELLOW}Found Secret: ${secret}, starting cleanup...${COLOR_NC}" + fi if ! kubectl delete secret "$secret" -n euler-copilot; then - echo -e "${RED}错误:删除Secret ${secret} 失败!${NC}" >&2 + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}错误:删除Secret ${secret} 失败!${COLOR_NC}" >&2 + else + echo -e "${COLOR_RED}Error: Failed to delete Secret ${secret}!${COLOR_NC}" >&2 + fi return 1 fi else - echo -e "${YELLOW}未找到需要清理的Secret: ${secret}${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_YELLOW}未找到需要清理的Secret: ${secret}${COLOR_NC}" + else + echo -e "${COLOR_YELLOW}No Secret found to clean up: ${secret}${COLOR_NC}" + fi fi done # 最终清理检查 - echo -e "${YELLOW}执行最终资源检查...${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_YELLOW}执行最终资源检查...${COLOR_NC}" + else + echo -e "${COLOR_YELLOW}Performing final resource check...${COLOR_NC}" + fi kubectl delete all --all -n euler-copilot --timeout=30s 2>/dev/null || true - echo -e "${GREEN}资源清理完成${NC}" - echo -e "\033[32m所有组件和数据已成功清除\033[0m" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_GREEN}资源清理完成${COLOR_NC}" + echo -e "${COLOR_GREEN}所有组件和数据已成功清除${COLOR_NC}" + else + echo -e "${COLOR_GREEN}Resource cleanup completed${COLOR_NC}" + echo -e "${COLOR_GREEN}All components and data have been successfully cleared${COLOR_NC}" + fi } # 手动部署子菜单循环 @@ -238,7 +470,7 @@ manual_deployment_loop() { if [ $retval -eq 2 ]; then # 返回主菜单 break elif [ $retval -eq 0 ]; then - echo "按任意键继续..." + echo "$(t "按任意键继续..." "Press any key to continue...")" read -r -n 1 -s fi done @@ -247,28 +479,56 @@ manual_deployment_loop() { restart_pod() { local service="$1" if [[ -z "$service" ]]; then - echo -e "${RED}错误:请输入服务名称${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}错误:请输入服务名称${COLOR_NC}" + else + echo -e "${COLOR_RED}Error: Please enter service name${COLOR_NC}" + fi return 1 fi local deployment="${service}-deploy" - echo -e "${BLUE}正在验证部署是否存在...${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_BLUE}正在验证部署是否存在...${COLOR_NC}" + else + echo -e "${COLOR_BLUE}Verifying if deployment exists...${COLOR_NC}" + fi if ! kubectl get deployment "$deployment" -n euler-copilot &> /dev/null; then - echo -e "${RED}错误:在 euler-copilot 命名空间中找不到部署 $deployment${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}错误:在 euler-copilot 命名空间中找不到部署 $deployment${COLOR_NC}" + else + echo -e "${COLOR_RED}Error: Deployment $deployment not found in euler-copilot namespace${COLOR_NC}" + fi return 1 fi - echo -e "${YELLOW}正在重启部署 $deployment ...${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_YELLOW}正在重启部署 $deployment ...${COLOR_NC}" + else + echo -e "${COLOR_YELLOW}Restarting deployment $deployment ...${COLOR_NC}" + fi if kubectl rollout restart deployment/"$deployment" -n euler-copilot; then - echo -e "${GREEN}成功触发滚动重启!${NC}" - echo -e "可以使用以下命令查看状态:\nkubectl rollout status deployment/$deployment -n euler-copilot" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_GREEN}成功触发滚动重启!${COLOR_NC}" + echo -e "可以使用以下命令查看状态:\nkubectl rollout status deployment/$deployment -n euler-copilot" + else + echo -e "${COLOR_GREEN}Successfully triggered rolling restart!${COLOR_NC}" + echo -e "You can check the status with:\nkubectl rollout status deployment/$deployment -n euler-copilot" + fi return 0 else - echo -e "${RED}重启部署 $deployment 失败!${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}重启部署 $deployment 失败!${COLOR_NC}" + else + echo -e "${COLOR_RED}Failed to restart deployment $deployment!${COLOR_NC}" + fi return 1 fi } +# 主程序 +select_language + # 主程序循环改进 while true; do show_top_menu @@ -276,8 +536,8 @@ while true; do case $main_choice in 0) - run_script_with_check "./0-one-click-deploy/one-click-deploy.sh" "一键自动部署" - echo "按任意键继续..." + run_script_with_check "./0-one-click-deploy/one-click-deploy.sh" "$(t "一键自动部署" "One-click Auto Deployment")" + echo "$(t "按任意键继续..." "Press any key to continue...")" read -r -n 1 -s ;; 1) @@ -301,30 +561,42 @@ while true; do 11) service="web" ;; 12) break ;; *) - echo -e "${RED}无效的选项,请输入1-12之间的数字${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}无效的选项,请输入1-12之间的数字${COLOR_NC}" + else + echo -e "${COLOR_RED}Invalid option, please enter a number between 1-12${COLOR_NC}" + fi continue ;; esac if [[ -n "$service" ]]; then restart_pod "$service" - echo "按任意键继续..." + echo "$(t "按任意键继续..." "Press any key to continue...")" read -r -n 1 -s fi done ;; - + 3) uninstall_all - echo "按任意键继续..." + echo "$(t "按任意键继续..." "Press any key to continue...")" read -r -n 1 -s ;; 4) - echo "退出部署系统" + if [[ "$LANGUAGE" == "zh" ]]; then + echo "退出部署系统" + else + echo "Exiting deployment system" + fi exit 0 ;; *) - echo -e "${RED}无效的选项,请输入0-4之间的数字${NC}" + if [[ "$LANGUAGE" == "zh" ]]; then + echo -e "${COLOR_RED}无效的选项,请输入0-4之间的数字${COLOR_NC}" + else + echo -e "${COLOR_RED}Invalid option, please enter a number between 0-4${COLOR_NC}" + fi sleep 1 ;; esac -- Gitee