
Huawei Cloud Flexus L Server Hermes Deployment
- 76 installs
- 19 repo stars
- Updated July 31, 2026
- huaweicloud/huaweicloud-skills
One-click deploy the Hermes AI agent platform on Huawei Cloud Flexus L instances with ModelArts model config and robot channel setup.
About
Deploys and configures the Hermes AI agent platform on Flexus L instances with automated instance creation, ModelArts model configuration via COC, and robot channel setup for Feishu/WeCom/DingTalk. A developer uses it to provision Hermes end to end on Huawei Cloud.
- Automated instance creation with optimized configs
- ModelArts model and robot channel setup via COC
Huawei Cloud Flexus L Server Hermes Deployment by the numbers
- 76 all-time installs (skills.sh)
- +4 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #632 of 1,042 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/huaweicloud/huaweicloud-skills --skill huawei-cloud-flexus-l-server-hermes-deploymentAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 76 |
|---|---|
| repo stars | ★ 19 |
| Last updated | July 31, 2026 |
| Repository | huaweicloud/huaweicloud-skills ↗ |
What it does
One-click deploy the Hermes AI agent platform on Huawei Cloud Flexus L instances with ModelArts model config and robot channel setup.
Files
⚠️ Security Execution Rules (Highest Priority): 1. All scripts MUST be executed via skill action=exec, NEVER run directly in shell 2. NEVER print script contents or commands containing AK/SK/Token in conversation 3. NEVER create temporary script files, prefer inline execution (python -c) 4. On execution failure, only return error info, do NOT rewrite scripts or print full commands 5. AK/SK/Token MUST be passed via environment variables, NEVER appear in conversation 6. ABSOLUTELY NEVER expose, log, or print AK/SK/Token values in any form - this is a critical security requirement 7. When using skill action=exec, credentials are automatically inherited from environment variables (HW_ACCESS_KEY, HW_SECRET_KEY, HW_SECURITY_TOKEN), no need to pass them as command line arguments
Hermes One-Click Deployment Skill
Overview
This skill supports one-click deployment of the Hermes AI Agent platform to Huawei Cloud Flexus L instances. It provides a complete workflow including:
- Automated instance creation with optimized configurations
- ModelArts large model configuration via COC (Cloud Operations Center)
- Robot channel configuration (Feishu, WeCom, DingTalk, etc.) via COC
- Gateway management for deployed instances
This skill supports both interactive mode (step-by-step prompts) and non-interactive mode (scripted operations), suitable for manual and automated deployment scenarios.
Prerequisites
Account Requirements
- Valid Huawei Cloud account with sufficient permissions
- Huawei Cloud credentials: Long-term AK/SK OR Temporary AK/SK + security_token
- Required permissions:
- Creating Flexus L instances
- Accessing COC (Cloud Operations Center) services
Credential Acquisition Methods:
This skill supports both long-term and temporary Huawei Cloud credentials:
1. Long-term AK/SK: No security_token required 2. Temporary AK/SK: Security token required
Environment Variables (optional):
HW_ACCESS_KEY: Access Key AK (long-term or temporary)HW_SECRET_KEY: Secret Key SK (long-term or temporary)HW_SECURITY_TOKEN: Security token for temporary credentials (only required for temporary AK/SK)
Architecture Diagram
This skill is built on multiple Huawei Cloud services, involving the following cloud services and components:
User/Agent ──────▶│ Flexus L Instance │──────▶│ Hermes App │──────▶│ Model Config │ ──────▶│ Channel Config │
(Skill caller) (Target Host) (AI Agent Platform) (ModelArts API) (Feishu/Wecom) Component Description:
- User/Agent: Skill caller that triggers Hermes deployment operations via natural language or API
- Flexus L Instance: Huawei Cloud Elastic Cloud Server, serving as the target host for Hermes deployment
- Hermes App: AI Agent platform running on the Flexus L instance
- Model Config: ModelArts large model configuration (API_BASE, API_KEY, MODEL_NAME)
- Channel Config: Robot channel configuration (Feishu, WeCom)
---
Core Commands
Deployment Commands
# Deploy using long-term AK/SK
python scripts/caller.py deploy --ak <AK> --sk <SK> --name hermes-{timestamp} --region cn-north-4
# Deploy using temporary AK/SK (requires security-token)
python scripts/caller.py deploy --ak <temp_ak> --sk <temp_sk> --security-token <security_token> --name hermes-{timestamp} --region cn-north-4
# Deploy in interactive mode (if not specified, auto-generates timestamp format: hermes-20260605143022)
python scripts/caller.py deployInstance Name Description:
- Can customize instance name via
--nameparameter (e.g.,hermes-prod-01,hermes-dev, etc.) - If name is not specified, auto-generates timestamp format:
hermes-YYYYMMDDHHMMSS(e.g.,hermes-20260605143022)
Model Configuration Commands
# Configure model using long-term AK/SK
python scripts/caller.py maas --ak <AK> --sk <SK> --resource-id <instance_id> --region-id cn-north-4 --api-key <api_key> --model-name deepseek-v3.2
# Configure model using temporary AK/SK
python scripts/caller.py maas --ak <temp_ak> --sk <temp_sk> --security-token <security_token> --resource-id <instance_id> --region-id cn-north-4 --api-key <api_key> --model-name deepseek-v3.2
# Configure model in interactive mode
python scripts/caller.py maasChannel Configuration Commands
# Configure Feishu channel using long-term AK/SK
python scripts/caller.py channel --ak <AK> --sk <SK> --resource-id <instance_id> --region-id cn-north-4 --bot-platform feishu --feishu-app-id <app_id> --feishu-app-secret <app_secret>
# Configure Feishu channel using temporary AK/SK
python scripts/caller.py channel --ak <temp_ak> --sk <temp_sk> --security-token <security_token> --resource-id <instance_id> --region-id cn-north-4 --bot-platform feishu --feishu-app-id <app_id> --feishu-app-secret <app_secret>
# Configure WeCom channel using long-term AK/SK
python scripts/caller.py channel --ak <AK> --sk <SK> --resource-id <instance_id> --region-id cn-north-4 --bot-platform wecom --wecom-bot-id <bot_id> --wecom-secret <secret>
# Configure WeCom channel using temporary AK/SK
python scripts/caller.py channel --ak <temp_ak> --sk <temp_sk> --security-token <security_token> --resource-id <instance_id> --region-id cn-north-4 --bot-platform wecom --wecom-bot-id <bot_id> --wecom-secret <secret>
# Configure channel in interactive mode
python scripts/caller.py channelGateway Management Commands
# Restart gateway using long-term AK/SK
python scripts/caller.py gateway --ak <AK> --sk <SK> --resource-id <instance_id> --region-id cn-north-4
# Restart gateway using temporary AK/SK
python scripts/caller.py gateway --ak <temp_ak> --sk <temp_sk> --security-token <security_token> --resource-id <instance_id> --region-id cn-north-4
# Restart gateway in interactive mode
python scripts/caller.py gatewayQuery Execution Result Commands
# Query execution result using long-term AK/SK
python scripts/caller.py query --ak <AK> --sk <SK> --execute-uuid SCT2023083109562601af694bf
# Query execution result using temporary AK/SK
python scripts/caller.py query --ak <temp_ak> --sk <temp_sk> --security-token <security_token> --execute-uuid SCT2023083109562601af694bfParameters:
--execute-uuid: Script execution UUID, format likeSCTxxxxxxxxxxxxxxxbf
Status Description:
FINISHED: Execution successfulABNORMAL: Execution failedRUNNING: Executing
UniAgent Status Query Commands
# Query UniAgent status using long-term AK/SK
python scripts/caller.py uniagent --ak <AK> --sk <SK> --resource-id <instance_id>
# Query UniAgent status using temporary AK/SK
python scripts/caller.py uniagent --ak <temp_ak> --sk <temp_sk> --security-token <security_token> --resource-id <instance_id>
# Query UniAgent status in interactive mode
python scripts/caller.py uniagentUniAgent Status Description:
ONLINE: UniAgent is running normally, can execute COC scriptsOFFLINE: UniAgent is not running, cannot execute COC scriptsUNKNOWN: Status cannot be determined
When to Use:
- Before configuring models or channels, ensure UniAgent is ONLINE
- Troubleshoot COC script execution failures
- Verify instance operational status after deployment
- After the instance creation command is successfully issued (with status codes "200", "201", or "202"), automatically check whether the preconditions are met (status of the gateway and UniAgent). If they are met, you can immediately proceed to the next steps!
Parameter Reference
Global Parameters
| Parameter | Description | Required | Default Value |
|---|---|---|---|
--ak | Huawei Cloud Access Key AK (supports both long-term and temporary) | No | Prompted |
--sk | Huawei Cloud Access Key SK (supports both long-term and temporary) | No | Prompted |
--security-token | Security token for temporary credentials (optional, only required for temporary AK/SK) | No | Prompted |
--non-interactive | Run in non-interactive mode | No | false |
Deploy Command Parameters
| Parameter | Description | Required | Default Value |
|---|---|---|---|
--name | Instance name | No | Auto-generated |
--region | Target region | No | cn-north-4 |
MaaS Command Parameters
| Parameter | Description | Required | Default Value |
|---|---|---|---|
--resource-id | L instance resource ID | Yes | - |
--region-id | COC service region | No | cn-north-4 |
--api-key | ModelArts API Key | Yes | - |
--model-name | Model name | Yes | - |
--api-base-url | API base URL | No | https://api.modelarts-maas.com/v2 |
--timeout | Execution timeout (seconds) | No | 600 |
--execute-user | Execution user | No | root |
Channel Command Parameters
| Parameter | Description | Required | Default Value |
|---|---|---|---|
--resource-id | L instance resource ID | Yes | - |
--region-id | COC service region | No | cn-north-4 |
--bot-platform | Bot platform: feishu or wecom | Yes | - |
--feishu-app-id | Feishu App ID | Conditional | - |
--feishu-app-secret | Feishu App Secret | Conditional | - |
--wecom-bot-id | WeCom Bot ID | Conditional | - |
--wecom-secret | WeCom Secret | Conditional | - |
--timeout | Execution timeout (seconds) | No | 600 |
--execute-user | Execution user | No | root |
Gateway Command Parameters
| Parameter | Description | Required | Default Value |
|---|---|---|---|
--resource-id | L instance resource ID | Yes | - |
--region-id | COC service region | No | cn-north-4 |
--timeout | Execution timeout (seconds) | No | 120 |
--execute-user | Execution user | No | root |
UniAgent Command Parameters
| Parameter | Description | Required | Default Value |
|---|---|---|---|
--resource-id | L instance resource ID | Yes | - |
Workflow
The skill follows these workflow steps:
1. Deploy Hermes: Create and configure a Flexus L instance with Hermes AI Agent platform 2. Configure Model: Set up ModelArts large model via COC (Cloud Operations Center) 3. Configure Channel: Set up robot channels (Feishu, WeCom) via COC 4. Manage Gateway: Restart gateway service when needed
Interactive Mode (Menu)
Run the main entry point to access the interactive menu:
python scripts/caller.pyThis will display a menu for selecting operations.
Output Format
Deploy Command Output
{
"status": "success",
"instance_id": "abc12345-6789-0abc-def1-23456789abc0",
"instance_name": "my-hermes",
"region": "cn-north-4",
"spec": "hf.small.1.linux",
"created_at": "2024-01-15T10:30:00Z"
}MaaS Command Output
{
"status": "success",
"resource_id": "abc12345-6789-0abc-def1-23456789abc0",
"model_name": "deepseek-v3.2",
"api_base_url": "https://api.modelarts-maas.com/v2",
"executed_at": "2024-01-15T10:35:00Z"
}Channel Command Output
{
"status": "success",
"resource_id": "abc12345-6789-0abc-def1-23456789abc0",
"bot_platform": "feishu",
"channel_id": "channel_123",
"executed_at": "2024-01-15T10:40:00Z"
}Gateway Command Output
{
"status": "success",
"resource_id": "abc12345-6789-0abc-def1-23456789abc0",
"action": "restart",
"message": "Hermes gateway restarted successfully"
}Validation Methods
1. Deployment Validation
# Check instance status
python scripts/caller.py deploy --ak <ak> --sk <sk> --name my-hermes --region cn-north-4 --non-interactive
# Expected output: "Instance created successfully" with instance_id2. Model Configuration Validation
# Check model configuration
python scripts/caller.py maas --ak <ak> --sk <sk> --resource-id <instance_id> --region-id cn-north-4 --api-key <key> --model-name deepseek-v3.2 --non-interactive
# Expected output: "Model configuration updated successfully"3. Channel Configuration Validation
# Check channel configuration
python scripts/caller.py channel --ak <ak> --sk <sk> --resource-id <instance_id> --region-id cn-north-4 --bot-platform feishu --feishu-app-id <id> --feishu-app-secret <secret> --non-interactive
# Expected output: "Channel configuration updated successfully"4. Gateway Validation
# Check gateway restart
python scripts/caller.py gateway --ak <ak> --sk <sk> --resource-id <instance_id> --region-id cn-north-4 --non-interactive
# Expected output: "Hermes gateway restarted successfully"Best Practices
1. Credential Management
- Temporary credentials: Use temporary AK/SK + security_token for authentication, providing higher security
- Temporary credentials are issued by STS service with expiration time limits
- Use
--security-tokenparameter to pass the security token - Supports environment variables, command line parameters, and interactive input methods
- Use IAM roles with minimal permissions for production environments
- Rotate credentials regularly according to security policies
2. Region Selection
- Choose the region closest to your users for better performance
- Consider regional compliance requirements when deploying
- Use
cn-north-4as default for China mainland deployments - Hermes deployment only supports: cn-north-4, cn-east-3, cn-south-1, cn-southwest-2
3. Instance Management
- Monitor instance health via Huawei Cloud Console
- Set up auto-scaling policies for high availability
- Configure backup policies for data persistence
4. Model Configuration
- Test models in staging environment before production
- Have fallback models configured for failover scenarios
- After initial deployment, the default model configuration is not usable. You must configure the model before using Hermes.
5. Channel Configuration
- Use dedicated bot accounts for production
- Monitor channel message throughput
- Configure rate limits to prevent abuse
- Currently only Feishu and WeCom bot platforms are supported. Only one bot per platform type is supported.
Notes
General Notes
1. Instance Creation Time: It may take 5-10 minutes for the instance to be fully provisioned 2. COC Script Execution: Model and channel configurations are executed remotely via Huawei Cloud COC (Cloud Operations Center) 3. Security Group: Configure security group rules in Huawei Cloud Console if external access is needed 4. Cost: Using Huawei Cloud resources will incur costs. Ensure your account has sufficient balance. 5. Subsequent Steps: When continuing with subsequent steps (configuring models, channels), there is no need to wait for instance creation to complete. The system handles instance status automatically.
Region Notes
- Fixed Endpoint: When creating a Hermes L Instance, requests are sent to the fixed endpoint
hcss.cn-north-4.myhuaweicloud.com. The region parameter only selects instance specifications. - Guiyang region (
cn-southwest-2) uses specahf.small.1.linux - Other regions (Beijing/Shanghai/Guangzhou) use spec
hf.small.1.linux - Status Codes: 200, 201, and 202 all indicate success
COC Region Concepts
COC involves two different region concepts:
1. COC Service Region (--region-id): The region where COC API service is located (cn-north-4, ap-southeast-3, eu-west-101)
2. Target Instance Region: The region where the L instance is located (can be any Huawei Cloud region worldwide)
These can be different - e.g., COC service in cn-north-4 can execute scripts on instances in ap-southeast-1 (Hong Kong).
Troubleshooting
- Credential Issues: Ensure
--akand--skparameters are provided, or use interactive mode - Region Not Supported: Use supported region IDs or Chinese names in interactive mode
- Instance Creation Failed: Verify account balance, instance type validity, and network connectivity
Reference Documents
scripts/caller.py- Main CLI entry pointscripts/deploy.py- Hermes deployment modulescripts/models.py- ModelArts model configurationscripts/channels.py- Robot channel configurationscripts/lib.py- Core business logic (instance creation, model/channel installation)scripts/utils.py- Utility functions (credentials setup, input prompts)
IAM 权限策略参考
本文档描述了使用 Hermes 一键部署技能所需的华为云 IAM 权限策略。
权限要求
1. Flexus L 实例相关权限
{
"Version": "1.1",
"Statement": [
{
"Action": [
"hcss:instance:create",
"hcss:instance:list",
"hcss:instance:get",
"hcss:instance:delete"
],
"Effect": "Allow",
"Resource": "*"
}
]
}2. COC (Cloud Operations Center) 相关权限
{
"Version": "1.1",
"Statement": [
{
"Action": [
"coc:script:create",
"coc:script:execute",
"coc:script:query",
"coc:script:delete"
],
"Effect": "Allow",
"Resource": "*"
}
]
}3. IAM 相关权限(Project ID 获取)
{
"Version": "1.1",
"Statement": [
{
"Action": [
"iam:project:list",
"iam:project:get"
],
"Effect": "Allow",
"Resource": "*"
}
]
}推荐策略组合
将上述权限组合为一个完整的自定义策略:
{
"Version": "1.1",
"Statement": [
{
"Action": [
"hcss:instance:create",
"hcss:instance:list",
"hcss:instance:get",
"hcss:instance:delete",
"coc:script:create",
"coc:script:execute",
"coc:script:query",
"coc:script:delete",
"iam:project:list",
"iam:project:get"
],
"Effect": "Allow",
"Resource": "*"
}
]
}权限配置步骤
1. 登录华为云控制台 2. 进入 "IAM" -> "用户" -> 选择目标用户 3. 点击 "权限" -> "授予权限" 4. 选择 "自定义策略" -> "新建自定义策略" 5. 粘贴上述策略内容并保存 6. 将策略授予目标用户
注意事项
- 建议遵循最小权限原则,仅授予必要的权限
- 定期审查和更新权限策略
- 使用 AK/SK 时确保密钥安全存储,避免硬编码
技能验证方法
本文档描述了 Hermes 一键部署技能的验证方法和测试步骤。
验证流程
阶段一:环境准备验证
验证项:
- [ ] Python 版本 >= 3.8
- [ ] 依赖包已安装 (
pip install -r requirements.txt) - [ ] 华为云 AK/SK 准备就绪
- [ ] 网络连通性正常
验证命令:
# 检查 Python 版本
python --version
# 检查依赖安装
python -c "from huaweicloudsdkcore.signer.signer import Signer; print('SDK OK')"
# 检查命令行参数支持
python scripts/caller.py deploy --help阶段二:部署功能验证
验证项:
- [ ] 实例创建成功
- [ ] 实例状态正常
- [ ] 实例规格符合预期
验证命令:
# 部署实例(测试环境建议使用较小规格)
python scripts/caller.py deploy --ak <your_ak> --sk <your_sk> --name test-hermes --region cn-north-4
# 验证实例状态(通过华为云控制台或API)预期结果:
- 实例创建成功,状态为 "running"
- 实例规格符合预期配置
阶段三:模型配置验证
验证项:
- [ ] UniAgent 状态为 ONLINE
- [ ] 模型配置成功
- [ ] 模型可正常调用
验证命令:
# 配置模型
python scripts/caller.py maas --ak <your_ak> --sk <your_sk> --resource-id <instance_id> --region-id cn-north-4 --api-key <your_api_key> --model-name deepseek-v3.2 --non-interactive预期结果:
- UniAgent 状态检查通过
- 模型配置任务执行成功
阶段四:通道配置验证
验证项:
- [ ] 通道配置成功
- [ ] 通道状态正常
- [ ] 消息收发正常
验证命令:
# 配置通道(飞书)
python scripts/caller.py channel --ak <your_ak> --sk <your_sk> --resource-id <instance_id> --region-id cn-north-4 --bot-platform feishu --feishu-app-id <app_id> --feishu-app-secret <app_secret> --non-interactive预期结果:
- 通道配置任务执行成功
- 通道显示在 Hermes 通道列表中
常见问题排查
问题 1:AK/SK 验证失败
现象:
错误:AK/SK 验证失败,请检查凭证是否正确排查步骤: 1. 确认 --ak 和 --sk 参数已正确传递 2. 确认 AK/SK 未过期 3. 确认 AK/SK 具有足够的权限
问题 2:UniAgent 状态异常
现象:
UniAgent状态: OFFLINE
请确保UniAgent已启动并在线排查步骤: 1. 等待实例完全启动(通常需要 5-10 分钟) 2. 通过华为云控制台检查 UniAgent 状态 3. 尝试重启 UniAgent 服务
问题 3:模型配置超时
现象:
错误:执行超时,请检查网络连接或增加超时时间排查步骤: 1. 增加超时时间参数 --timeout 1200 2. 检查实例网络连接 3. 确认模型参数正确
自动化测试脚本
可以创建以下测试脚本来自动化验证流程:
#!/bin/bash
echo "=== Hermes Deployment Verification ==="
echo ""
echo "1. Checking Python version..."
python --version
echo ""
echo "2. Checking SDK installation..."
python -c "from huaweicloudsdkcore.signer.signer import Signer; print('SDK OK')"
echo ""
echo "3. Checking command line parameters..."
python scripts/caller.py deploy --help | grep -E "(ak|sk)"
echo ""
echo "=== Verification completed ==="
echo ""
echo "Note: AK/SK credentials are passed via --ak and --sk command line parameters"验证矩阵
| 验证项 | 成功标准 | 失败处理 |
|---|---|---|
| 环境准备 | Python >= 3.8, 依赖安装成功 | 检查 Python 版本,重新安装依赖 |
| 凭证配置 | --ak 和 --sk 参数已正确传递 | 确认 AK/SK 参数正确 |
| 实例部署 | 实例创建成功,状态 running | 检查权限和网络 |
| 模型配置 | 模型配置成功,可正常调用 | 检查 UniAgent 状态和模型参数 |
| 通道配置 | 通道配置成功,可收发消息 | 检查通道配置参数 |
#!/usr/bin/env python3
# coding: utf-8
"""
Huawei Cloud Flexus L Instance One-Click Hermes Deployment Command Line Tool
Use Huawei Cloud SDK for Hermes deployment and configuration management.
Note: This tool supports both long-term and temporary credentials.
- Long-term AK/SK: No security_token required
- Temporary AK/SK: Security token required
Commands:
deploy - One-click deploy Hermes to Huawei Cloud Flexus L Instance
maas - Configure ModelArts large model based on deployed Hermes instance
channel - Configure bot channels based on deployed Hermes instance
Parameters:
--ak: Huawei Cloud Access Key (supports both long-term and temporary AK)
--sk: Huawei Cloud Secret Key (supports both long-term and temporary SK)
--security-token: Security token for temporary credentials (optional, only required for temporary AK/SK)
"""
import argparse
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from scripts.utils import REGION_IDS
from scripts.deploy import do_deploy_hermes
from scripts.models import do_install_maas
from scripts.channels import do_install_channel
from scripts.gateway import do_restart_gateway
from scripts.uniagent import do_check_uniagent
from scripts.lib import coc_query_execution
def show_main_menu():
"""Display main menu for user to select operation type"""
print("=" * 60)
print(" Hermes One-Click Deployment Tool")
print("=" * 60)
print("Please select the operation you want to perform:")
print("")
print(" 1. One-click deploy Hermes to Huawei Cloud Flexus L Instance")
print(" 2. Configure ModelArts large model on deployed Hermes instance")
print(" 3. Configure bot channels on deployed Hermes instance")
print(" 4. Restart Hermes Gateway")
print(" 5. Query COC script execution result")
print(" 6. Query UniAgent status")
print(" 0. Exit")
print("")
print("=" * 60)
while True:
try:
choice = input("Please enter your choice (0-6): ")
choice = int(choice)
if choice in [0, 1, 2, 3, 4, 5, 6]:
return choice
else:
print("Invalid input, please enter a number between 0-6")
except ValueError:
print("Invalid input, please enter a number")
def main():
parser = argparse.ArgumentParser(
description="Huawei Cloud Flexus L Instance One-Click Hermes Deployment",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Interactive mode (shows menu)
python scripts/caller.py
# One-click deploy Hermes to Flexus L Instance using long-term AK/SK
python scripts/caller.py deploy --ak <AK> --sk <SK> --name hermes-{timestamp} --region cn-north-4
# One-click deploy Hermes to Flexus L Instance using temporary AK/SK (requires security-token)
python scripts/caller.py deploy --ak <temp_ak> --sk <temp_sk> --security-token <security_token> --name hermes-{timestamp} --region cn-north-4
# Configure ModelArts large model using long-term AK/SK
python scripts/caller.py maas --ak <AK> --sk <SK> --resource-id <instance_id> --region-id cn-north-4 --api-key <your_api_key> --model-name deepseek-v3.2
# Configure ModelArts large model using temporary AK/SK
python scripts/caller.py maas --ak <temp_ak> --sk <temp_sk> --security-token <security_token> --resource-id <instance_id> --region-id cn-north-4 --api-key <your_api_key> --model-name deepseek-v3.2
# Configure Feishu bot channel using long-term AK/SK
python scripts/caller.py channel --ak <AK> --sk <SK> --resource-id <instance_id> --region-id cn-north-4 --bot-platform feishu --feishu-app-id <app_id> --feishu-app-secret <app_secret>
# Configure WeCom bot channel using long-term AK/SK
python scripts/caller.py channel --ak <AK> --sk <SK> --resource-id <instance_id> --region-id cn-north-4 --bot-platform wecom --wecom-bot-id <bot_id> --wecom-secret <secret>
# Query COC script execution result using long-term AK/SK
python scripts/caller.py query --ak <AK> --sk <SK> --execute-uuid <execute_uuid>
""",
)
subparsers = parser.add_subparsers(dest='command', help='Available commands')
deploy_parser = subparsers.add_parser('deploy', help='One-click deploy Hermes to Flexus L Instance')
deploy_parser.add_argument('--ak', help='Huawei Cloud AK (supports both long-term and temporary AK, optional, will prompt for input if not provided)')
deploy_parser.add_argument('--sk', help='Huawei Cloud SK (supports both long-term and temporary SK, optional, will prompt for input if not provided)')
deploy_parser.add_argument('--security-token', help='Huawei Cloud Security Token (optional, only required for temporary AK/SK, will prompt for input if not provided)')
deploy_parser.add_argument('--name', help='Instance name (optional, auto-generated by default)')
deploy_parser.add_argument('--region', choices=REGION_IDS, help='Region ID (optional, default cn-north-4)')
deploy_parser.add_argument('--non-interactive', action='store_true', help='Non-interactive mode, execute without confirmation')
maas_parser = subparsers.add_parser('maas', help='Configure ModelArts large model on deployed Hermes instance')
maas_parser.add_argument('--ak', help='Huawei Cloud AK (supports both long-term and temporary AK, optional, will prompt for input if not provided)')
maas_parser.add_argument('--sk', help='Huawei Cloud SK (supports both long-term and temporary SK, optional, will prompt for input if not provided)')
maas_parser.add_argument('--security-token', help='Huawei Cloud Security Token (optional, only required for temporary AK/SK, will prompt for input if not provided)')
maas_parser.add_argument('--resource-id', required=True, help='L Instance resource ID (required)')
maas_parser.add_argument('--region-id', choices=REGION_IDS, help='Region ID (optional, default cn-north-4)')
maas_parser.add_argument('--api-key', required=True, help='ModelArts API Key (required)')
maas_parser.add_argument('--model-name', required=True, help='Large model name (required, e.g.: deepseek-v3.2, qwen-plus, glm-4)')
maas_parser.add_argument('--api-base-url', default='https://api.modelarts-maas.com/v2', help='API Base URL (optional, default https://api.modelarts-maas.com/v2)')
maas_parser.add_argument('--timeout', type=int, help='Timeout in seconds (optional, default 600)')
maas_parser.add_argument('--execute-user', default='root', help='Execute user (optional, default root)')
maas_parser.add_argument('--non-interactive', action='store_true', help='Non-interactive mode, execute without confirmation')
channel_parser = subparsers.add_parser('channel', help='Configure bot channels on deployed Hermes instance')
channel_parser.add_argument('--ak', help='Huawei Cloud AK (supports both long-term and temporary AK, optional, will prompt for input if not provided)')
channel_parser.add_argument('--sk', help='Huawei Cloud SK (supports both long-term and temporary SK, optional, will prompt for input if not provided)')
channel_parser.add_argument('--security-token', help='Huawei Cloud Security Token (optional, only required for temporary AK/SK, will prompt for input if not provided)')
channel_parser.add_argument('--resource-id', required=True, help='L Instance resource ID (required)')
channel_parser.add_argument('--region-id', choices=REGION_IDS, help='Region ID (optional, default cn-north-4)')
channel_parser.add_argument('--bot-platform', choices=['feishu', 'wecom'], required=True, help='Bot platform: feishu or wecom (required)')
channel_parser.add_argument('--feishu-app-id', help='Feishu App ID (required when feishu platform is selected)')
channel_parser.add_argument('--feishu-app-secret', help='Feishu App Secret (required when feishu platform is selected)')
channel_parser.add_argument('--wecom-bot-id', help='WeCom Bot ID (required when wecom platform is selected)')
channel_parser.add_argument('--wecom-secret', help='WeCom Secret (required when wecom platform is selected)')
channel_parser.add_argument('--timeout', type=int, help='Timeout in seconds (optional, default 600)')
channel_parser.add_argument('--execute-user', default='root', help='Execute user (optional, default root)')
channel_parser.add_argument('--non-interactive', action='store_true', help='Non-interactive mode, execute without confirmation')
gateway_parser = subparsers.add_parser('gateway', help='Restart Hermes Gateway')
gateway_parser.add_argument('--ak', help='Huawei Cloud AK (supports both long-term and temporary AK, optional, will prompt for input if not provided)')
gateway_parser.add_argument('--sk', help='Huawei Cloud SK (supports both long-term and temporary SK, optional, will prompt for input if not provided)')
gateway_parser.add_argument('--security-token', help='Huawei Cloud Security Token (optional, only required for temporary AK/SK, will prompt for input if not provided)')
gateway_parser.add_argument('--resource-id', required=True, help='L Instance resource ID (required)')
gateway_parser.add_argument('--region-id', choices=REGION_IDS, help='Region ID (optional, default cn-north-4)')
gateway_parser.add_argument('--timeout', type=int, help='Timeout in seconds (optional, default 120)')
gateway_parser.add_argument('--execute-user', default='root', help='Execute user (optional, default root)')
gateway_parser.add_argument('--non-interactive', action='store_true', help='Non-interactive mode, execute without confirmation')
query_parser = subparsers.add_parser('query', help='Query COC script execution result')
query_parser.add_argument('--ak', help='Huawei Cloud AK (supports both long-term and temporary AK, optional, will prompt for input if not provided)')
query_parser.add_argument('--sk', help='Huawei Cloud SK (supports both long-term and temporary SK, optional, will prompt for input if not provided)')
query_parser.add_argument('--security-token', help='Huawei Cloud Security Token (optional, only required for temporary AK/SK, will prompt for input if not provided)')
query_parser.add_argument('--execute-uuid', required=True, help='Script execution UUID (e.g.: SCT2023083109562601af694bf)')
uniagent_parser = subparsers.add_parser('uniagent', help='Query UniAgent status')
uniagent_parser.add_argument('--ak', help='Huawei Cloud AK (supports both long-term and temporary AK, optional, will prompt for input if not provided)')
uniagent_parser.add_argument('--sk', help='Huawei Cloud SK (supports both long-term and temporary SK, optional, will prompt for input if not provided)')
uniagent_parser.add_argument('--security-token', help='Huawei Cloud Security Token (optional, only required for temporary AK/SK, will prompt for input if not provided)')
uniagent_parser.add_argument('--resource-id', required=True, help='L Instance resource ID (required)')
args = parser.parse_args()
try:
if args.command == 'query':
security_token = args.security_token if hasattr(args, 'security_token') else None
region = args.region if hasattr(args, 'region') else None
print(f"Querying script execution result: {args.execute_uuid}")
result = coc_query_execution(args.execute_uuid, args.ak, args.sk, security_token, region)
data = result.get('data', {})
if data:
print("=" * 60)
print("Query Result:")
print("-" * 60)
print(f"Batch Index: {data.get('batch_index', '')}")
print(f"Total Instances: {data.get('total_instances', '')}")
instances = data.get('execute_instances', [])
if instances:
inst = instances[0]
print(f"Execution Status: {inst.get('status', '')}")
print(f"Instance ID: {inst.get('id', '')}")
print(f"Command UUID: {inst.get('cmd_uuid', '')}")
print(f"Execute Costs: {inst.get('execute_costs', '')}ms")
print("-" * 60)
if inst.get('message'):
print("Execution Output:")
print(inst['message'])
target = inst.get('target_instance', {})
if target:
print("-" * 60)
print("Target Instance:")
print(f" Resource ID: {target.get('resource_id', '')}")
print(f" Region: {target.get('region_id', '')}")
print(f" Provider: {target.get('provider', '')}")
print("=" * 60)
else:
print(f"Query failed: {result.get('error', {}).get('message', 'Unknown error')}")
elif args.command == 'uniagent':
do_check_uniagent(args)
elif args.command == 'maas':
do_install_maas(args)
elif args.command == 'channel':
do_install_channel(args)
elif args.command == 'gateway':
do_restart_gateway(args)
elif args.command == 'deploy':
do_deploy_hermes(args)
else:
choice = show_main_menu()
if choice == 0:
print("退出程序")
sys.exit(0)
elif choice == 1:
args.command = 'deploy'
do_deploy_hermes(args)
elif choice == 2:
args.command = 'maas'
do_install_maas(args)
elif choice == 3:
args.command = 'channel'
do_install_channel(args)
elif choice == 4:
args.command = 'gateway'
do_restart_gateway(args)
elif choice == 5:
ak = input("Please enter Huawei Cloud Temporary AK: ")
sk = input("Please enter Huawei Cloud Temporary SK: ")
security_token = input("Please enter Security Token: ")
execute_uuid = input("Please enter script execution UUID: ")
region = input("Please enter COC region (default: cn-north-4): ") or "cn-north-4"
print(f"Querying script execution result: {execute_uuid}")
result = coc_query_execution(execute_uuid, ak, sk, security_token, region)
data = result.get('data', {})
if data:
print("=" * 60)
print("Query Result:")
print("-" * 60)
print(f"Batch Index: {data.get('batch_index', '')}")
print(f"Total Instances: {data.get('total_instances', '')}")
instances = data.get('execute_instances', [])
if instances:
inst = instances[0]
print(f"Execution Status: {inst.get('status', '')}")
print(f"Instance ID: {inst.get('id', '')}")
print(f"Command UUID: {inst.get('cmd_uuid', '')}")
print(f"Execute Costs: {inst.get('execute_costs', '')}ms")
print("-" * 60)
if inst.get('message'):
print("Execution Output:")
print(inst['message'])
target = inst.get('target_instance', {})
if target:
print("-" * 60)
print("Target Instance:")
print(f" Resource ID: {target.get('resource_id', '')}")
print(f" Region: {target.get('region_id', '')}")
print(f" Provider: {target.get('provider', '')}")
print("=" * 60)
else:
print(f"Query failed: {result.get('error', {}).get('message', 'Unknown error')}")
elif choice == 6:
args.command = 'uniagent'
do_check_uniagent(args)
except KeyboardInterrupt:
print("\n\nUser interrupted operation")
sys.exit(0)
if __name__ == '__main__':
main()
#!/usr/bin/env python3
# coding: utf-8
"""
Huawei Cloud Flexus L Instance One-Click Hermes Deployment - Channel Installation Module
Note: This module supports both long-term and temporary credentials.
- Long-term AK/SK: No security_token required
- Temporary AK/SK: Security token required
"""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from scripts.lib import install_channel_remote
from scripts.utils import prompt_for_input, REGION_IDS
def do_install_channel(args):
"""Execute bot channel configuration
Args:
args: Command line argument object with the following attributes:
- resource_id: L instance resource ID (command line arg --resource-id)
- region_id: Region ID (command line arg --region-id)
- bot_platform: Bot platform (command line arg --bot-platform)
- feishu_app_id: Feishu App ID (command line arg --feishu-app-id)
- feishu_app_secret: Feishu App Secret (command line arg --feishu-app-secret)
- wecom_bot_id: WeCom Bot ID (command line arg --wecom-bot-id)
- wecom_secret: WeCom Secret (command line arg --wecom-secret)
- timeout: Timeout duration (command line arg --timeout)
- execute_user: Execute user (command line arg --execute-user)
- ak: Huawei Cloud AK (supports both long-term and temporary AK) (command line arg --ak)
- sk: Huawei Cloud SK (supports both long-term and temporary SK) (command line arg --sk)
- security_token: Security token for temporary credentials (optional, only required for temporary AK/SK) (command line arg --security-token)
- non_interactive: Whether non-interactive mode (command line arg --non-interactive)
Returns:
None
"""
print("=" * 60)
print(" Hermes Bot Channel Configuration")
print("=" * 60)
non_interactive = args.non_interactive if hasattr(args, 'non_interactive') else False
# Get credentials (from command line parameters)
ak = args.ak if hasattr(args, 'ak') and args.ak else None
sk = args.sk if hasattr(args, 'sk') and args.sk else None
security_token = args.security_token if hasattr(args, 'security_token') and args.security_token else None
# If credentials not provided, prompt interactively (skip in non-interactive mode)
if not ak or not sk:
print("\nHuawei Cloud credentials not configured, entering interactive configuration...")
print("Please configure Huawei Cloud credentials:")
print(" - Long-term AK/SK: No security_token required")
print(" - Temporary AK/SK: Security token required")
print("-" * 40)
ak = prompt_for_input("Huawei Cloud AK (HW_ACCESS_KEY)", required=True)
sk = prompt_for_input("Huawei Cloud SK (HW_SECRET_KEY)", required=True, hide_input=True)
security_token = prompt_for_input("Security Token (optional, only for temporary credentials)", required=False)
# Get parameters
resource_id = args.resource_id if hasattr(args, 'resource_id') and args.resource_id else None
region_id = args.region_id if hasattr(args, 'region_id') and args.region_id else None
bot_platform = args.bot_platform if hasattr(args, 'bot_platform') and args.bot_platform else ""
feishu_app_id = args.feishu_app_id if hasattr(args, 'feishu_app_id') and args.feishu_app_id else ""
feishu_app_secret = args.feishu_app_secret if hasattr(args, 'feishu_app_secret') and args.feishu_app_secret else ""
wecom_bot_id = args.wecom_bot_id if hasattr(args, 'wecom_bot_id') and args.wecom_bot_id else ""
wecom_secret = args.wecom_secret if hasattr(args, 'wecom_secret') and args.wecom_secret else ""
timeout = args.timeout if hasattr(args, 'timeout') and args.timeout else 600
# Get parameters interactively (skip in non-interactive mode)
if not resource_id:
if non_interactive:
print("Error: Missing required parameter --resource-id")
return
resource_id = prompt_for_input("L Instance resource ID", required=True)
if not region_id:
if non_interactive:
region_id = "cn-north-4"
else:
region_id = prompt_for_input("Region ID", required=False, default="cn-north-4", choices=REGION_IDS)
if not bot_platform:
if non_interactive:
print("Error: Missing required parameter --bot-platform")
return
print("\nAvailable platforms:")
print(" feishu - Feishu")
print(" wecom - WeCom")
bot_platform = prompt_for_input("Bot platform", required=True, choices=["feishu", "wecom"])
# Get platform-specific parameters
if bot_platform == "feishu":
if not feishu_app_id:
if non_interactive:
print("Error: Missing required parameter --feishu-app-id")
return
feishu_app_id = prompt_for_input("Feishu App ID", required=True)
if not feishu_app_secret:
if non_interactive:
print("Error: Missing required parameter --feishu-app-secret")
return
feishu_app_secret = prompt_for_input("Feishu App Secret", required=True)
elif bot_platform == "wecom":
if not wecom_bot_id:
if non_interactive:
print("Error: Missing required parameter --wecom-bot-id")
return
wecom_bot_id = prompt_for_input("WeCom Bot ID", required=True)
if not wecom_secret:
if non_interactive:
print("Error: Missing required parameter --wecom-secret")
return
wecom_secret = prompt_for_input("WeCom Secret", required=True)
if not timeout:
timeout = 600
print(f"\nConfiguration:")
print(f" Resource ID: {resource_id}")
print(f" Region: {region_id}")
print(f" Target Platform: {bot_platform}")
if bot_platform == "feishu":
print(f" Feishu App ID: {feishu_app_id}")
print(f" Feishu App Secret: {feishu_app_secret[:8]}****")
elif bot_platform == "wecom":
print(f" WeCom Bot ID: {wecom_bot_id}")
print(f" WeCom Secret: {wecom_secret[:8]}****")
print(f" Timeout: {timeout} seconds")
if not non_interactive:
confirm = prompt_for_input("Confirm configuration?", required=False, default="y", choices=["y", "n"])
if confirm.lower() != "y":
print("\nConfiguration cancelled")
return
print("\nStarting bot channel configuration...")
result = install_channel_remote(
resource_id, region_id, bot_platform,
feishu_app_id, feishu_app_secret,
wecom_bot_id, wecom_secret,
timeout, ak=ak, sk=sk, security_token=security_token, coc_region=region_id
)
if result.get("ok"):
print(f"\n✓ {result['text']}")
if result.get("result"):
print(f" Execution ID: {result['result'].get('execute_uuid', 'Unknown')}")
print(f" Status: {result['result'].get('status', 'Unknown')}")
if result['result'].get('output'):
print(f" Output: {result['result']['output'][:200]}...")
else:
print(f"\n✗ Configuration failed")
if result.get("error"):
print(f" Error Code: {result['error'].get('code')}")
print(f" Error Message: {result['error'].get('message')}")#!/usr/bin/env python3
# coding: utf-8
"""
Huawei Cloud Flexus L Instance One-Click Hermes Deployment - Deployment Module
Note: This module supports both long-term and temporary credentials.
- Long-term AK/SK: No security_token required
- Temporary AK/SK: Security token required
"""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from scripts.lib import create_hermes_instance
from scripts.utils import print_region_list, prompt_for_input, REGION_IDS, get_region_id_by_name, REGIONS
def do_deploy_hermes(args):
"""Execute Hermes instance deployment
Args:
args: Command line argument object with the following attributes:
- name: Instance name (command line arg --name)
- region: Region ID (command line arg --region)
- ak: Huawei Cloud AK (supports both long-term and temporary AK) (command line arg --ak)
- sk: Huawei Cloud SK (supports both long-term and temporary SK) (command line arg --sk)
- security_token: Security token for temporary credentials (optional, only required for temporary AK/SK) (command line arg --security-token)
- non_interactive: Whether non-interactive mode (command line arg --non-interactive)
Returns:
None
"""
print("=" * 60)
print(" Hermes Instance One-Click Deployment")
print("=" * 60)
non_interactive = getattr(args, 'non_interactive', False)
# Get credentials (from command line parameters)
ak = args.ak if hasattr(args, 'ak') and args.ak else None
sk = args.sk if hasattr(args, 'sk') and args.sk else None
security_token = args.security_token if hasattr(args, 'security_token') and args.security_token else None
# Get parameters
instance_name = getattr(args, 'name', None)
region = getattr(args, 'region', None)
# If credentials not provided, prompt interactively (skip in non-interactive mode)
if not ak or not sk:
print("\nHuawei Cloud credentials not configured, entering interactive configuration...")
print("Please configure Huawei Cloud credentials:")
print(" - Long-term AK/SK: No security_token required")
print(" - Temporary AK/SK: Security token required")
print("-" * 40)
ak = prompt_for_input("Huawei Cloud AK (HW_ACCESS_KEY)", required=True)
sk = prompt_for_input("Huawei Cloud SK (HW_SECRET_KEY)", required=True, hide_input=True)
security_token = prompt_for_input("Security Token (optional, only for temporary credentials)", required=False)
# If instance_name not provided via CLI, prompt interactively (skip in non-interactive mode)
# Note: If still None after this block, lib.py will auto-generate timestamp format (hermes-YYYYMMDDHHMMSS)
if not instance_name and not non_interactive:
instance_name = prompt_for_input("Instance name (optional, press Enter for auto-generate)", required=False)
if not region:
if non_interactive:
region = "cn-north-4"
else:
print_region_list()
print("Tip: You can enter region ID (e.g. cn-southwest-2) or Chinese name (e.g. Southwest-Guiyang)")
user_input = prompt_for_input("Target region", required=False, default="cn-north-4")
# Convert user input to standard region ID (supports Chinese names)
region = get_region_id_by_name(user_input)
# Validate region
while region not in REGION_IDS:
print(f"Error: '{region}' is not a valid region.")
print_region_list()
user_input = prompt_for_input("Please re-enter target region", required=False, default="cn-north-4")
region = get_region_id_by_name(user_input)
# Get region display name
region_name = REGIONS.get(region, region)
print(f"\nDeployment Configuration:")
print(f" Instance Name: {instance_name or 'Auto-generated'}")
print(f" Target Region: {region} ({region_name})")
# Confirm deployment (skip in non-interactive mode)
non_interactive = getattr(args, 'non_interactive', False)
if not non_interactive:
confirm = prompt_for_input("Confirm deployment?", required=False, default="y", choices=["y", "n"])
if confirm.lower() != "y":
print("\nDeployment cancelled")
return
else:
print(" Non-interactive mode: Auto-confirm")
# Execute deployment
print("\nStarting Hermes instance creation...")
result = create_hermes_instance(ak, sk, security_token, instance_name, region)
if result.get("ok"):
print(f"\n✓ {result['text']}")
if result.get("result"):
print(f" Order ID: {result['result'].get('order_id', 'Unknown')}")
print(f" Instance ID: {result['result'].get('instance_ids', ['Unknown'])[0]}")
print("\nDeployment completed!")
print("Tip: Instance creation may take several minutes, please wait patiently.")
else:
print(f"\n✗ Deployment failed")
if result.get("error"):
print(f" Error Code: {result['error'].get('code')}")
print(f" Error Message: {result['error'].get('message')}")#!/usr/bin/env python3
# coding: utf-8
"""
Huawei Cloud Flexus L Instance One-Click Hermes Deployment - Gateway Management Module
Note: This module supports both long-term and temporary credentials.
- Long-term AK/SK: No security_token required
- Temporary AK/SK: Security token required
"""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from scripts.lib import restart_gateway_remote
from scripts.utils import prompt_for_input, REGION_IDS
def do_restart_gateway(args):
"""Execute Hermes gateway restart
Args:
args: Command line argument object with the following attributes:
- resource_id: L instance resource ID (command line arg --resource-id)
- region_id: Region ID (command line arg --region-id)
- timeout: Timeout duration (command line arg --timeout)
- execute_user: Execute user (command line arg --execute-user)
- ak: Huawei Cloud AK (supports both long-term and temporary AK) (command line arg --ak)
- sk: Huawei Cloud SK (supports both long-term and temporary SK) (command line arg --sk)
- security_token: Security token for temporary credentials (optional, only required for temporary AK/SK) (command line arg --security-token)
- non_interactive: Whether non-interactive mode (command line arg --non-interactive)
Returns:
None
"""
print("=" * 60)
print(" Hermes Gateway Restart")
print("=" * 60)
non_interactive = args.non_interactive if hasattr(args, 'non_interactive') else False
# Get credentials (from command line parameters)
ak = args.ak if hasattr(args, 'ak') and args.ak else None
sk = args.sk if hasattr(args, 'sk') and args.sk else None
security_token = args.security_token if hasattr(args, 'security_token') and args.security_token else None
# If credentials not provided, prompt interactively (skip in non-interactive mode)
if not ak or not sk:
print("\nHuawei Cloud credentials not configured, entering interactive configuration...")
print("Please configure Huawei Cloud credentials:")
print(" - Long-term AK/SK: No security_token required")
print(" - Temporary AK/SK: Security token required")
print("-" * 40)
ak = prompt_for_input("Huawei Cloud AK (HW_ACCESS_KEY)", required=True)
sk = prompt_for_input("Huawei Cloud SK (HW_SECRET_KEY)", required=True, hide_input=True)
security_token = prompt_for_input("Security Token (optional, only for temporary credentials)", required=False)
# Get parameters
resource_id = args.resource_id if hasattr(args, 'resource_id') and args.resource_id else None
region_id = args.region_id if hasattr(args, 'region_id') and args.region_id else None
timeout = args.timeout if hasattr(args, 'timeout') and args.timeout else 120
# Get parameters interactively (skip in non-interactive mode)
if not resource_id:
if non_interactive:
print("Error: Missing required parameter --resource-id")
return
resource_id = prompt_for_input("L Instance resource ID", required=True)
if not region_id:
if non_interactive:
region_id = "cn-north-4"
else:
region_id = prompt_for_input("Region ID", required=False, default="cn-north-4", choices=REGION_IDS)
if not timeout:
timeout = 120
print(f"\nConfiguration:")
print(f" Resource ID: {resource_id}")
print(f" Region: {region_id}")
print(f" Timeout: {timeout} seconds")
if not non_interactive:
confirm = prompt_for_input("Confirm gateway restart?", required=False, default="y", choices=["y", "n"])
if confirm.lower() != "y":
print("\nOperation cancelled")
return
print("\nStarting Hermes gateway restart...")
result = restart_gateway_remote(resource_id, region_id, timeout, ak=ak, sk=sk, security_token=security_token, coc_region=region_id)
if result.get("ok"):
print(f"\n✓ {result['text']}")
if result.get("result"):
print(f" Execution ID: {result['result'].get('execute_uuid', 'Unknown')}")
print(f" Status: {result['result'].get('status', 'Unknown')}")
if result['result'].get('output'):
print(f"\n Execution Output:")
print(f" {result['result']['output']}")
if result['result'].get('error'):
print(f"\n Error Message:")
print(f" {result['result']['error']}")
else:
print(f"\n✗ Restart failed")
if result.get("error"):
print(f" Error Code: {result['error'].get('code')}")
print(f" Error Message: {result['error'].get('message')}")
if result.get("result") and result['result'].get('output'):
print(f"\n Execution Output:")
print(f" {result['result']['output']}")#!/usr/bin/env python3
# coding: utf-8
"""
Huawei Cloud Flexus L Instance One-Click Hermes Deployment Core Module
Includes:
1. L Instance creation functionality
2. COC script management (create script, execute script, query script)
3. ModelArts large model configuration
4. Bot channel configuration
Note: This module supports both long-term and temporary credentials.
- Long-term AK/SK: No security_token required
- Temporary AK/SK: Security token required
"""
import json
import os
import logging
import requests
import uuid
from datetime import datetime
from urllib.parse import urlparse
from typing import Any, Optional, List, Dict
from huaweicloudsdkcore.auth.credentials import GlobalCredentials
from huaweicloudsdkcoc.v1.region.coc_region import CocRegion
from huaweicloudsdkcore.exceptions import exceptions
from huaweicloudsdkcoc.v1 import *
from huaweicloudsdkcoc.v1.model.script_execute_model import ScriptExecuteModel
from huaweicloudsdkcoc.v1.model.script_execute_param import ScriptExecuteParam
from huaweicloudsdkcoc.v1.model.execute_instances_batch_info import ExecuteInstancesBatchInfo
from huaweicloudsdkcoc.v1.model.execute_resource_instance import ExecuteResourceInstance
from huaweicloudsdkcoc.v1.model.script_properties_model import ScriptPropertiesModel
from huaweicloudsdkcoc.v1.model.add_script_model import AddScriptModel
logger = logging.getLogger(__name__)
# Constants definition
VALID_SCRIPT_TYPES = ["SHELL", "PYTHON", "BAT"]
VALID_RISK_LEVELS = ["LOW", "MEDIUM", "HIGH"]
VALID_ROTATION_STRATEGIES = ["CONTINUE", "STOP"]
# Default configuration
DEFAULT_BASE_URL = "https://api.modelarts-maas.com/v2"
DEFAULT_CONFIG_PATH = "/home/hermes/.hermes/config.yaml"
DEFAULT_ENV_PATH = "/home/hermes/.hermes/.env"
class Credentials:
"""Credentials for Huawei Cloud temporary access"""
def __init__(self, ak, sk, security_token):
self.ak = ak
self.sk = sk
self.security_token = security_token
def get_credentials(ak, sk, region=None):
"""Get Huawei Cloud credentials (parameter passing)"""
if not ak or not sk:
raise ValueError("ak and sk are required parameters")
if not region:
region = "cn-north-4"
return ak, sk, region
def get_project_id_by_region(ak: str, sk: str, security_token: str, region: str) -> Optional[str]:
"""
Get Project ID for specified region via AK/SK
Args:
ak: Huawei Cloud temporary AK
sk: Huawei Cloud temporary SK
security_token: Security token for temporary credentials (required)
region: Target region, e.g. cn-north-4, cn-southwest-2
Returns:
Project ID string, or None if failed
"""
if not ak or not sk or not security_token:
print("Error: Credentials not configured")
return None
iam_endpoint = f"https://iam.{region}.myhuaweicloud.com/v3/projects"
try:
from huaweicloudsdkcore.signer.signer import Signer
from huaweicloudsdkcore.sdk_request import SdkRequest
credentials = Credentials(ak, sk, security_token)
signer = Signer(credentials)
request = SdkRequest()
request.method = "GET"
request.schema = "https"
request.host = f"iam.{region}.myhuaweicloud.com"
request.resource_path = "/v3/projects"
request.body = ""
request.header_params = {
"Content-Type": "application/json",
"Client-Request-Id": str(uuid.uuid4()),
"X-Security-Token": security_token
}
request.query_params = []
signed_request = signer.sign(request)
headers = {}
for key, value in signed_request.header_params.items():
if isinstance(value, bytes):
headers[key] = value.decode('iso-8859-1')
else:
headers[key] = str(value)
print(f"Getting Project ID - Request URL: {iam_endpoint}")
resp = requests.get(iam_endpoint, headers=headers, timeout=30)
if resp.status_code == 200:
data = resp.json()
projects = data.get('projects', [])
if projects:
for project in projects:
project_name = project.get('name', '')
if project_name == region:
return project.get('id')
return projects[0].get('id')
else:
print("Error: Project not found")
return None
else:
print(f"Failed to get Project ID - Status code: {resp.status_code}, Response: {resp.text}")
return None
except ImportError as e:
print(f"SDK import failed: {str(e)}")
return None
except Exception as e:
print(f"Error getting Project ID: {str(e)}")
return None
def create_hermes_instance(ak, sk, security_token, instance_name=None, region=None):
"""
Create Huawei Cloud Flexus L Instance dedicated for Hermes
Parameters:
ak: Huawei Cloud temporary AK
sk: Huawei Cloud temporary SK
security_token: Security token for temporary credentials (required)
instance_name: Instance name, optional, auto-generated as hermes-timestamp if not specified
region: Target region, optional, default cn-north-4 if not specified
Returns:
dict: Result dictionary containing ok, text, result, error fields
"""
if not ak or not sk or not security_token:
return {
"ok": False,
"text": "Credentials not configured",
"result": None,
"error": {
"code": "CONFIG_ERROR",
"message": "ak, sk and security_token are required parameters"
}
}
target_region = region if region else "cn-north-4"
project_id = get_project_id_by_region(ak, sk, security_token, target_region)
if not project_id:
return {
"ok": False,
"text": "Failed to get Project ID",
"result": None,
"error": {
"code": "PROJECT_ID_ERROR",
"message": f"Failed to get Project ID for region {target_region}, please check credentials"
}
}
if not instance_name:
instance_name = f"hermes-{datetime.now().strftime('%Y%m%d%H%M%S')}"
endpoint = "https://hcss.cn-north-4.myhuaweicloud.com/v1/light-instances"
if target_region == "cn-southwest-2":
plan_spec = "ahf.small.1.linux"
else:
plan_spec = "hf.small.1.linux"
request_body = {
"instance_name": instance_name,
"plan_spec": plan_spec,
"image_ref": {
"image_name": "Hermes",
"image_version": "0.9.0"
},
"region": target_region,
"charging_mode": "prePaid",
"period_type": "month",
"period_num": 1,
"purchase_quantity": 1,
"description": "Hermes one-click deployment",
"is_auto_renew": True,
"is_auto_pay": True,
"extra_resources": [
{"type": "evs", "size": 50},
{"type": "cbr", "size": 50},
{"type": "hss"}
]
}
try:
from huaweicloudsdkcore.signer.signer import Signer
from huaweicloudsdkcore.sdk_request import SdkRequest
credentials = Credentials(ak, sk, security_token)
signer = Signer(credentials)
parsed_url = urlparse(endpoint)
body_str = json.dumps(request_body, ensure_ascii=False, separators=(',', ':'))
request = SdkRequest()
request.method = "POST"
request.schema = parsed_url.scheme
request.host = parsed_url.hostname
request.resource_path = parsed_url.path
request.body = body_str
request.header_params = {
"X-Project-Id": project_id,
"Content-Type": "application/json",
"Client-Request-Id": str(uuid.uuid4())
}
if security_token:
request.header_params["X-Security-Token"] = security_token
request.query_params = []
signed_request = signer.sign(request)
headers = {}
for key, value in signed_request.header_params.items():
if isinstance(value, bytes):
headers[key] = value.decode('iso-8859-1')
else:
headers[key] = str(value)
# Send instance creation request
print(f" Sending instance creation request...")
resp = requests.request(
"POST",
endpoint,
headers=headers,
data=body_str.encode('utf-8'),
verify=True
)
# Output HTTP status code immediately to let user know request is processed
print(f" HTTP Status Code: {resp.status_code}")
if resp.status_code in [200, 201, 202]:
print(f" ✓ Instance creation request submitted successfully")
else:
print(f" ✗ Request failed: {resp.reason}")
if resp.status_code in [200, 201, 202]:
response_data = resp.json()
return {
"ok": True,
"text": f"Instance creation request submitted, Instance ID: {response_data.get('instance_id', 'unknown')}",
"result": response_data,
"error": None
}
else:
return {
"ok": False,
"text": f"Instance creation failed: {resp.reason}",
"result": None,
"error": {
"code": str(resp.status_code),
"message": resp.text
}
}
except ImportError as e:
return {
"ok": False,
"text": "SDK import failed",
"result": None,
"error": {
"code": "SDK_ERROR",
"message": f"Please install huaweicloudsdkcore: {str(e)}"
}
}
except Exception as e:
return {
"ok": False,
"text": f"Error occurred while creating instance: {str(e)}",
"result": None,
"error": {
"code": "UNKNOWN_ERROR",
"message": str(e)
}
}
# Hermes script templates
HERMES_SCRIPT_TEMPLATES = {
"install_maas": {
"name": "Hermes-MaaS-Model-Install",
"type": "SHELL",
"description": "Configure ModelArts large model on Hermes instance",
"risk_level": "MEDIUM",
"content": '''#!/bin/bash
# Hermes ModelArts Large Model Configuration Script
API_KEY='${api_key}'
MODEL_NAME='${model_name}'
API_BASE_URL='${api_base_url}'
CONFIG_PATH='/home/hermes/.hermes/config.yaml'
echo "=== Hermes ModelArts Large Model Configuration ==="
echo "API Key: ${API_KEY:0:8}****"
echo "Model Name: $MODEL_NAME"
echo "API Base URL: $API_BASE_URL"
echo "Config File: $CONFIG_PATH"
# Check and install yq (YAML version of jq)
if ! command -v yq &> /dev/null; then
echo ""
echo "Installing yq..."
# Try package manager installation
if command -v apt-get &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq yq 2>/dev/null
elif command -v yum &> /dev/null; then
sudo yum install -y -q yq 2>/dev/null
fi
# If package manager installation failed, download binary directly
if ! command -v yq &> /dev/null; then
echo "Package manager installation failed, trying direct download..."
if command -v curl &> /dev/null; then
sudo curl -sL https://github.com/mikefarah/yq/releases/download/v4.35.1/yq_linux_amd64 -o /usr/local/bin/yq
else
sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.35.1/yq_linux_amd64
fi
sudo chmod +x /usr/local/bin/yq
fi
if command -v yq &> /dev/null; then
echo "yq installed successfully"
else
echo "Error: Failed to install yq, please install manually!"
exit 1
fi
fi
# Create config directory if not exists
mkdir -p /home/hermes/.hermes
# Create default config if config file doesn't exist
if [ ! -f "$CONFIG_PATH" ]; then
echo "Config file not found, creating default config..."
cat > "$CONFIG_PATH" << 'EOFCONFIG'
model:
default: ""
base_url: ""
api_key: ""
provider: custom
EOFCONFIG
fi
# Update config using Python script (compatible with all environments)
echo ""
echo "Starting configuration update..."
python3 -c "
import yaml
import sys
config_path = '$CONFIG_PATH'
model_name = '$MODEL_NAME'
api_base_url = '$API_BASE_URL'
api_key = '$API_KEY'
with open(config_path, 'r') as f:
config = yaml.safe_load(f)
if 'model' not in config:
config['model'] = {}
config['model']['default'] = model_name
config['model']['base_url'] = api_base_url
config['model']['api_key'] = api_key
config['model']['provider'] = 'custom'
with open(config_path, 'w') as f:
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
print(' Updated model.default:', model_name)
print(' Updated model.base_url:', api_base_url)
print(' Updated model.api_key:', api_key[:8] + '****')
"
echo ""
echo "Configuration update completed!"
# Verify configuration
echo ""
echo "Configuration verification:"
echo " model.default: $(grep "^ default:" "$CONFIG_PATH" | sed 's/ default: //')"
echo " model.base_url: $(grep "^ base_url:" "$CONFIG_PATH" | sed 's/ base_url: //')"
echo " model.api_key: $(grep "^ api_key:" "$CONFIG_PATH" | sed 's/ api_key: //' | cut -c1-8)****"
echo ""
echo "=== Configuration Completed ==="
echo ""
echo "Tip: Configuration updated, please restart Hermes service manually to apply changes"
echo " Recommended: hermes start or systemctl restart hermes"
'''
},
"install_channel": {
"name": "Hermes-Channel-Install",
"type": "SHELL",
"description": "Configure bot channels on Hermes instance (Feishu/WeCom)",
"risk_level": "MEDIUM",
"content": '''#!/bin/bash
# Hermes Bot Channel Configuration Script
BOT_PLATFORM='${bot_platform}'
FEISHU_APP_ID='${feishu_app_id}'
FEISHU_APP_SECRET='${feishu_app_secret}'
WECOM_BOT_ID='${wecom_bot_id}'
WECOM_SECRET='${wecom_secret}'
ENV_PATH='/home/hermes/.hermes/.env'
echo "⚙️ Configuring bot channel..."
echo " - Target Platform: $BOT_PLATFORM"
# Set environment variable function
set_env_variable() {
local env_file="$1"
local key="$2"
local value="$3"
if grep -q "^[#]\\?[[:space:]]*$key=" "$env_file"; then
sed -i.bak "s/^[#]\\?[[:space:]]*$key=.*/$key=$value/" "$env_file"
rm -f "$env_file.bak"
else
echo "" >> "$env_file"
echo "# Auto injected by setup script" >> "$env_file"
echo "$key=$value" >> "$env_file"
fi
}
# Configure based on platform type
if [ "$BOT_PLATFORM" = "feishu" ]; then
echo "Configuring Feishu channel..."
set_env_variable "$ENV_PATH" "FEISHU_APP_ID" "$FEISHU_APP_ID"
set_env_variable "$ENV_PATH" "FEISHU_APP_SECRET" "$FEISHU_APP_SECRET"
set_env_variable "$ENV_PATH" "FEISHU_DOMAIN" "feishu"
set_env_variable "$ENV_PATH" "FEISHU_CONNECTION_MODE" "websocket"
set_env_variable "$ENV_PATH" "FEISHU_ALLOW_ALL_USERS" "true"
set_env_variable "$ENV_PATH" "FEISHU_ALLOWED_USERS" ""
set_env_variable "$ENV_PATH" "FEISHU_GROUP_POLICY" "open"
set_env_variable "$ENV_PATH" "GATEWAY_ALLOW_ALL_USERS" "true"
echo "✅ Feishu configuration written successfully"
elif [ "$BOT_PLATFORM" = "wecom" ]; then
echo "Configuring WeCom channel..."
set_env_variable "$ENV_PATH" "WECOM_BOT_ID" "$WECOM_BOT_ID"
set_env_variable "$ENV_PATH" "WECOM_SECRET" "$WECOM_SECRET"
set_env_variable "$ENV_PATH" "GATEWAY_ALLOW_ALL_USERS" "true"
echo "✅ WeCom configuration written successfully"
fi
echo "✅ $ENV_PATH updated successfully!"
echo ""
echo "Tip: Configuration updated, please restart Hermes service manually to apply changes"
echo " Recommended: hermes start or systemctl restart hermes"
'''
},
"restart_gateway": {
"name": "Hermes-Gateway-Restart",
"type": "SHELL",
"description": "Restart Hermes gateway service",
"risk_level": "LOW",
"content": '''#!/bin/bash
# Hermes Gateway Restart Script
echo "=== Hermes Gateway Restart ==="
# Switch to hermes user and execute restart command
su - hermes -c "hermes gateway restart"
if [ $? -eq 0 ]; then
echo "✓ Hermes gateway restarted successfully"
else
echo "✗ Hermes gateway restart failed"
exit 1
fi
'''
}
}
def install_maas_models_remote(
resource_id: str,
region_id: str,
api_key: str = "",
model_name: str = "",
api_base_url: str = "https://api.modelarts-maas.com/v2",
timeout: int = 600,
execute_user: str = "root",
ak: str = "",
sk: str = "",
security_token: str = None,
coc_region: str = None
) -> dict[str, Any]:
"""
Configure ModelArts large model on remote L instance via COC
Parameters:
resource_id: L Instance resource ID
region_id: L Instance region
api_key: ModelArts API Key
model_name: Large model name (e.g.: deepseek-v3.2, qwen-plus, glm-4)
api_base_url: API Base URL, default: https://api.modelarts-maas.com/v2
timeout: Execution timeout in seconds, default 600
execute_user: Execute user, default root
ak: Huawei Cloud AK (supports both long-term and temporary AK)
sk: Huawei Cloud SK (supports both long-term and temporary SK)
security_token: Security token for temporary credentials (optional, only required for temporary AK/SK)
coc_region: COC region (optional, default cn-north-4)
Returns:
{
"ok": True,
"text": "Script execution started: SCT2023083109562601af694bf",
"result": {...},
"error": None
}
"""
if not ak or not sk:
return {
"ok": False,
"text": "Credentials not configured",
"result": None,
"error": {
"code": "CONFIG_ERROR",
"message": "ak and sk are required parameters"
}
}
import time
script_info = HERMES_SCRIPT_TEMPLATES["install_maas"]
# Replace variables in template
content = script_info["content"]
content = content.replace("${api_key}", api_key if api_key else "")
content = content.replace("${model_name}", model_name if model_name else "")
content = content.replace("${api_base_url}", api_base_url if api_base_url else "https://api.modelarts-maas.com/v2")
create_result = create_script(
name=f"{script_info['name']}-{int(time.time())}",
script_type=script_info["type"],
content=content,
description=script_info["description"],
ak=ak,
sk=sk,
security_token=security_token,
region=coc_region,
risk_level=script_info["risk_level"]
)
if not create_result.get("ok"):
return create_result
script_uuid = create_result.get("result", {}).get("script_uuid")
if not script_uuid:
# Compatible with older response format
result_data = create_result.get("result")
if hasattr(result_data, 'data'):
script_uuid = result_data.data
target_instances = [{
"resource_id": resource_id,
"region_id": region_id,
"provider": "HCSS",
"type": "L-INSTANCE"
}]
execute_result = execute_script(
script_uuid=script_uuid,
execute_user=execute_user,
timeout=timeout,
success_rate=100.0,
target_instances=target_instances,
ak=ak,
sk=sk,
security_token=security_token,
region=coc_region,
rotation_strategy="CONTINUE"
)
return execute_result
def install_channel_remote(
resource_id: str,
region_id: str,
bot_platform: str = "",
feishu_app_id: str = "",
feishu_app_secret: str = "",
wecom_bot_id: str = "",
wecom_secret: str = "",
timeout: int = 600,
execute_user: str = "root",
ak: str = "",
sk: str = "",
security_token: str = None,
coc_region: str = None
) -> dict[str, Any]:
"""
Configure bot channel on remote L instance via COC
Parameters:
resource_id: L Instance resource ID
region_id: L Instance region
bot_platform: Bot platform: feishu or wecom
feishu_app_id: Feishu App ID (required when feishu platform is selected)
feishu_app_secret: Feishu App Secret (required when feishu platform is selected)
wecom_bot_id: WeCom Bot ID (required when wecom platform is selected)
wecom_secret: WeCom Secret (required when wecom platform is selected)
timeout: Execution timeout in seconds, default 600
execute_user: Execute user, default root
ak: Huawei Cloud AK (supports both long-term and temporary AK)
sk: Huawei Cloud SK (supports both long-term and temporary SK)
security_token: Security token for temporary credentials (optional, only required for temporary AK/SK)
coc_region: COC region (optional, default cn-north-4)
Returns:
{
"ok": True,
"text": "Script execution started: SCT2023083109562601af694bf",
"result": {...},
"error": None
}
"""
if not ak or not sk:
return {
"ok": False,
"text": "Credentials not configured",
"result": None,
"error": {
"code": "CONFIG_ERROR",
"message": "ak and sk are required parameters"
}
}
import time
script_info = HERMES_SCRIPT_TEMPLATES["install_channel"]
# Replace variables in template
content = script_info["content"]
content = content.replace("${bot_platform}", bot_platform if bot_platform else "")
content = content.replace("${feishu_app_id}", feishu_app_id if feishu_app_id else "")
content = content.replace("${feishu_app_secret}", feishu_app_secret if feishu_app_secret else "")
content = content.replace("${wecom_bot_id}", wecom_bot_id if wecom_bot_id else "")
content = content.replace("${wecom_secret}", wecom_secret if wecom_secret else "")
create_result = create_script(
name=f"{script_info['name']}-{int(time.time())}",
script_type=script_info["type"],
content=content,
description=script_info["description"],
ak=ak,
sk=sk,
security_token=security_token,
region=coc_region,
risk_level=script_info["risk_level"]
)
if not create_result.get("ok"):
return create_result
script_uuid = create_result.get("result", {}).get("script_uuid")
if not script_uuid:
# Compatible with older response format
result_data = create_result.get("result")
if hasattr(result_data, 'data'):
script_uuid = result_data.data
target_instances = [{
"resource_id": resource_id,
"region_id": region_id,
"provider": "HCSS",
"type": "L-INSTANCE"
}]
execute_result = execute_script(
script_uuid=script_uuid,
execute_user=execute_user,
timeout=timeout,
success_rate=100.0,
target_instances=target_instances,
ak=ak,
sk=sk,
security_token=security_token,
region=coc_region,
rotation_strategy="CONTINUE"
)
return execute_result
def restart_gateway_remote(
resource_id: str,
region_id: str,
timeout: int = 120,
execute_user: str = "root",
ak: str = "",
sk: str = "",
security_token: str = None,
coc_region: str = None
) -> dict[str, Any]:
"""
Restart Hermes gateway on remote L instance via COC
Parameters:
resource_id: L Instance resource ID
region_id: L Instance region
timeout: Execution timeout in seconds, default 120
execute_user: Execute user, default root
ak: Huawei Cloud AK (supports both long-term and temporary AK)
sk: Huawei Cloud SK (supports both long-term and temporary SK)
security_token: Security token for temporary credentials (optional, only required for temporary AK/SK)
coc_region: COC region (optional, default cn-north-4)
Returns:
{
"ok": True,
"text": "Script execution started: SCT2023083109562601af694bf",
"result": {...},
"error": None
}
"""
if not ak or not sk:
return {
"ok": False,
"text": "Credentials not configured",
"result": None,
"error": {
"code": "CONFIG_ERROR",
"message": "ak and sk are required parameters"
}
}
import time
script_info = HERMES_SCRIPT_TEMPLATES["restart_gateway"]
create_result = create_script(
name=f"{script_info['name']}-{int(time.time())}",
script_type=script_info["type"],
content=script_info["content"],
description=script_info["description"],
ak=ak,
sk=sk,
security_token=security_token,
region=coc_region,
risk_level=script_info["risk_level"]
)
if not create_result.get("ok"):
return create_result
script_uuid = create_result.get("result", {}).get("script_uuid")
if not script_uuid:
result_data = create_result.get("result")
if hasattr(result_data, 'data'):
script_uuid = result_data.data
target_instances = [{
"resource_id": resource_id,
"region_id": region_id,
"provider": "HCSS",
"type": "L-INSTANCE"
}]
execute_result = execute_script(
script_uuid=script_uuid,
execute_user=execute_user,
timeout=timeout,
success_rate=100.0,
target_instances=target_instances,
ak=ak,
sk=sk,
security_token=security_token,
region=coc_region,
rotation_strategy="CONTINUE"
)
return execute_result
def get_valid_coc_regions() -> list[str]:
"""Dynamically get COC service supported regions from SDK"""
from huaweicloudsdkcoc.v1.region.coc_region import CocRegion
return list(CocRegion.static_fields.keys())
def get_config(ak, sk, region=None) -> tuple[str, str, str]:
"""Get AK/SK and region information (parameter passing)"""
if not ak:
raise ValueError("ak is required parameter")
if not sk:
raise ValueError("sk is required parameter")
# COC region: Use passed region first, default to cn-north-4 if not provided
# Note: COC region is different from target instance region, COC service only supports limited regions
if not region:
region = "cn-north-4"
valid_regions = get_valid_coc_regions()
if region not in valid_regions:
raise ValueError(f"COC region must be one of {valid_regions}. Note: COC region is different from target instance region. Target instance region is specified by --region-id parameter")
return ak, sk, region
def get_client(ak, sk, security_token, region=None) -> CocClient:
"""Create and return COC client (parameter passing)
Args:
ak: Huawei Cloud temporary AK
sk: Huawei Cloud temporary SK
security_token: Security token for temporary credentials (required)
region: COC region (optional, default cn-north-4)
"""
_, _, coc_region = get_config(ak, sk, region)
credentials = GlobalCredentials(ak, sk).with_security_token(security_token)
client = CocClient.new_builder() \
.with_credentials(credentials) \
.with_region(CocRegion.value_of(coc_region)) \
.build()
return client
def create_script(
name: str,
script_type: str,
content: str,
description: str,
ak: str,
sk: str,
security_token: str = None,
region: str = None,
risk_level: str = "LOW",
version: str = "1.0.0",
script_params: Optional[List[Dict[str, Any]]] = None,
) -> dict[str, Any]:
"""Create custom script in COC"""
if not name:
return _error("INPUT_ERROR", "name is required")
if script_type not in VALID_SCRIPT_TYPES:
return _error("INPUT_ERROR", f"script_type must be one of {VALID_SCRIPT_TYPES}")
if not content:
return _error("INPUT_ERROR", "content is required")
if not description:
return _error("INPUT_ERROR", "description is required")
if risk_level not in VALID_RISK_LEVELS:
return _error("INPUT_ERROR", f"risk_level must be one of {VALID_RISK_LEVELS}")
if not ak or not sk:
return _error("CONFIG_ERROR", "ak and sk are required")
try:
client = get_client(ak, sk, security_token, region)
except ValueError as e:
return _error("CONFIG_ERROR", str(e))
try:
print(f" Creating script: {name}")
request = CreateScriptRequest()
properties = ScriptPropertiesModel(
risk_level=risk_level,
version=version
)
request.body = AddScriptModel(
name=name,
type=script_type,
content=content,
description=description,
properties=properties
)
response = client.create_script(request)
script_uuid = ""
if hasattr(response, 'data'):
script_uuid = response.data
elif hasattr(response, 'script_uuid'):
script_uuid = response.script_uuid
else:
script_uuid = str(response)
print(f" ✓ Script created successfully: {script_uuid}")
return {
"ok": True,
"text": f"Script created successfully: {script_uuid}",
"result": {"script_uuid": script_uuid},
"error": None,
}
except exceptions.ClientRequestException as e:
return _error("API_ERROR", f"{e.error_code}: {e.error_msg}")
except Exception as e:
return _error("UNKNOWN_ERROR", str(e))
def execute_script(
script_uuid: str,
execute_user: str,
timeout: int,
success_rate: float,
target_instances: List[Dict[str, str]],
ak: str,
sk: str,
security_token: str = None,
region: str = None,
rotation_strategy: str = "CONTINUE",
wait_for_completion: bool = False,
) -> dict[str, Any]:
"""
Execute custom script on target instances
Parameters:
script_uuid: Script UUID to execute
execute_user: User to execute script (e.g. root)
timeout: Execution timeout in seconds (5 < timeout < 1800)
success_rate: Success rate (supports one decimal place, e.g. 1 or 100)
target_instances: List of target instances, each containing:
- resource_id: Instance ID (required)
- region_id: Server region (required)
- provider: Resource provider (not required for ECS, default "HCSS" for L Instance)
- type: Resource type (not required for ECS, default "L-INSTANCE" for L Instance)
ak: Huawei Cloud AK (supports both long-term and temporary AK)
sk: Huawei Cloud SK (supports both long-term and temporary SK)
security_token: Security token for temporary credentials (optional, only required for temporary AK/SK)
region: COC region (optional, default cn-north-4)
rotation_strategy: Rotation strategy (CONTINUE/STOP), default CONTINUE
wait_for_completion: Whether to wait for completion and get logs, default True
Returns:
{
"ok": True,
"text": "Script execution successful: SCT2023083109562601af694bf",
"result": {
"execute_uuid": "SCT2023083109562601af694bf",
"status": "FINISHED",
"output": "Script execution output log...",
"error": "Error message (if any)"
},
"error": None
}
"""
if not script_uuid:
return _error("INPUT_ERROR", "script_uuid is required")
if not execute_user:
return _error("INPUT_ERROR", "execute_user is required")
if timeout <= 5 or timeout >= 1800:
return _error("INPUT_ERROR", "timeout must be between 5 and 1800 seconds")
if success_rate < 0 or success_rate > 100:
return _error("INPUT_ERROR", "success_rate must be between 0 and 100")
if not target_instances or not isinstance(target_instances, list):
return _error("INPUT_ERROR", "target_instances is required")
if rotation_strategy not in VALID_ROTATION_STRATEGIES:
return _error("INPUT_ERROR", f"rotation_strategy must be one of {VALID_ROTATION_STRATEGIES}")
if not ak or not sk:
return _error("CONFIG_ERROR", "ak and sk are required")
try:
client = get_client(ak, sk, security_token, region)
except ValueError as e:
return _error("CONFIG_ERROR", str(e))
try:
import time
request = ExecuteScriptRequest()
request.script_uuid = script_uuid
execute_param = ScriptExecuteParam(
timeout=timeout,
success_rate=success_rate,
execute_user=execute_user
)
listTargetInstancesExecuteBatches = []
for instance_info in target_instances:
instance_kwargs = {
"resource_id": instance_info.get("resource_id", ""),
"region_id": instance_info.get("region_id", "cn-north-4")
}
provider = instance_info.get("provider")
instance_type = instance_info.get("type")
if provider:
instance_kwargs["provider"] = provider
if instance_type:
instance_kwargs["type"] = instance_type
instance = ExecuteResourceInstance(**instance_kwargs)
listTargetInstancesExecuteBatches.append(instance)
listExecuteBatchesbody = [
ExecuteInstancesBatchInfo(
batch_index=1,
target_instances=listTargetInstancesExecuteBatches,
rotation_strategy=rotation_strategy
)
]
request.body = ScriptExecuteModel(
execute_batches=listExecuteBatchesbody,
execute_param=execute_param
)
# Execute script API call
response = client.execute_script(request)
execute_uuid = ""
if hasattr(response, 'data'):
execute_uuid = response.data
elif hasattr(response, 'execute_uuid'):
execute_uuid = response.execute_uuid
else:
execute_uuid = str(response)
# Output execution UUID immediately after API call success to notify user request is submitted
print(f"\n✓ Script execution request submitted")
print(f" Execution ID: {execute_uuid}")
if not wait_for_completion:
return {
"ok": True,
"text": f"Script execution started: {execute_uuid}",
"result": {"execute_uuid": execute_uuid},
"error": None,
}
print(f" Waiting for script execution to complete...")
max_wait_time = timeout + 60
wait_interval = 5
elapsed_time = 0
last_status = ""
while elapsed_time < max_wait_time:
query_result = coc_query_execution(execute_uuid, ak, sk, security_token, region)
data = query_result.get("data", {})
if not data:
# Query failed, output error message and continue waiting
error_msg = query_result.get("error", {}).get("message", "query failed")
print(f" Failed to query status: {error_msg}, retrying...")
time.sleep(wait_interval)
elapsed_time += wait_interval
continue
# Extract status and output from new format
instances = data.get("execute_instances", [])
if instances:
status = instances[0].get("status", "")
output = instances[0].get("message", "")
error = output if status == "ABNORMAL" else ""
else:
status = data.get("status", "")
output = data.get("message", "")
error = output if status == "ABNORMAL" else ""
# Output progress when status changes
if status != last_status:
last_status = status
print(f" Execution status: {status}")
# Output heartbeat every 30 seconds to keep user informed
if elapsed_time % 30 == 0:
print(f" Waiting... ({elapsed_time}/{max_wait_time} seconds)")
if status in ["SUCCESS", "FAILED", "TIMEOUT", "CANCELLED", "FINISHED", "ABNORMAL"]:
result_data = {
"execute_uuid": execute_uuid,
"status": status,
"output": output,
"error": error
}
if status == "FINISHED":
print(f" Execution completed: SUCCESS")
return {
"ok": True,
"text": f"Script execution successful: {execute_uuid}",
"result": result_data,
"error": None,
}
else:
print(f" Execution completed: {status}")
error_msg = f"Script execution failed, status: {status}"
if error:
error_msg += f", error: {error}"
if output:
error_msg += f", output: {output}"
return {
"ok": False,
"text": error_msg,
"result": result_data,
"error": {"code": "EXECUTE_FAILED", "message": error_msg}
}
time.sleep(wait_interval)
elapsed_time += wait_interval
print(f" Execution timeout (waiting exceeded {max_wait_time} seconds)")
return {
"ok": False,
"text": f"Script execution timeout (waiting exceeded {max_wait_time} seconds)",
"result": {"execute_uuid": execute_uuid},
"error": {"code": "TIMEOUT", "message": "Script execution timeout"}
}
except exceptions.ClientRequestException as e:
return _error("API_ERROR", f"{e.error_code}: {e.error_msg}")
except Exception as e:
return _error("UNKNOWN_ERROR", str(e))
def coc_query_execution(execute_uuid: str, ak: str = None, sk: str = None, security_token: str = None, region: str = None) -> dict[str, Any]:
"""
Query script execution status by execute UUID.
API: GET /v1/job/script/orders/{execute_uuid}/batches/1
Parameters:
execute_uuid: Execution UUID (format: SCT2023083109562601af694bf)
ak: Huawei Cloud AK (supports both long-term and temporary AK)
sk: Huawei Cloud SK (supports both long-term and temporary SK)
security_token: Security token for temporary credentials (optional, only required for temporary AK/SK)
region: COC region (optional, default cn-north-4)
Returns:
{
"data": {
"batch_index": 1,
"total_instances": 1,
"execute_instances": [{
"id": 40304358,
"cmd_uuid": "xxx",
"job_sign": null,
"status": "FINISHED", # or "ABNORMAL", "RUNNING", etc.
"message": "Execution log...",
"gmt_created": 1779934038727,
"gmt_finished": 1779934107670,
"execute_costs": 68943,
"target_instance": {
"resource_id": "xxx",
"agent_sn": "xxx",
"agent_status": null,
"agent_version": "1.1.8",
"region_id": "cn-north-4",
"project_id": null,
"properties": {
"host_name": "dify-test-001",
"fixed_ip": null,
"floating_ip": null,
"region_id": "cn-north-4",
"zone_id": null,
"application": null,
"group": null,
"project_id": null
},
"custom_attributes": null,
"provider": "hcss",
"type": "l-instance"
}
}]
}
}
"""
if not execute_uuid:
return _error("INPUT_ERROR", "execute_uuid is required")
if not ak or not sk:
return _error("CONFIG_ERROR", "ak and sk are required")
# 固定参数
batch_index = 1
limit = 50
if not region:
region = "cn-north-4"
try:
client = get_client(ak, sk, security_token, region)
except ValueError as e:
return _error("CONFIG_ERROR", str(e))
try:
from huaweicloudsdkcoc.v1 import GetScriptJobBatchRequest
request = GetScriptJobBatchRequest()
request.batch_index = batch_index
request.execute_uuid = execute_uuid
request.limit = limit
response = client.get_script_job_batch(request)
result_dict = {}
if hasattr(response, 'data') and response.data is not None:
data = response.data
if hasattr(data, 'batch_index'):
result_dict['batch_index'] = data.batch_index
if hasattr(data, 'total_instances'):
result_dict['total_instances'] = data.total_instances
if hasattr(data, 'execute_instances') and data.execute_instances:
instances = []
for instance in data.execute_instances:
instance_dict = {}
if hasattr(instance, 'id'):
instance_dict['id'] = instance.id
if hasattr(instance, 'cmd_uuid'):
instance_dict['cmd_uuid'] = instance.cmd_uuid
if hasattr(instance, 'status'):
instance_dict['status'] = instance.status
if hasattr(instance, 'message'):
instance_dict['message'] = instance.message
if hasattr(instance, 'execute_costs'):
instance_dict['execute_costs'] = instance.execute_costs
if hasattr(instance, 'gmt_created'):
instance_dict['gmt_created'] = instance.gmt_created
if hasattr(instance, 'gmt_finished'):
instance_dict['gmt_finished'] = instance.gmt_finished
if hasattr(instance, 'target_instance') and instance.target_instance:
target = instance.target_instance
target_dict = {}
if hasattr(target, 'resource_id'):
target_dict['resource_id'] = target.resource_id
if hasattr(target, 'agent_sn'):
target_dict['agent_sn'] = target.agent_sn
if hasattr(target, 'agent_status'):
target_dict['agent_status'] = target.agent_status
if hasattr(target, 'agent_version'):
target_dict['agent_version'] = target.agent_version
if hasattr(target, 'region_id'):
target_dict['region_id'] = target.region_id
if hasattr(target, 'project_id'):
target_dict['project_id'] = target.project_id
if hasattr(target, 'properties') and target.properties:
props = target.properties
props_dict = {}
if hasattr(props, 'host_name'):
props_dict['host_name'] = props.host_name
if hasattr(props, 'fixed_ip'):
props_dict['fixed_ip'] = props.fixed_ip
if hasattr(props, 'floating_ip'):
props_dict['floating_ip'] = props.floating_ip
if hasattr(props, 'region_id'):
props_dict['region_id'] = props.region_id
if hasattr(props, 'zone_id'):
props_dict['zone_id'] = props.zone_id
if hasattr(props, 'application'):
props_dict['application'] = props.application
if hasattr(props, 'group'):
props_dict['group'] = props.group
if hasattr(props, 'project_id'):
props_dict['project_id'] = props.project_id
target_dict['properties'] = props_dict
if hasattr(target, 'custom_attributes'):
target_dict['custom_attributes'] = target.custom_attributes
if hasattr(target, 'provider'):
target_dict['provider'] = target.provider
if hasattr(target, 'type'):
target_dict['type'] = target.type
instance_dict['target_instance'] = target_dict
if hasattr(instance, 'job_sign'):
instance_dict['job_sign'] = instance.job_sign
instances.append(instance_dict)
result_dict['execute_instances'] = instances
else:
result_dict['status'] = 'UNKNOWN'
result_dict['message'] = 'Execution record not found or empty'
return {
"data": result_dict
}
except exceptions.ClientRequestException as e:
return _error("API_ERROR", f"{e.error_code}: {e.error_msg}")
except Exception as e:
return _error("UNKNOWN_ERROR", str(e))
def get_script_detail(script_uuid: str, ak: str, sk: str, security_token: str = None, region: str = None) -> dict[str, Any]:
"""Get script details"""
if not script_uuid:
return _error("INPUT_ERROR", "script_uuid is required")
if not ak or not sk:
return _error("CONFIG_ERROR", "ak and sk are required")
try:
client = get_client(ak, sk, security_token, region)
except ValueError as e:
return _error("CONFIG_ERROR", str(e))
try:
request = GetScriptRequest()
request.script_uuid = script_uuid
response = client.get_script(request)
script_data = {}
if hasattr(response, 'data'):
data = response.data
script_data = {
"script_uuid": data.script_uuid if hasattr(data, 'script_uuid') else "",
"name": data.name if hasattr(data, 'name') else "",
"type": data.type if hasattr(data, 'type') else "",
"content": data.content if hasattr(data, 'content') else "",
"description": data.description if hasattr(data, 'description') else "",
"risk_level": data.risk_level if hasattr(data, 'risk_level') else "",
"version": data.version if hasattr(data, 'version') else "",
"create_time": data.create_time if hasattr(data, 'create_time') else ""
}
return {
"ok": True,
"text": "Script details retrieved",
"result": script_data,
"error": None,
}
except exceptions.ClientRequestException as e:
return _error("API_ERROR", f"{e.error_code}: {e.error_msg}")
except Exception as e:
return _error("UNKNOWN_ERROR", str(e))
def list_scripts(ak: str, sk: str, security_token: str = None, region: str = None, page: int = 1, limit: int = 10) -> dict[str, Any]:
"""List scripts"""
if not ak or not sk:
return _error("CONFIG_ERROR", "ak and sk are required")
try:
client = get_client(ak, sk, security_token, region)
except ValueError as e:
return _error("CONFIG_ERROR", str(e))
try:
request = ListScriptsRequest()
request.page = page
request.limit = limit
response = client.list_scripts(request)
scripts = []
total = 0
if hasattr(response, 'data'):
data = response.data
if hasattr(data, 'data'):
for script in data.data:
risk_level = ""
version = ""
if hasattr(script, 'properties') and script.properties:
props = script.properties
risk_level = props.risk_level if hasattr(props, 'risk_level') else ""
version = props.version if hasattr(props, 'version') else ""
scripts.append({
"script_uuid": script.script_uuid if hasattr(script, 'script_uuid') else "",
"name": script.name if hasattr(script, 'name') else "",
"type": script.type if hasattr(script, 'type') else "",
"description": script.description if hasattr(script, 'description') else "",
"risk_level": risk_level,
"version": version,
"create_time": script.gmt_created if hasattr(script, 'gmt_created') else ""
})
if hasattr(data, 'total'):
total = data.total
return {
"ok": True,
"text": f"Found {total} scripts",
"result": {
"scripts": scripts,
"total": total
},
"error": None,
}
except exceptions.ClientRequestException as e:
return _error("API_ERROR", f"{e.error_code}: {e.error_msg}")
except Exception as e:
return _error("UNKNOWN_ERROR", str(e))
def get_hermes_script_content() -> str:
"""Get built-in Hermes configuration script content"""
script_content = """#!/bin/bash
# ==================== Default Configuration ====================
DEFAULT_BASE_URL="https://api.modelarts-maas.com/v2"
DEFAULT_CONFIG_PATH="/home/hermes/.hermes/config.yaml"
DEFAULT_ENV_PATH="/home/hermes/.hermes/.env"
# ==================== Display Help Information ====================
show_usage() {
echo "Hermes Configuration Tool (Feishu/WeCom compatible)"
echo ""
echo "Usage: $0 --api_key <API_KEY> --model_name <MODEL_NAME> --bot_platform <feishu|wecom> [options]"
echo ""
echo "Required parameters:"
echo " --api_key Large model API Key"
echo " --model_name Large model name (e.g.: deepseek-v3.2, qwen-plus, glm-4)"
echo " --bot_platform Bot platform: feishu or wecom"
echo ""
echo "Optional parameters:"
echo " --api_base_url API Base URL (default: $DEFAULT_BASE_URL)"
echo " --feishu_app_id Feishu App ID"
echo " --feishu_app_secret Feishu App Secret"
echo " --wecom_bot_id WeCom Bot ID"
echo " --wecom_secret WeCom Secret"
echo " --config_path config.yaml path (default: $DEFAULT_CONFIG_PATH)"
echo " --env_path .env file path (default: $DEFAULT_ENV_PATH)"
echo ""
}
# ==================== Initialize Variables ====================
API_KEY="${api_key}"
MODEL_NAME="${model_name}"
API_BASE_URL="$DEFAULT_BASE_URL"
BOT_PLATFORM="${bot_platform}"
FEISHU_APP_ID="${feishu_app_id}"
FEISHU_APP_SECRET="${feishu_app_secret}"
WECOM_BOT_ID="${wecom_bot_id}"
WECOM_SECRET="${wecom_secret}"
CONFIG_PATH="$DEFAULT_CONFIG_PATH"
ENV_PATH="$DEFAULT_ENV_PATH"
# ==================== Parse Parameters ====================
while [ $# -gt 0 ]
do
case "$1" in
--api_key)
API_KEY="$2"
shift
;;
--model_name)
MODEL_NAME="$2"
shift
;;
--api_base_url)
API_BASE_URL="$2"
shift
;;
--bot_platform)
BOT_PLATFORM="$2"
shift
;;
--feishu_app_id)
FEISHU_APP_ID="$2"
shift
;;
--feishu_app_secret)
FEISHU_APP_SECRET="$2"
shift
;;
--wecom_bot_id)
WECOM_BOT_ID="$2"
shift
;;
--wecom_secret)
WECOM_SECRET="$2"
shift
;;
--config_path)
CONFIG_PATH="$2"
shift
;;
--env_path)
ENV_PATH="$2"
shift
;;
-h|--help)
show_usage
exit 0
;;
*)
echo "Error: Unknown parameter $1"
show_usage
exit 1
;;
esac
shift
done
# ==================== Validate Parameters ====================
if [ -z "$API_KEY" ]; then
echo "❌ Error: --api_key parameter is required"
show_usage
exit 1
fi
if [ -z "$MODEL_NAME" ]; then
echo "❌ Error: --model_name parameter is required"
show_usage
exit 1
fi
if [ -z "$BOT_PLATFORM" ]; then
echo "❌ Error: --bot_platform parameter is required"
show_usage
exit 1
fi
if [ "$BOT_PLATFORM" != "feishu" ] && [ "$BOT_PLATFORM" != "wecom" ]; then
echo "❌ Error: --bot_platform must be 'feishu' or 'wecom'"
show_usage
exit 1
fi
if [ "$BOT_PLATFORM" = "feishu" ]; then
if [ -z "$FEISHU_APP_ID" ] || [ -z "$FEISHU_APP_SECRET" ]; then
echo "❌ Error: When selecting Feishu, --feishu_app_id and --feishu_app_secret are required"
show_usage
exit 1
fi
fi
if [ "$BOT_PLATFORM" = "wecom" ]; then
if [ -z "$WECOM_BOT_ID" ] || [ -z "$WECOM_SECRET" ]; then
echo "❌ Error: When selecting WeCom, --wecom_bot_id and --wecom_secret are required"
show_usage
exit 1
fi
fi
# ==================== Validate Files ====================
if [ ! -f "$CONFIG_PATH" ]; then
echo "❌ Cannot find $CONFIG_PATH, please check the path!"
exit 1
fi
if [ ! -f "$ENV_PATH" ]; then
echo "❌ Cannot find $ENV_PATH, please check the path!"
exit 1
fi
# ==================== Helper Functions ====================
set_env_variable() {
local env_file="$1"
local key="$2"
local value="$3"
if grep -q "^[#]\\?[[:space:]]*$key=" "$env_file"; then
sed -i.bak "s/^[#]\\?[[:space:]]*$key=.*/$key=$value/" "$env_file"
rm -f "$env_file.bak"
else
echo "" >> "$env_file"
echo "# Auto injected by setup script" >> "$env_file"
echo "$key=$value" >> "$env_file"
fi
}
# ==================== Update config.yaml ====================
update_config_yaml() {
echo "⚙️ Updating $CONFIG_PATH ..."
# Use Python script to modify config file
python3 -c "
import yaml
config_path = '$CONFIG_PATH'
model_name = '$MODEL_NAME'
api_base_url = '$API_BASE_URL'
api_key = '$API_KEY'
with open(config_path, 'r') as f:
config = yaml.safe_load(f)
if 'model' not in config:
config['model'] = {}
config['model']['default'] = model_name
config['model']['base_url'] = api_base_url
config['model']['api_key'] = api_key
config['model']['provider'] = 'custom'
if 'custom_providers' in config:
del config['custom_providers']
provider_host = api_base_url.replace('https://', '').replace('http://', '').split('/')[0]
provider_name = provider_host[0].upper() + provider_host[1:] if provider_host else 'Custom'
config['custom_providers'] = [{
'name': provider_name,
'base_url': api_base_url,
'api_key': api_key,
'model': model_name
}]
with open(config_path, 'w') as f:
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
print('✅ config.yaml updated successfully!')
"
}
# ==================== Update .env File ====================
update_env_file() {
echo "⚙️ Updating $ENV_PATH ..."
if [ "$BOT_PLATFORM" = "feishu" ]; then
set_env_variable "$ENV_PATH" "FEISHU_APP_ID" "$FEISHU_APP_ID"
set_env_variable "$ENV_PATH" "FEISHU_APP_SECRET" "$FEISHU_APP_SECRET"
set_env_variable "$ENV_PATH" "FEISHU_DOMAIN" "feishu"
set_env_variable "$ENV_PATH" "FEISHU_CONNECTION_MODE" "websocket"
set_env_variable "$ENV_PATH" "FEISHU_ALLOW_ALL_USERS" "true"
set_env_variable "$ENV_PATH" "FEISHU_ALLOWED_USERS" ""
set_env_variable "$ENV_PATH" "FEISHU_GROUP_POLICY" "open"
set_env_variable "$ENV_PATH" "GATEWAY_ALLOW_ALL_USERS" "true"
echo "✅ Feishu configuration written successfully."
elif [ "$BOT_PLATFORM" = "wecom" ]; then
set_env_variable "$ENV_PATH" "WECOM_BOT_ID" "$WECOM_BOT_ID"
set_env_variable "$ENV_PATH" "WECOM_SECRET" "$WECOM_SECRET"
set_env_variable "$ENV_PATH" "GATEWAY_ALLOW_ALL_USERS" "true"
echo "✅ WeCom configuration written successfully."
fi
echo "✅ $ENV_PATH updated successfully!"
}
# ==================== Main Function ====================
main() {
echo "🚀 Starting Hermes configuration update..."
echo " - Target Model: $MODEL_NAME"
echo " - API Base URL: $API_BASE_URL"
echo " - Target Platform: $BOT_PLATFORM"
update_config_yaml
update_env_file
echo ""
echo "🎉 Hermes configuration completed successfully!"
}
main "$@"
"""
return script_content
def _error(code: str, message: str) -> dict:
"""Create error response"""
return {
"ok": False,
"text": "",
"result": None,
"error": {"code": code, "message": message},
}
def query_uniagent_status(
resource_id: str,
ak: str,
sk: str,
security_token: str = None
) -> dict[str, Any]:
"""
Query L instance UniAgent status via COC API
Args:
resource_id: L instance resource ID
ak: Huawei Cloud AK (supports both long-term and temporary AK)
sk: Huawei Cloud SK (supports both long-term and temporary SK)
security_token: Security token for temporary credentials (optional, only required for temporary AK/SK)
Returns:
{
"ok": True,
"text": "Query successful",
"result": {...},
"error": None
}
"""
if not resource_id:
return _error("INPUT_ERROR", "resource_id parameter is required")
if not ak or not sk:
return _error("CONFIG_ERROR", "Please provide AK and SK parameters. For temporary credentials, also provide security_token.")
region = os.environ.get("HUAWEICLOUD_REGION", "cn-north-4")
try:
from huaweicloudsdkcore.auth.credentials import GlobalCredentials
from huaweicloudsdkcore.signer.signer import Signer
from huaweicloudsdkcore.sdk_request import SdkRequest
from urllib.parse import urlparse
credentials = Credentials(ak, sk, security_token)
signer = Signer(credentials)
endpoint = "https://coc.myhuaweicloud.com/v1/resources"
query_params = {
"resource_id_list": resource_id,
"limit": "100",
"provider": "hcss",
"type": "l-instance"
}
url_with_params = endpoint + "?" + "&".join([f"{k}={v}" for k, v in query_params.items()])
parsed_url = urlparse(url_with_params)
request = SdkRequest()
request.method = "GET"
request.schema = parsed_url.scheme
request.host = parsed_url.hostname
request.resource_path = parsed_url.path
request.query_params = [[k, v] for k, v in query_params.items()]
request.header_params = {
"Content-Type": "application/json",
"Client-Request-Id": str(uuid.uuid4())
}
if security_token:
request.header_params["X-Security-Token"] = security_token
signed_request = signer.sign(request)
headers = {}
for key, value in signed_request.header_params.items():
if isinstance(value, bytes):
headers[key] = value.decode('iso-8859-1')
else:
headers[key] = str(value)
print(f"Request URL: {url_with_params}")
print(f"Request headers: {headers}")
resp = requests.request(
"GET",
url_with_params,
headers=headers,
verify=True
)
print(f"Response status code: {resp.status_code}")
print(f"Response content: {resp.text}")
if resp.status_code in [200, 202]:
response_data = resp.json()
return {
"ok": True,
"text": "UniAgent status query successful",
"result": response_data,
"error": None
}
else:
return {
"ok": False,
"text": f"Query failed: {resp.reason}",
"result": None,
"error": {
"code": str(resp.status_code),
"message": resp.text
}
}
except ImportError as e:
return _error("SDK_ERROR", f"Please install huaweicloudsdkcore: {str(e)}")
except Exception as e:
error_msg = str(e)
return _error("UNKNOWN_ERROR", error_msg)
#!/usr/bin/env python3
# coding: utf-8
"""
Huawei Cloud Flexus L Instance One-Click Hermes Deployment - Model Installation Module
Note: This module supports both long-term and temporary credentials.
- Long-term AK/SK: No security_token required
- Temporary AK/SK: Security token required
"""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from scripts.lib import install_maas_models_remote, DEFAULT_BASE_URL
from scripts.utils import prompt_for_input, REGION_IDS
def do_install_maas(args):
"""Execute ModelArts large model configuration
Args:
args: Command line argument object with the following attributes:
- resource_id: L instance resource ID (command line arg --resource-id)
- region_id: Region ID (command line arg --region-id)
- api_key: ModelArts API Key (command line arg --api-key)
- model_name: Large model name (command line arg --model-name)
- api_base_url: API Base URL (command line arg --api-base-url)
- timeout: Timeout duration (command line arg --timeout)
- execute_user: Execute user (command line arg --execute-user)
- ak: Huawei Cloud AK (supports both long-term and temporary AK) (command line arg --ak)
- sk: Huawei Cloud SK (supports both long-term and temporary SK) (command line arg --sk)
- security_token: Security token for temporary credentials (optional, only required for temporary AK/SK) (command line arg --security-token)
- non_interactive: Whether non-interactive mode (command line arg --non-interactive)
Returns:
None
"""
print("=" * 60)
print(" Hermes ModelArts Large Model Configuration")
print("=" * 60)
non_interactive = args.non_interactive if hasattr(args, 'non_interactive') else False
# Get credentials (from command line parameters)
ak = args.ak if hasattr(args, 'ak') and args.ak else None
sk = args.sk if hasattr(args, 'sk') and args.sk else None
security_token = args.security_token if hasattr(args, 'security_token') and args.security_token else None
# If credentials not provided, prompt interactively (skip in non-interactive mode)
if not ak or not sk:
print("\nHuawei Cloud credentials not configured, entering interactive configuration...")
print("Please configure Huawei Cloud credentials:")
print(" - Long-term AK/SK: No security_token required")
print(" - Temporary AK/SK: Security token required")
print("-" * 40)
ak = prompt_for_input("Huawei Cloud AK (HW_ACCESS_KEY)", required=True)
sk = prompt_for_input("Huawei Cloud SK (HW_SECRET_KEY)", required=True, hide_input=True)
security_token = prompt_for_input("Security Token (optional, only for temporary credentials)", required=False)
# Get parameters
resource_id = args.resource_id if hasattr(args, 'resource_id') and args.resource_id else None
region_id = args.region_id if hasattr(args, 'region_id') and args.region_id else None
api_key = args.api_key if hasattr(args, 'api_key') and args.api_key else ""
model_name = args.model_name if hasattr(args, 'model_name') and args.model_name else ""
api_base_url = args.api_base_url if hasattr(args, 'api_base_url') and args.api_base_url else DEFAULT_BASE_URL
timeout = args.timeout if hasattr(args, 'timeout') and args.timeout else 600
# Get parameters interactively (skip in non-interactive mode)
if not resource_id:
if non_interactive:
print("Error: Missing required parameter --resource-id")
return
resource_id = prompt_for_input("L Instance resource ID", required=True)
if not region_id:
if non_interactive:
region_id = "cn-north-4"
else:
region_id = prompt_for_input("Region ID", required=False, default="cn-north-4", choices=REGION_IDS)
if not api_key:
if non_interactive:
print("Error: Missing required parameter --api-key")
return
api_key = prompt_for_input("ModelArts API Key", required=True)
if not model_name:
if non_interactive:
print("Error: Missing required parameter --model-name")
return
print("\nAvailable model examples:")
print(" deepseek-v3.2, qwen-plus, glm-4")
model_name = prompt_for_input("Large model name", required=True)
if not api_base_url:
api_base_url = DEFAULT_BASE_URL
if not timeout:
timeout = 600
print(f"\nConfiguration:")
print(f" Resource ID: {resource_id}")
print(f" Region: {region_id}")
print(f" API Key: {api_key[:8]}****")
print(f" Model Name: {model_name}")
print(f" API Base URL: {api_base_url}")
print(f" Timeout: {timeout} seconds")
if not non_interactive:
confirm = prompt_for_input("Confirm configuration?", required=False, default="y", choices=["y", "n"])
if confirm.lower() != "y":
print("\nConfiguration cancelled")
return
print("\nStarting ModelArts large model configuration...")
result = install_maas_models_remote(resource_id, region_id, api_key, model_name, api_base_url, timeout, ak=ak, sk=sk, security_token=security_token, coc_region=region_id)
if result.get("ok"):
print(f"\n✓ {result['text']}")
if result.get("result"):
print(f" Execution ID: {result['result'].get('execute_uuid', 'Unknown')}")
print(f" Status: {result['result'].get('status', 'Unknown')}")
if result['result'].get('output'):
print(f"\n Execution Output:")
print(f" {result['result']['output']}")
if result['result'].get('error'):
print(f"\n Error Message:")
print(f" {result['result']['error']}")
else:
print(f"\n✗ Configuration failed")
if result.get("error"):
print(f" Error Code: {result['error'].get('code')}")
print(f" Error Message: {result['error'].get('message')}")
if result.get("result") and result['result'].get('output'):
print(f"\n Execution Output:")
print(f" {result['result']['output']}")[project]
name = "huawei-cloud-flexus-l-server-hermes-deployment"
version = "1.0.0"
dependencies = [
"huaweicloudsdkcore>=3.1.0",
"huaweicloudsdkcoc>=3.1.0",
"pyyaml>=6.0",
]
[tool.setuptools]
py_modules = [
"caller",
"lib",
"utils",
"deploy",
"models",
"channels",
"gateway"
]
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"#!/usr/bin/env python3
# coding: utf-8
"""
Huawei Cloud Flexus L Instance One-Click Hermes Deployment - UniAgent Status Query Module
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from scripts.lib import query_uniagent_status
from scripts.utils import prompt_for_input
def do_check_uniagent(args):
"""
Execute UniAgent status query
Args:
args: Command line argument object with the following attributes:
- resource_id: L instance resource ID
- ak: Huawei Cloud AK (supports both long-term and temporary AK)
- sk: Huawei Cloud SK (supports both long-term and temporary SK)
- security_token: Security token for temporary credentials (optional, only required for temporary AK/SK)
Returns:
None
"""
print("=" * 60)
print(" UniAgent Status Query")
print("=" * 60)
ak = getattr(args, 'ak', None)
sk = getattr(args, 'sk', None)
security_token = getattr(args, 'security_token', None)
# If credentials not provided, prompt interactively
if not ak or not sk:
print("\nHuawei Cloud credentials not configured, entering interactive configuration...")
print("Please configure Huawei Cloud credentials:")
print(" - Long-term AK/SK: No security_token required")
print(" - Temporary AK/SK: Security token required")
print("-" * 40)
ak = prompt_for_input("Huawei Cloud AK (HW_ACCESS_KEY)", required=True)
sk = prompt_for_input("Huawei Cloud SK (HW_SECRET_KEY)", required=True, hide_input=True)
security_token = prompt_for_input("Security Token (optional, only for temporary credentials)", required=False)
resource_id = args.resource_id if hasattr(args, 'resource_id') and args.resource_id else None
if not resource_id:
resource_id = prompt_for_input("L instance resource ID", required=True)
print(f"\nQuery configuration:")
print(f" Resource ID: {resource_id}")
print("\nQuerying UniAgent status...")
result = query_uniagent_status(resource_id, ak, sk, security_token)
if result.get("ok"):
print(f"\n[OK] {result['text']}")
if result.get("result"):
data = result['result']
resources = data.get("data", [])
if resources:
for resource in resources:
print(f" Resource ID: {resource.get('resource_id', 'Unknown')}")
print(f" UniAgent status: {resource.get('agent_state', 'Unknown')}")
print(f" Instance name: {resource.get('name', 'Unknown')}")
else:
print(f"\n[FAIL] Query failed")
if result.get("error"):
print(f" Error code: {result['error'].get('code')}")
print(f" Error message: {result['error'].get('message')}")