
Huawei Cloud Flexus L Deploy Jiuwenswarm
- 78 installs
- 19 repo stars
- Updated July 31, 2026
- huaweicloud/huaweicloud-skills
One-click deploy the JiuwenSwarm multi-agent platform on Huawei Cloud Flexus L instances, auto-creating instances and configuring models and channels.
About
Automates end-to-end deployment of the JiuwenSwarm/JiuwenClaw multi-agent collaboration platform on Flexus L instances, from instance creation through model API and message-channel setup via COC. A developer uses it to stand up the AI agent platform without manual console steps.
- Auto-creates instances and deploys via Cloud Operations Center
- Configures model APIs and Feishu/DingTalk/Xiaoyi channels
Huawei Cloud Flexus L Deploy Jiuwenswarm by the numbers
- 78 all-time installs (skills.sh)
- +4 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #627 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-deploy-jiuwenswarmAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 78 |
|---|---|
| repo stars | ★ 19 |
| Last updated | July 31, 2026 |
| Repository | huaweicloud/huaweicloud-skills ↗ |
What it does
One-click deploy the JiuwenSwarm multi-agent platform on Huawei Cloud Flexus L instances, auto-creating instances and configuring models and channels.
Files
Important Notes:
1. All Python files in the scripts directory have implemented all functions. Do not create additional py files. 2. Do not modify the script files in the scripts directory. 3. Please operate directly according to the provided code and documentation. No need to check Huawei Cloud official API documentation. ---
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 commansds 5. AK/SK/Token MUST be passed via environment variables, NEVER appear in conversation 6. NEVER interactively collect Huawei Cloud credentials from users. Credentials MUST be obtained only through:
- Temporary Security Credentials (STS Token) via environment variables
- Permanent credentials via environment variables
---
JiuwenSwarm Deployment Skill for Huawei Cloud Flexus L Instance
Overview
This skill provides a complete automated deployment solution for the JiuwenSwarm (JiuwenClaw) multi-Agent collaboration platform on Huawei Cloud Flexus L instances. It implements full-process automation from environment preparation to message channel configuration through phased scripts.
---
Prerequisites
Before using this skill, the following prerequisites must be met:
1. Huawei Cloud Account Requirements
- A valid Huawei Cloud account with active subscription
- Sufficient balance or billing method configured
- Flexus L instance quota available in the target region (cn-north-4)
2. IAM Credentials
- Huawei Cloud Access Key (AK) and Secret Key (SK) with appropriate permissions
- Temporary Security Credentials (STS Token): Supports temporary security credentials. When
HUAWEICLOUD_SDK_SECURITY_TOKENenvironment variable is set along with AK/SK, the skill will use temporary credentials for authentication. - Required IAM permissions:
hcss:lightInstance:create- Create Flexus L instanceshcss:lightInstance:list- Query instance informationrms:resource:list- Query resource informationcoc:execution:create- Execute COC scriptscoc:execution:list- Query COC task statusiam:project:list- Get project information
3. Environment Requirements
- Python 3.8+ installed with pip
- Required Python packages:
requests- HTTP clienthuaweicloudsdkcore- Huawei Cloud SDK corehuaweicloudsdkcoc- COC service SDKhuaweicloudsdkrms- RMS service SDKhuaweicloudsdkiam- IAM service SDK
4. Network Requirements
- Internet access to Huawei Cloud APIs
- Security group rules allowing outbound HTTP/HTTPS traffic (ports 80, 443)
- For web access: Port 5173 needs to be opened in security group after deployment
5. Resource Requirements
- Flexus L instance with minimum specifications:
- Flavor: medium (2 vCPUs, 4GB RAM) or higher
- System disk: 40GB or larger
- Network: Public IP required
6. Configuration Requirements
- Model API credentials (API_BASE, API_KEY) for LLM integration (required for Phase 6)
- Message channel credentials (Xiaoyi/Feishu/DingTalk) if channel configuration is needed (required for Phase 7)
---
Architecture Diagram
This skill is built on multiple Huawei Cloud services, involving the following cloud services and components:
User/Agent ──────▶│ Flexus L Instance │──────▶│ JiuwenSwarm App │──────▶│ Model Config │ ──────▶│ Channel Config │
(Skill caller) (Target Host) (Multi-Agent Platform) (API_BASE/KEY) (Xiaoyi/Feishu/Dingtalk) Component Description:
- User/Agent: Skill caller that triggers JiuwenSwarm deployment operations via natural language or API
- Flexus L Instance: Huawei Cloud Elastic Cloud Server, serving as the target host for JiuwenSwarm deployment
- JiuwenSwarm App: Multi-agent collaboration platform running on the Flexus L instance
- Model Config: Configuration for external LLM services (API_BASE, API_KEY, MODEL_NAME, MODEL_PROVIDER)
- Channel Config: Messaging channel configuration (Huawei Xiaoyi, Feishu, Dingtalk)
---
Skill Responsibilities
Core Functions
1. Flexus L Instance Creation - Call Flexus L API to create instances, supporting parameters like instance name, flavor (medium/large), image version, etc. 2. Instance Status Query - Query instance status, public IP, instance ID via RMS API 3. COC Remote Deployment - Use Huawei Cloud COC (Cloud Operations Center) to remotely execute deployment scripts on instances 4. COC Task Status Query - Query deployment task execution status and results via COC API 5. System Service Configuration - Configure systemd service for auto-start on boot 6. Model Configuration - Configure API_BASE, API_KEY, MODEL_NAME, MODEL_PROVIDER 7. Message Channel Configuration - Support three message channels: Xiaoyi, Feishu, DingTalk
Execution Flow
Phase 1: Environment Preparation → Phase 2: Create Instance → Phase 3: Install Dependencies → COC Status Query → Phase 4: Deploy Service → COC Status Query → Phase 5: Verify Deployment → Phase 6: Model Configuration → Phase 7: Message Channel Configuration---
Typical Use Cases
User may say:
English Examples: 1. "Help me deploy JiuwenSwarm to Huawei Cloud" 2. "I want to install JiuwenClaw on Flexus L instance" 3. "How to add Feishu bot to my JiuwenSwarm?" 4. "I want to configure JiuwenSwarm to use custom model" 5. "Help me deploy JiuwenSwarm with one click and configure Xiaoyi channel"
---
⚠️ Important: Customer Confirmation Required
Before executing any cloud resource creation operations, explicit customer consent must be obtained!
Scenarios Requiring Confirmation
| Operation | Confirmation Required |
|---|---|
| Create new Flexus L instance | Required |
| Deploy application on existing instance | Required |
| Modify cloud resource configuration | Required |
Confirmation Template
============================================================
⚠️ Cloud Resource Creation Confirmation
============================================================
Operation to be executed: Create new Flexus L instance
Instance Specifications:
- Name: {instance_name}
- Flavor: {flavor}
- Region: {region}
- Estimated Cost: ~100 RMB/month (actual price subject to Huawei Cloud pricing)
Resources will be created immediately after confirmation.
Please reply "confirm" or "agree" to continue.
============================================================---
Execution Steps
Phase 1: Environment Preparation
1. Verify Huawei Cloud credentials (AK/SK)
2. Set environment variable: PYTHONIOENCODING=utf-8
3. Check dependency modules: requests, huaweicloudsdkcore, huaweicloudsdkcoc, huaweicloudsdkrms
4. Validate credential validity (via IAM API)Phase 2: Create Flexus L Instance
⚠️ The following steps can only be executed after obtaining customer confirmation!
1. Display instance configuration information to customer (name, flavor, region, estimated cost)
2. Wait for customer confirmation (reply "confirm" or "agree")
3. After confirmation, execute:
- Get Project ID (via IAM API)
- Call Flexus L create API
- Save order_id for subsequent queries
- Wait for instance creation to complete (poll RMS API)
- Get instance information: instance_id, public_ip, ecs_instance_idPhase 3: COC Remote Dependency Installation
Based on instance information from Phase 2: instance_id, public_ip, ecs_instance_id, execute:
1. Execute dependency installation script via COC
2. Install base tools: git, curl, vim, wget, net-tools, etc.
3. Check Python and Node.js environment
4. Wait for deployment to complete. Note: script execution takes approximately 8 minutes. Please be patient. Only retry if script execution errors occur.Phase 4: COC Remote JiuwenSwarm Service Deployment
1. Read deployment script template (assets/deploy_script_template.sh)
2. Execute complete deployment script on instance via COC
3. Install JiuwenSwarm and related dependencies
4. Configure systemd service
5. Start JiuwenSwarm service
6. Wait for deployment to complete. Note: script execution takes approximately 15 minutes. Please be patient. Only retry if script execution errors occur.Phase 5: Verify Deployment Result
1. Query COC deployment task status
2. Verify port 5173 listening
3. Check service health status
4. Output web access URLPhase 6: Model Configuration
1. Interactively collect model configuration information:
- API_BASE: Model API URL
- API_KEY: Model API key
- MODEL_NAME: Model name
- MODEL_PROVIDER: Model provider
2. Generate configuration script (COC remote execution):
- Backup original .env file
- Update only four core parameters (API_BASE, API_KEY, MODEL_NAME, MODEL_PROVIDER)
- Keep other configuration parameters unchanged
- Set file permission to 600
3. Restart JiuwenSwarm servicePhase 7: Message Channel Configuration
1. Select channel type: xiaoyi / feishu / dingtalk
2. Collect configuration information based on channel type:
- xiaoyi: AK, SK, Agent ID
- feishu: App ID, App Secret
- dingtalk: Client ID, Client Secret, Allow From
3. Generate configuration script (COC remote execution):
- Backup original config.yaml file
- Update only key configuration fields for specified channel, keep other configurations unchanged
- Xiaoyi: Update only ak, sk, agent_id, enabled
- Feishu: Update only app_id, app_secret, enabled
- DingTalk: Update only client_id, client_secret, allow_from, enabled
- Set file permission to 644
4. Restart JiuwenSwarm serviceCOC Remote Script Execution Status Query
1. Query task status by COC execution UUID
2. Support three query methods:
- Direct query: python query_coc_status.py --uuid <execute_uuid>
- Detailed output: python query_coc_status.py --uuid <execute_uuid> --verbose
- Wait for completion: pythonquery_coc_status.py --uuid <execute_uuid> --wait
3. Load UUID from JSON file:
- python query_coc_status.py --from-file new_instance_info.json
4. Return task status, duration, output results, etc.COC Task Status Query
COC task status query supports the following features:
1. Single query - Query current status of specified UUID task
2. Detailed output - Display script execution output
3. Wait for completion - Continuous polling until task completes or timeout
4. File loading - Read UUID from JSON file saved during deployment
Script location: scripts/query_coc_status.py
Usage examples:
# Query single task status
python query_coc_status.py --uuid SCT20250101000000000000000
# Query with detailed output
python query_coc_status.py --uuid SCT20250101000000000000000 --verbose
# Wait for task completion
python query_coc_status.py --uuid SCT20250101000000000000000 --wait
# Custom wait time and polling interval
python query_coc_status.py --uuid SCT20250101000000000000000 --wait --timeout 3600 --interval 30
# Load UUID from JSON file
python query_coc_status.py --from-file new_instance_info.json
COC Task Status Description:
| Status | Description |
|--------|-------------|
| READY | Ready |
| PROCESSING | Running, waiting required |
| FINISHED | Completed successfully |
| ABNORMAL | Execution abnormal, failed |
| CANCELED | Canceled |---
Output Standards
Success Output Template
============================================================
JiuwenSwarm COC Deployment - Complete
============================================================
Target Instance:
Name: {instance_name}
ID: {instance_id}
IP: {public_ip}
COC Execution:
Execute UUID: {execute_uuid}
Status: FINISHED
Deployment Result:
Web Access: http://{public_ip}:5173
Submit Time: {submit_time}
============================================================
[SUCCESS] Deployment task completed!
============================================================Error Output Template
============================================================
[ERROR] Deployment Failed
============================================================
Error: {error_message}
Suggestions:
1. Check Huawei Cloud credentials
2. Verify instance status
3. Check deployment logs
============================================================COC Task Status Description
| Status | Description |
|---|---|
| PROCESSING | Running, waiting required |
| FINISHED | Completed successfully |
| ABNORMAL | Execution abnormal, failed |
| CANCELED | Canceled |
---
Directory Structure
huawei-cloud-flexus-l-deploy-jiuwenSwarm/
├── SKILL.md # Skill documentation
├── requirements.txt # Python dependency list
├── scripts/ # Phased deployment scripts
│ ├── utils.py # Utility functions
│ ├── prepare_env.py # Environment preparation
│ ├── create_instance.py # Create Flexus L instance
│ ├── install_deps.py # COC remote dependency installation
│ ├── deploy_service.py # COC remote service deployment
│ ├── verify_deployment.py # Verify deployment result
│ ├── config_model.py # Model configuration
│ ├── config_channel.py # Message channel configuration
│ └── query_coc_status.py # COC task status query
├── assets/ # Template files
│ ├── deploy_script_template.sh # Deployment script template
│ ├── jiuwenswarm.service.template # systemd service template
│ ├── config_template.yaml # Configuration template
│ └── env.template # Environment variable template
└── references/ # Reference documents
├── api_specs.md # API specifications
├── deployment_checklist.md # Deployment checklist
├── iam_policies.md # IAM policies
└── troubleshooting.md # Troubleshooting guide---
Installation and Usage
Environment Preparation
# Install dependencies
pip install -r requirements.txt
# Configure Huawei Cloud credentials (Recommended: temporary security credentials - STS Token)
# export HUAWEICLOUD_SDK_AK=<your-temp-access-key>
# export HUAWEICLOUD_SDK_SK=<your-temp-secret-key>
# export HUAWEICLOUD_SDK_SECURITY_TOKEN=<your-security-token>
# export HUAWEICLOUD_REGION="cn-north-4"
# OR use permanent credentials (not recommended)
# export HUAWEICLOUD_SDK_AK=<your-access-key>
# export HUAWEICLOUD_SDK_SK=<your-secret-key>
# export HUAWEICLOUD_REGION="cn-north-4"Quick Deployment Flow
# 1. Environment preparation
python scripts/prepare_env.py
# 2. Create instance (interactive confirmation)
python scripts/create_instance.py --name jiuwenSwarm-<timestamp> --flavor medium --wait
# 3. Install dependencies
python scripts/install_deps.py --ip <public_ip>
# 4. Deploy service
python scripts/deploy_service.py --ip <public_ip>
# 5. Verify deployment
python scripts/verify_deployment.py --ip <public_ip>
# 6. Configure model
python scripts/config_model.py --ip <public_ip> --interactive
# 7. Configure message channel
python scripts/config_channel.py --channel xiaoyi --ip <public_ip> --interactive
# 8. Query COC task status
python scripts/query_coc_status.py --uuid <execute_uuid> --verbose---
Web UI Access
Web UI access requires manual security group configuration in Huawei Cloud Console: 1. Login to Huawei Cloud Flexus Application Server L Instance Console
- 🔗 Console URL: https://console.huaweicloud.com/smb/?/resource/list
2. Find your JiuwenSwarm instance in the instance list 3. Click instance name to enter details page 4. Find "Security" or "Network" options in left menu 5. Configure security group rules to open port 5173 Access URL: http://<instance_public_ip>:5173 Security Warning: After opening the port, JiuwenSwarm Web interface will be accessible. Please evaluate security risks before enabling. It is recommended to open temporarily only when needed and close after use. ---
Script Parameter Description
create_instance.py
| Parameter | Description | Default Value |
|---|---|---|
| --name | Instance name | jiuwenSwarm-{timestamp} |
| --flavor | Instance flavor | medium |
| --region | Region (cn-north-4 only) | cn-north-4 |
| --wait | Wait for creation completion | False |
| --timeout | Timeout in seconds | 600 |
| --confirm | Skip confirmation prompt | False |
deploy_service.py
| Parameter | Description | Default Value |
|---|---|---|
| --ip | Instance public IP | Required |
| --wait | Wait for deployment completion | True |
| --timeout | Timeout in seconds | 1800 |
config_model.py
| Parameter | Description |
|---|---|
| --api-base | Model API URL |
| --api-key | Model API key |
| --model-name | Model name |
| --model-provider | Model provider |
| --ip | Instance public IP |
| --interactive | Interactive configuration |
config_channel.py
| Parameter | Description |
|---|---|
| --channel | Channel type (xiaoyi/feishu/dingtalk) |
| --ip | Instance public IP |
| --interactive | Interactive configuration |
query_coc_status.py
| Parameter | Description | Default Value |
|---|---|---|
| --uuid, -u | COC execution UUID | Required |
| --from-file, -f | Read UUID from JSON file | - |
| --key, -k | UUID key name in JSON file | execute_uuid |
| --verbose, -v | Show detailed output | False |
| --wait, -w | Wait for task completion | False |
| --timeout, -t | Wait timeout in seconds | 1800 |
| --interval, -i | Polling interval in seconds | 60 |
---
Huawei Cloud Credential Configuration
Recommended: Use temporary security credentials (STS Token) by default. Please use this method first.
Temporary Security Credentials (STS Token) - Recommended (Default)
The skill supports temporary security credentials. Temporary credentials require an additional HUAWEICLOUD_SDK_SECURITY_TOKEN environment variable.
| Environment Variable | Description | Required |
|---|---|---|
HUAWEICLOUD_SDK_AK | Temporary Access Key | Yes |
HUAWEICLOUD_SDK_SK | Temporary Secret Key | Yes |
HUAWEICLOUD_SDK_SECURITY_TOKEN | Security Token | Yes |
HUAWEICLOUD_REGION | Huawei Cloud Region (default: cn-north-4) | Yes |
Permanent Credentials
Credentials must be set via environment variables before running the skill.
| Environment Variable | Description | Required |
|---|---|---|
HUAWEICLOUD_SDK_AK | Huawei Cloud Access Key | Yes |
HUAWEICLOUD_SDK_SK | Huawei Cloud Secret Key | Yes |
HUAWEICLOUD_REGION | Huawei Cloud Region (default: cn-north-4) | Yes |
Credential Concept:
- Temporary credentials (Default): AK + SK + SECURITY_TOKEN + REGION (STS token is added to permanent credentials)
- Permanent credentials: AK + SK + REGION
Reference: https://support.huaweicloud.com/iam_faq/iam_01_0620.html
---
Key API Endpoints
| Service | Endpoint | Purpose |
|---|---|---|
| Flexus L | https://hcss.{region}.myhuaweicloud.com/v1/light-instances | Create/query instances |
| IAM | https://iam.{region}.myhuaweicloud.com/v3/projects | Get Project ID |
| RMS | https://rms.{region}.myhuaweicloud.com/v1/resource-manager/domains/{domain_id}/resources | Query resources |
| COC | https://coc.{region}.myhuaweicloud.com | Remote script execution |
Supported Region: cn-north-4 only (China North 4)
System Image: Ubuntu 24.04 LTS only
---
Troubleshooting
Instance Creation Failed
- Check if AK/SK are correct
- Confirm sufficient account quota
- Ensure using cn-north-4 region
COC Deployment Unresponsive
- Check if execute_uuid is correct
- Confirm instance status is RUNNING
- Verify COC service permissions
Web Service Unaccessible
- Check security group rules (port 5173 open)
- Confirm service is started:
systemctl status jiuwenswarm - View logs:
journalctl -u jiuwenswarm -f
# JiuwenSwarm Configuration
# Server Configuration
server:
host: 0.0.0.0
port: 5173
# Logging Configuration
logging:
level: INFO
format: "%(asctime)s - %(levelname)s - %(message)s"
# Message Channel Configuration
channels:
xiaoyi:
enabled: false
ak: ""
sk: ""
agent_id: ""
feishu:
enabled: false
app_id: ""
app_secret: ""
dingtalk:
enabled: false
client_id: ""
client_secret: ""
allow_from: "*"
# Model Configuration (read from .env file)
model:
api_base: ${API_BASE}
api_key: ${API_KEY}
model_name: ${MODEL_NAME}
model_provider: ${MODEL_PROVIDER}
# Database Configuration
database:
type: sqlite
path: ./data/jiuwenswarm.db
# Security Configuration
security:
allowed_origins:
- "*"
cors_enabled: true
#!/bin/bash
set -euo pipefail
# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Log functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
echo "============================================================="
echo " JiuwenSwarm Deployment Script"
echo "============================================================="
export DEBIAN_FRONTEND=noninteractive
# Create configuration directories
log_info "Creating configuration directories..."
mkdir -p /root/.jiuwenswarm/config
mkdir -p /root/.jiuwenswarm/logs
mkdir -p /root/.jiuwenswarm/data
mkdir -p /root/.jiuwenswarm/cache
# Create configuration files
log_info "Creating configuration files..."
cat > /root/.jiuwenswarm/config/config.yaml << 'CONFIGEOF'
channels:
xiaoyi:
enabled: false
ak: ""
sk: ""
api_id: ""
agent_id: ""
feishu:
enabled: false
app_id: ""
app_secret: ""
dingtalk:
enabled: false
client_id: ""
client_secret: ""
allow_from: ""
database:
type: sqlite
path: /root/.jiuwenswarm/data/jiuwenswarm.db
cache:
type: memory
size: 1000
security:
session_secret: "change-this-to-a-random-string"
cors_origins: "*"
rate_limit: 100
CONFIGEOF
cat > /root/.jiuwenswarm/config/.env << 'ENVEOL'
API_BASE=https://api.openai.com/v1
API_KEY=your-api-key-here
MODEL_NAME=gpt-4
MODEL_PROVIDER=openai
JIUWENSWARM_HOST=0.0.0.0
JIUWENSWARM_PORT=5173
JIUWENSWARM_LOG_LEVEL=INFO
ENVEOL
chmod 600 /root/.jiuwenswarm/config/config.yaml
chmod 600 /root/.jiuwenswarm/config/.env
log_info "Installing Python 3.11"
# 1. Install PPA tools
sudo apt update
sudo apt install -y software-properties-common
# 2. Add deadsnakes PPA (provides multiple Python versions)
sudo add-apt-repository ppa:deadsnakes/ppa -y
# 3. Update sources
sudo apt update
# 4. Install Python 3.11 + venv + dev
sudo apt install -y python3.11 python3.11-venv python3.11-dev
# 5. Verify installation
python3.11 --version
log_info "Creating Python virtual environment..."
python3.11 -m venv /opt/jiuwenswarm-env
source /opt/jiuwenswarm-env/bin/activate
log_info "Upgrading pip, setuptools, and wheel..."
pip install --upgrade pip setuptools wheel -q -i https://mirrors.aliyun.com/pypi/simple/
log_info "Installing JiuwenSwarm (using domestic mirror)..."
pip install jiuwenswarm -i https://mirrors.aliyun.com/pypi/simple/ --no-cache-dir
# Initialize JiuwenSwarm
log_info "Starting JiuwenSwarm initialization..."
# Use expect or printf to send all responses sequentially
# First try expect, use printf if unavailable
if command -v expect &> /dev/null; then
log_info "Using expect to auto-answer interactive prompts..."
expect << 'EOF'
set timeout 60
spawn jiuwenswarm-init --config /root/.jiuwenswarm/config/config.yaml
expect {
"Do you want to continue? (yes/no):" {
send "yes\r"
exp_continue
}
"Please enter option (1, 2, zh, en) or no to cancel:" {
send "1\r"
exp_continue
}
"Enter option (1, 2, zh, en) or no to cancel:" {
send "zh\r"
exp_continue
}
eof {
catch wait result
exit [lindex $result 3]
}
timeout {
puts "Initialization timeout"
exit 1
}
}
EOF
init_result=$?
else
log_info "Using printf to auto-answer interactive prompts..."
# Use printf to send all responses with sufficient delay
{
echo "yes"
sleep 2
echo "1"
sleep 2
} | jiuwenswarm-init --config /root/.jiuwenswarm/config/config.yaml
init_result=$?
fi
if [[ $init_result -eq 0 ]]; then
log_success "JiuwenSwarm initialization completed"
else
log_error "JiuwenSwarm initialization failed (exit code: $init_result)"
log_info "Attempting alternative initialization method..."
# Alternative: Use --yes and --lang parameters
if jiuwenswarm-init --help 2>&1 | grep -q "--yes"; then
log_info "Trying --yes and --lang parameters..."
jiuwenswarm-init --config /root/.jiuwenswarm/config/config.yaml --yes --lang zh
if [[ $? -eq 0 ]]; then
log_success "JiuwenSwarm initialization completed (alternative method)"
init_result=0
else
log_error "Alternative method also failed, please run initialization manually"
fi
else
log_error "Cannot complete initialization automatically, please execute manually: jiuwenswarm-init --config /root/.jiuwenswarm/config/config.yaml"
exit 1
fi
fi
log_info "Creating systemd service..."
cat > /etc/systemd/system/jiuwenswarm.service << 'SERVICE_EOF'
[Unit]
Description=JiuwenSwarm Service
Description=Multi-Agent Collaboration Platform
After=network.target
Wants=network.target
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/opt/jiuwenswarm-env
EnvironmentFile=/root/.jiuwenswarm/config/.env
ExecStart=/opt/jiuwenswarm-env/bin/jiuwenswarm-start
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=jiuwenswarm
[Install]
WantedBy=multi-user.target
SERVICE_EOF
log_info "Enabling and starting service..."
systemctl daemon-reload
systemctl enable jiuwenswarm
systemctl start jiuwenswarm
log_info "Waiting for service to start..."
sleep 15
log_info "Checking port listening..."
if netstat -tln | grep -q ':5173'; then
log_success "Port 5173 is listening"
else
log_error "Port 5173 is not listening"
journalctl -u jiuwenswarm --no-pager | tail -20
exit 1
fi
log_info "Checking service health status..."
if curl -s -o /dev/null -w "%{http_code}" http://localhost:5173/health | grep -q "200"; then
log_success "Service health check passed"
else
log_error "Service health check failed"
journalctl -u jiuwenswarm --no-pager | tail -20
exit 1
fi
log_success "JiuwenSwarm service started successfully!"
log_info "Web access address: http://$(hostname -I | awk '{print $1}'):5173"
echo "============================================================="
echo " Deployment Complete"
echo "============================================================="
# JiuwenSwarm Environment Variables
# Model Configuration
API_BASE=https://api.openai.com/v1
API_KEY=your-api-key-here
MODEL_NAME=gpt-4
MODEL_PROVIDER=openai
# Service Configuration
PORT=5173
HOST=0.0.0.0
# Database Configuration
DATABASE_TYPE=sqlite
DATABASE_PATH=./data/jiuwenswarm.db
# Logging Configuration
LOG_LEVEL=INFO
# Security Configuration
SECRET_KEY=your-secret-key-here
ALLOWED_ORIGINS=*
# Huawei Cloud Configuration
HUAWEICLOUD_SDK_AK=your-ak-here
HUAWEICLOUD_SDK_SK=your-sk-here
HUAWEICLOUD_REGION=cn-north-4
[
{
"project_id": "",
"region": "cn-north-4",
"region_name": "华北-北京四"
}
]
[Unit]
Description=JiuwenSwarm Service
After=network.target
[Service]
User=root
WorkingDirectory=/opt/jiuwenswarm-env/jiuwenswarm
Environment="PATH=/opt/jiuwenswarm-env/bin"
ExecStart=/opt/jiuwenswarm-env/bin/python -m jiuwenswarm
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
API Specification
Huawei Cloud Service Endpoints
Flexus L Service
- Endpoint:
https://hcss.cn-north-4.myhuaweicloud.com/v1/light-instances - Method: POST
- Purpose: Create Flexus L instance
IAM Service
- Endpoint:
https://iam.{region}.myhuaweicloud.com/v3/projects - Method: GET
- Purpose: Get Project ID
RMS Service
- Endpoint:
https://rms.{region}.myhuaweicloud.com/v1/resource-manager/domains/{domain_id}/resources - Method: GET
- Purpose: Query resource information
COC Service
- Endpoint:
https://coc.{region}.myhuaweicloud.com - Method: POST
- Purpose: Remote script execution
Flexus L Instance Specifications
| Name | Resource ID | CPU | Memory |
|---|---|---|---|
| small | hf.small.1.linux | 1 Core | 2GB |
| medium | hf.medium.1.linux | 2 Core | 4GB |
| large | hf.large.1.linux | 4 Core | 8GB |
| xlarge | hf.xlarge.1.linux | 8 Core | 16GB |
| 2xlarge | hf.2xlarge.1.linux | 16 Core | 32GB |
COC Script Execution Status
| Status | Description |
|---|---|
| PROCESSING | Running |
| FINISHED | Completed |
| ABNORMAL | Abnormal |
Security Group Rules
The following ports need to be opened:
- 5173: JiuwenSwarm Web service port
- 22: SSH remote access port
API Authentication
Using Huawei Cloud SDK for signature authentication: 1. Set environment variables HUAWEICLOUD_SDK_AK and HUAWEICLOUD_SDK_SK 2. SDK automatically handles request signing 3. Region configuration supported via HUAWEICLOUD_REGION environment variable
Deployment Checklist
Pre-Deployment Checks
Credential Checks
- [ ] Huawei Cloud AK/SK configured
- [ ] Credentials have Flexus L instance creation permission
- [ ] Credentials have COC script execution permission
Environment Checks
- [ ] Python 3.10+ installed
- [ ] Huawei Cloud SDK installed
- [ ] Network can access Huawei Cloud services
Resource Checks
- [ ] Sufficient Flexus L quota
- [ ] Target region available
- [ ] Security group rules configured
Deployment Step Checks
Phase 1: Environment Preparation
- [ ] Credential validation passed
- [ ] Dependency module check passed
Phase 2: Create Instance
- [ ] Customer confirmed creation
- [ ] Instance created successfully
- [ ] Instance status is RUNNING
- [ ] Public IP obtained
Phase 3: Install Dependencies
- [ ] Base tools installed
- [ ] Python environment configured
Phase 4: Deploy Service
- [ ] JiuwenSwarm installed
- [ ] systemd service configured
- [ ] Service started successfully
Phase 5: Verify Deployment
- [ ] Port 5173 listening
- [ ] Service health check passed
- [ ] Web interface accessible
Phase 6: Model Configuration
- [ ] API_BASE configured
- [ ] API_KEY configured
- [ ] MODEL_NAME configured
- [ ] MODEL_PROVIDER configured
- [ ] Service restarted successfully
Phase 7: Message Channel Configuration
- [ ] Channel configured
- [ ] Service restarted successfully
Post-Deployment Checks
- [ ] Service auto-start configured correctly
- [ ] Log files generated normally
- [ ] Security group rules correct
- [ ] Backup strategy configured
Rollback Checks
- [ ] Instance can be deleted normally
- [ ] Configuration files backed up completely
- [ ] Data can be migrated normally
IAM Permission Policies - JiuwenSwarm Deployment
Permission Failure Handling Process (MUST)
When any command fails due to permission errors, follow this process:
1. Read this document - Read references/iam_policies.md 2. Display required permissions - Show users the required permission list and policy JSON from this file 3. Guide authorization - Guide users to create custom policies in the IAM console and grant permissions 4. Pause execution - Wait for user confirmation that permissions have been granted before continuing
---
Basic Diagnostics (Read-only)
| API Action | Permission | Purpose |
|---|---|---|
| iam:projects:list | List projects | Get Project ID for Region |
| ecs:servers:get | View instance details | Get Flexus L instance basic info |
| ecs:servers:list | List instances | List all ECS instances under account |
| rms:resources:list | List resources | Query Flexus L instance status and IP |
| coc:scripts:list | List scripts | View created COC scripts |
| coc:scriptJobs:get | View job details | Query COC script execution status |
Advanced Operations (Requires additional authorization)
| API Action | Permission | Purpose |
|---|---|---|
| coc:scripts:create | Create script | Create COC remote execution script |
| coc:scripts:execute | Execute script | Execute commands remotely on Flexus L instance |
| coc:scriptJobs:cancel | Cancel job | Cancel running COC task |
| ecs:servers:start | Start instance | Start Flexus L instance |
| ecs:servers:stop | Stop instance | Stop Flexus L instance |
| ecs:servers:reboot | Reboot instance | Reboot Flexus L instance |
| vpc:securityGroups:list | List security groups | View instance security group configuration |
| vpc:securityGroups:get | View security group | Check security group rules |
Instance Creation (On-demand authorization)
| API Action | Permission | Purpose |
|---|---|---|
| hcss:instances:create | Create Flexus L instance | Create new Flexus L instance |
| hcss:instances:get | View instance details | Get created instance info |
| hcss:instances:list | List instances | Confirm instance creation success |
| hcss:orders:get | View orders | Confirm order status |
---
Minimum Permission Policy JSON
{
"Version": "1.1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:projects:list"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"ecs:servers:get",
"ecs:servers:list",
"ecs:servers:start",
"ecs:servers:stop",
"ecs:servers:reboot"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"rms:resources:list"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"coc:scripts:list",
"coc:scripts:create",
"coc:scripts:execute",
"coc:scriptJobs:get",
"coc:scriptJobs:cancel"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"vpc:securityGroups:list",
"vpc:securityGroups:get"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"hcss:instances:get",
"hcss:instances:list"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"hcss:orders:get"
],
"Resource": ["*"]
}
]
}---
Full Permission Policy JSON (Including instance creation)
Use the following policy if you need to create new Flexus L instances:
{
"Version": "1.1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:projects:list"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"ecs:servers:get",
"ecs:servers:list",
"ecs:servers:start",
"ecs:servers:stop",
"ecs:servers:reboot"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"rms:resources:list"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"coc:scripts:list",
"coc:scripts:create",
"coc:scripts:execute",
"coc:scriptJobs:get",
"coc:scriptJobs:cancel"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"vpc:securityGroups:list",
"vpc:securityGroups:get"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"hcss:instances:create",
"hcss:instances:get",
"hcss:instances:list"
],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": [
"hcss:orders:get"
],
"Resource": ["*"]
}
]
}---
Steps to Create Custom Policy in IAM Console
1. Log in to Huawei Cloud Console 2. Go to IAM (Identity and Access Management) 3. Click left menu Permission Management > Permission Policies 4. Click Create Policy 5. Select JSON tab 6. Paste the policy JSON above 7. Enter policy name (e.g., JiuwenSwarm-Deployment-Policy) 8. Click OK to create policy 9. Go to IAM (Identity and Access Management) > User Groups 10. Select or create a user group 11. Click Assign Policy 12. Search and check the created policy 13. Click OK to complete authorization
---
Permission Verification Command
After creating the policy, verify permissions with:
python scripts/prepare_env.pySuccessful output should show all dependency modules checked successfully.
Troubleshooting Guide
Common Issues
1. Instance Creation Failed
Symptoms:
- Cannot create Flexus L instance
- Authentication error returned
- Quota insufficient error returned
Troubleshooting Steps: 1. Check if AK/SK are configured correctly 2. Verify AK/SK has Flexus L instance creation permission 3. Check account Flexus L quota 4. Confirm target region is available
Solutions:
# Check credential configuration
echo $HUAWEICLOUD_SDK_AK
echo $HUAWEICLOUD_SDK_SK
# Check quota (via Huawei Cloud Console)
# Visit: https://console.huaweicloud.com/flexus/2. COC Script Execution Unresponsive
Symptoms:
- COC task status remains PROCESSING
- Execution timeout
- Cannot get execution result
Troubleshooting Steps: 1. Check if execute_uuid is correct 2. Confirm instance status is RUNNING 3. Verify COC service permissions 4. Check network connectivity
Solutions:
# Check COC task status
python scripts/query_coc_status.py --uuid <execute_uuid>
# Manually check instance status
curl -H "X-Auth-Token: <token>" https://rms.cn-north-4.myhuaweicloud.com/v1/resource-manager/domains/{domain_id}/resources3. Web Service Unaccessible
Symptoms:
- Cannot access http://{ip}:5173
- Connection refused
- Timeout
Troubleshooting Steps: 1. Check security group rules (port 5173 open) 2. Confirm service is started 3. Check firewall settings 4. Verify port listening
Solutions:
# Check service status
systemctl status jiuwenswarm
# Check port listening
netstat -tlnp | grep 5173
# View service logs
journalctl -u jiuwenswarm --no-pager | tail -50
# Check firewall
ufw status4. Service Startup Failed
Symptoms:
- systemd service startup failed
- Service status is failed
- Cannot run normally
Troubleshooting Steps: 1. View system logs 2. Check Python environment 3. Verify dependency installation 4. Check configuration files
Solutions:
# View service logs
journalctl -u jiuwenswarm --no-pager
# Check Python environment
source /opt/jiuwenswarm-env/bin/activate
python --version
# Verify dependencies
pip list | grep jiuwenswarm
# Test manual startup
cd /opt/jiuwenswarm-env/jiuwenswarm
python -m jiuwenswarm5. Model Configuration Invalid
Symptoms:
- Model invocation failed
- API request timeout
- Authentication failed
Troubleshooting Steps: 1. Check .env file configuration 2. Verify API_KEY validity 3. Confirm network can access model service 4. Check proxy configuration
Solutions:
# View configuration file
cat /opt/jiuwenswarm-env/jiuwenswarm/.env
# Test API connection
curl -v -H "Authorization: Bearer <api_key>" <api_base>/models
# Check network connectivity
ping api.openai.com6. Message Channel Configuration Failed
Symptoms:
- Messages cannot be sent
- Channel authentication failed
- Webhook verification failed
Troubleshooting Steps: 1. Check config.yaml configuration 2. Verify channel credentials 3. Confirm network can access channel service 4. Check callback URL
Solutions:
# View configuration file
cat /opt/jiuwenswarm-env/jiuwenswarm/config.yaml
# Test network connectivity
ping api.xiaoyi.com
ping open.feishu.cn
ping oapi.dingtalk.comLog Locations
Service Logs
# systemd service logs
journalctl -u jiuwenswarm
# Application logs
/opt/jiuwenswarm-env/jiuwenswarm/logs/COC Execution Logs
# Query execution logs via COC API
# Use query_coc_status.py script
python scripts/query_coc_status.py --uuid <execute_uuid>Emergency Recovery
Manual Deployment Steps
# 1. Login to instance
ssh root@<public_ip>
# 2. Install dependencies
apt-get update && apt-get install -y python3.11 python3.11-dev python3.11-venv git
# 3. Create virtual environment
python3.11 -m venv /opt/jiuwenswarm-env
source /opt/jiuwenswarm-env/bin/activate
# 4. Install JiuwenSwarm
pip install jiuwenswarm
# 5. Initialize
mkdir -p /opt/jiuwenswarm-env/jiuwenswarm
cd /opt/jiuwenswarm-env/jiuwenswarm
python -m jiuwenswarm init
# 6. Start service
python -m jiuwenswarmInstance Deletion
# Delete instance via Huawei Cloud Console
# Or use Flexus L API
curl -X DELETE "https://hcss.cn-north-4.myhuaweicloud.com/v1/light-instances/{instance_id}" \
-H "X-Auth-Token: <token>"Contact Support
If the issue persists, collect the following information and contact Huawei Cloud support:
1. Error Messages: Complete error output 2. Log Files: systemd logs and application logs 3. Environment Info: Instance specifications, region, OS version 4. Configuration Files: .env and config.yaml (hide sensitive information) 5. Timestamp: Time when the issue occurred
Recovery Process
1. Confirm root cause
2. Backup current configuration
3. Execute fix
4. Verify fix result
5. Update deployment documentation
6. Document issue and solution#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
JiuwenSwarm Message Channel Configuration Script
Configures Xiaoyi, Feishu, or DingTalk message channels for JiuwenSwarm deployment.
Uses Huawei Cloud COC (Cloud Operation Center) to execute configuration commands on target instances.
"""
import os
import sys
import json
import argparse
import logging
from pathlib import Path
from datetime import datetime
os.environ['PYTHONIOENCODING'] = 'utf-8'
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)
EXECUTION_TIMEOUT = 300
CHANNEL_TYPES = ['xiaoyi', 'feishu', 'dingtalk']
# Import utility modules
sys.path.insert(0, str(Path(__file__).parent))
try:
from utils import (
get_huaweicloud_credentials,
get_coc_client,
coc_query_execution,
print_header,
print_success,
print_error,
print_warning,
print_info
)
except ImportError as e:
log.error(f"Failed to import utility modules: {e}")
log.error("Please ensure utils.py exists")
sys.exit(1)
def query_instance_by_ip(public_ip, ak, sk, region, security_token=None):
from huaweicloudsdkcore.auth.credentials import GlobalCredentials, BasicCredentials
from huaweicloudsdkrms.v1 import RmsClient
from huaweicloudsdkrms.v1.region.rms_region import RmsRegion
# RMS requires GlobalCredentials
if security_token:
credentials = GlobalCredentials(ak, sk).with_security_token(security_token)
else:
credentials = GlobalCredentials(ak, sk)
client = RmsClient.new_builder() \
.with_credentials(credentials) \
.with_region(RmsRegion.value_of(region)) \
.build()
from huaweicloudsdkrms.v1 import model
request = model.ListAllResourcesRequest()
request.region_id = region
request.type = "hcss.l-instance"
request.limit = 200
response = client.list_all_resources(request)
resources = response.resources if hasattr(response, 'resources') else []
for r in resources:
name = getattr(r, 'name', '') or getattr(r, 'resource_name', '')
instance_id = getattr(r, 'id', '') or getattr(r, 'resource_id', '')
props = getattr(r, 'properties', None)
ip = None
ecs_instance_id = None
if props:
resources_list = props.get('resources', [])
for res in resources_list:
if isinstance(res, dict):
attrs = res.get('resource_attributes', [])
for attr in attrs:
if isinstance(attr, dict):
key = attr.get('key')
value = attr.get('value')
if key == 'public_ip_address':
ip = value
if key == 'associate_instance_id':
ecs_instance_id = value
if ip == public_ip:
return {
'instance_name': name,
'instance_id': instance_id,
'ecs_instance_id': ecs_instance_id,
'public_ip': ip,
'region': region,
'status': props.get('status') if props else 'UNKNOWN'
}
return None
def load_instance_info():
info_file = Path(__file__).parent / "new_instance_info.json"
if info_file.exists():
with open(info_file, 'r', encoding='utf-8') as f:
return json.load(f)
return None
def create_and_execute_command(client, command, instance_id, instance_name, region):
from huaweicloudsdkcoc.v1.model.create_script_request import CreateScriptRequest
from huaweicloudsdkcoc.v1.model.add_script_model import AddScriptModel
from huaweicloudsdkcoc.v1.model.script_properties_model import ScriptPropertiesModel
from huaweicloudsdkcoc.v1.model.execute_script_request import ExecuteScriptRequest
from huaweicloudsdkcoc.v1.model.script_execute_model import ScriptExecuteModel
from huaweicloudsdkcoc.v1.model.execute_instances_batch_info import ExecuteInstancesBatchInfo
from huaweicloudsdkcoc.v1.model.execute_resource_instance import ExecuteResourceInstance
from huaweicloudsdkcoc.v1.model.script_execute_param import ScriptExecuteParam
from huaweicloudsdkcore.exceptions import exceptions
script_name = f"jiuwenswarm-channel-{datetime.now().strftime('%Y%m%d%H%M%S')}"
description = f"JiuwenSwarm channel configuration on {instance_name}"
log.info("Creating COC script for channel configuration...")
request = CreateScriptRequest()
properties = ScriptPropertiesModel(risk_level="LOW", version="1.0.0")
request.body = AddScriptModel(
name=script_name,
type="SHELL",
content=command,
description=description,
properties=properties
)
try:
response = client.create_script(request)
script_uuid = response.data if hasattr(response, 'data') else str(response)
log.info(f"[OK] Script created: {script_uuid}")
except exceptions.ClientRequestException as e:
log.error(f"Script creation failed: {e.error_code}: {e.error_msg}")
return None, None
log.info("Executing command on target instance...")
execute_request = ExecuteScriptRequest()
execute_request.script_uuid = script_uuid
execute_param = ScriptExecuteParam(timeout=EXECUTION_TIMEOUT, success_rate=100, execute_user="root")
instance = ExecuteResourceInstance(
resource_id=instance_id,
region_id=region,
provider="HCSS",
type="L-INSTANCE"
)
execute_request.body = ScriptExecuteModel(
execute_batches=[ExecuteInstancesBatchInfo(
batch_index=1,
target_instances=[instance],
rotation_strategy="CONTINUE"
)],
execute_param=execute_param
)
try:
execute_response = client.execute_script(execute_request)
execute_uuid = execute_response.data if hasattr(execute_response, 'data') else str(execute_response)
log.info(f"[OK] Execution submitted: {execute_uuid}")
return execute_uuid, script_uuid
except exceptions.ClientRequestException as e:
log.error(f"Script execution failed: {e.error_code}: {e.error_msg}")
return None, None
def wait_for_completion(client, execute_uuid, timeout=300, interval=10):
"""Wait for command execution to complete - using Huawei Cloud COC GetScriptJobInfo API"""
import time
print_info(f"\nWaiting for command execution...")
print_info(f"Timeout: {timeout}s, Polling Interval: {interval}s")
start_time = datetime.now()
while True:
elapsed = (datetime.now() - start_time).total_seconds()
if elapsed > timeout:
print_error(f"Command execution timeout ({timeout}s)")
return False
try:
# Query status using Huawei Cloud COC GetScriptJobInfo API
result = coc_query_execution(execute_uuid)
if not result.get("ok"):
error_info = result.get("error", {})
print_warning(f"Status query failed: {error_info.get('message', 'Unknown error')}")
time.sleep(interval)
continue
job_info = result.get("result", {})
status = job_info.get('status', 'UNKNOWN')
# Task status mapping
STATUS_MAP = {
'READY': 'Preparing',
'PROCESSING': 'Processing',
'FINISHED': 'Completed',
'ABNORMAL': 'Abnormal',
'CANCELED': 'Canceled'
}
status_display = STATUS_MAP.get(status, status)
print(f" Status: {status} ({status_display}) (Elapsed: {int(elapsed)}s)", end='\r')
# According to Huawei Cloud COC API, script execution ends when status is ABNORMAL, CANCELED, or FINISHED
if status == 'FINISHED':
success_count = job_info.get('success_count', 0)
fail_count = job_info.get('fail_count', 0)
print(f"\n[OK] Command execution completed. Success: {success_count}, Failed: {fail_count}")
return success_count > 0
elif status in ['ABNORMAL', 'CANCELED']:
error_msg = job_info.get('error', job_info.get('error_message', 'Unknown error'))
print(f"\n[ERROR] Command execution failed! Status: {status} ({status_display})")
if error_msg:
print_error(f"Error Message: {error_msg}")
return False
except Exception as e:
print(f"\n[WARN] Error checking status: {e}")
time.sleep(interval)
return False
def generate_xiaoyi_script(config):
"""Generate Xiaoyi channel configuration script"""
ak, sk, agent_id = config
script = f"""#!/bin/bash
set -e
echo "[INFO] Configuring Xiaoyi channel..."
CONFIG_DIR="/root/.jiuwenswarm/config"
CONFIG_FILE="$CONFIG_DIR/config.yaml"
if [ ! -d "$CONFIG_DIR" ]; then
echo "[ERROR] Config directory not found: $CONFIG_DIR"
exit 1
fi
if [ ! -f "$CONFIG_FILE" ]; then
echo "[WARN] Config file not found, creating new one..."
cat > "$CONFIG_FILE" << 'EOF'
channels:
xiaoyi:
enabled: false
feishu:
enabled: false
dingtalk:
enabled: false
EOF
fi
echo "[INFO] Backup existing config file..."
cp "$CONFIG_FILE" "$CONFIG_FILE.backup.$(date +%Y%m%d%H%M%S)"
echo "[INFO] Updating Xiaoyi configuration..."
python3 << 'PYEOF'
import yaml
import os
config_file = "/root/.jiuwenswarm/config/config.yaml"
# Read existing configuration
with open(config_file, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f) or {{}}
# Ensure channels section exists
if 'channels' not in config:
config['channels'] = {{}}
# Ensure xiaoyi configuration section exists
if 'xiaoyi' not in config['channels']:
config['channels']['xiaoyi'] = {{}}
# Update only specified fields, keep other fields unchanged
xiaoyi_config = config['channels']['xiaoyi']
# Update Xiaoyi configuration
xiaoyi_config['ak'] = '{ak}'
xiaoyi_config['sk'] = '{sk}'
xiaoyi_config['agent_id'] = '{agent_id}'
xiaoyi_config['enabled'] = True
# Write updated configuration
with open(config_file, 'w', encoding='utf-8') as f:
yaml.dump(config, f, default_flow_style=False, allow_unicode=True, sort_keys=False)
print("[OK] Xiaoyi configuration updated - only specific fields modified")
PYEOF
chmod 644 "$CONFIG_FILE"
echo "[OK] Configuration file permissions set"
echo ""
echo "[INFO] ==========================================="
echo "[INFO] Stop JiuwenSwarm Service"
echo "[INFO] ==========================================="
if systemctl is-active --quiet jiuwenswarm; then
echo "[INFO] Stopping jiuwenswarm service..."
systemctl stop jiuwenswarm
echo "[OK] jiuwenswarm service stopped"
else
echo "[WARN] jiuwenswarm service is not running"
fi
echo ""
echo "[INFO] Waiting 3 seconds..."
sleep 3
echo ""
echo "[INFO] ==========================================="
echo "[INFO] Restart JiuwenSwarm Service"
echo "[INFO] ==========================================="
echo "[INFO] Starting jiuwenswarm service..."
systemctl start jiuwenswarm
echo "[INFO] Waiting for service to start..."
sleep 5
if systemctl is-active --quiet jiuwenswarm; then
echo "[OK] jiuwenswarm service started successfully"
systemctl status jiuwenswarm --no-pager
else
echo "[ERROR] Failed to start jiuwenswarm service"
systemctl status jiuwenswarm --no-pager
exit 1
fi
echo ""
echo "[INFO] ==========================================="
echo "[SUCCESS] Xiaoyi channel configuration completed"
echo "[INFO] ==========================================="
"""
return script
def generate_feishu_script(config):
"""Generate Feishu channel configuration script"""
app_id, app_secret = config
script = f"""#!/bin/bash
set -e
echo "[INFO] Configuring Feishu channel..."
CONFIG_DIR="/root/.jiuwenswarm/config"
CONFIG_FILE="$CONFIG_DIR/config.yaml"
if [ ! -d "$CONFIG_DIR" ]; then
echo "[ERROR] Config directory not found: $CONFIG_DIR"
exit 1
fi
if [ ! -f "$CONFIG_FILE" ]; then
echo "[WARN] Config file not found, creating new one..."
cat > "$CONFIG_FILE" << 'EOF'
channels:
xiaoyi:
enabled: false
feishu:
enabled: false
dingtalk:
enabled: false
EOF
fi
echo "[INFO] Backup existing config file..."
cp "$CONFIG_FILE" "$CONFIG_FILE.backup.$(date +%Y%m%d%H%M%S)"
echo "[INFO] Updating Feishu configuration..."
python3 << 'PYEOF'
import yaml
import os
config_file = "/root/.jiuwenswarm/config/config.yaml"
# Read existing configuration
with open(config_file, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f) or {{}}
# Ensure channels section exists
if 'channels' not in config:
config['channels'] = {{}}
# Ensure feishu configuration section exists
if 'feishu' not in config['channels']:
config['channels']['feishu'] = {{}}
# Update only specified fields, keep other fields unchanged
feishu_config = config['channels']['feishu']
# Update Feishu configuration
feishu_config['app_id'] = '{app_id}'
feishu_config['app_secret'] = '{app_secret}'
feishu_config['enabled'] = True
# Write updated configuration
with open(config_file, 'w', encoding='utf-8') as f:
yaml.dump(config, f, default_flow_style=False, allow_unicode=True, sort_keys=False)
print("[OK] Feishu configuration updated - only specific fields modified")
PYEOF
chmod 644 "$CONFIG_FILE"
echo "[OK] Configuration file permissions set"
echo ""
echo "[INFO] ==========================================="
echo "[INFO] Stopping JiuwenSwarm Service"
echo "[INFO] ==========================================="
if systemctl is-active --quiet jiuwenswarm; then
echo "[INFO] Stopping jiuwenswarm service..."
systemctl stop jiuwenswarm
echo "[OK] jiuwenswarm service stopped"
else
echo "[WARN] jiuwenswarm service is not running"
fi
echo ""
echo "[INFO] Waiting 3 seconds..."
sleep 3
echo ""
echo "[INFO] ==========================================="
echo "[INFO] Restarting JiuwenSwarm Service"
echo "[INFO] ==========================================="
echo "[INFO] Starting jiuwenswarm service..."
systemctl start jiuwenswarm
echo "[INFO] Waiting for service to start..."
sleep 5
if systemctl is-active --quiet jiuwenswarm; then
echo "[OK] jiuwenswarm service started successfully"
systemctl status jiuwenswarm --no-pager
else
echo "[ERROR] Failed to start jiuwenswarm service"
systemctl status jiuwenswarm --no-pager
exit 1
fi
echo ""
echo "[INFO] ==========================================="
echo "[SUCCESS] Feishu channel configuration completed"
echo "[INFO] ==========================================="
"""
return script
def generate_dingtalk_script(config):
"""Generate DingTalk channel configuration script"""
client_id, client_secret, allow_from = config
script = f"""#!/bin/bash
set -e
echo "[INFO] Configuring DingTalk channel..."
CONFIG_DIR="/root/.jiuwenswarm/config"
CONFIG_FILE="$CONFIG_DIR/config.yaml"
if [ ! -d "$CONFIG_DIR" ]; then
echo "[ERROR] Config directory not found: $CONFIG_DIR"
exit 1
fi
if [ ! -f "$CONFIG_FILE" ]; then
echo "[WARN] Config file not found, creating new one..."
cat > "$CONFIG_FILE" << 'EOF'
channels:
xiaoyi:
enabled: false
feishu:
enabled: false
dingtalk:
enabled: false
EOF
fi
echo "[INFO] Backup existing config file..."
cp "$CONFIG_FILE" "$CONFIG_FILE.backup.$(date +%Y%m%d%H%M%S)"
echo "[INFO] Updating DingTalk configuration..."
python3 << 'PYEOF'
import yaml
import os
config_file = "/root/.jiuwenswarm/config/config.yaml"
# Read existing configuration
with open(config_file, 'r', encoding='utf-8') as f:
config = yaml.safe_load(f) or {{}}
# Ensure channels section exists
if 'channels' not in config:
config['channels'] = {{}}
# Ensure dingtalk configuration section exists
if 'dingtalk' not in config['channels']:
config['channels']['dingtalk'] = {{}}
# Update only specified fields, keep other fields unchanged
dingtalk_config = config['channels']['dingtalk']
# Update DingTalk configuration
dingtalk_config['client_id'] = '{client_id}'
dingtalk_config['client_secret'] = '{client_secret}'
dingtalk_config['allow_from'] = '{allow_from}'
dingtalk_config['enabled'] = True
# Write updated configuration
with open(config_file, 'w', encoding='utf-8') as f:
yaml.dump(config, f, default_flow_style=False, allow_unicode=True, sort_keys=False)
print("[OK] DingTalk configuration updated - only specific fields modified")
PYEOF
chmod 644 "$CONFIG_FILE"
echo "[OK] Configuration file permissions set"
echo ""
echo "[INFO] ==========================================="
echo "[INFO] Stopping JiuwenSwarm Service"
echo "[INFO] ==========================================="
if systemctl is-active --quiet jiuwenswarm; then
echo "[INFO] Stopping jiuwenswarm service..."
systemctl stop jiuwenswarm
echo "[OK] jiuwenswarm service stopped"
else
echo "[WARN] jiuwenswarm service is not running"
fi
echo ""
echo "[INFO] Waiting 3 seconds..."
sleep 3
echo ""
echo "[INFO] ==========================================="
echo "[INFO] Restarting JiuwenSwarm Service"
echo "[INFO] ==========================================="
echo "[INFO] Starting jiuwenswarm service..."
systemctl start jiuwenswarm
echo "[INFO] Waiting for service to start..."
sleep 5
if systemctl is-active --quiet jiuwenswarm; then
echo "[OK] jiuwenswarm service started successfully"
systemctl status jiuwenswarm --no-pager
else
echo "[ERROR] Failed to start jiuwenswarm service"
systemctl status jiuwenswarm --no-pager
exit 1
fi
echo ""
echo "[INFO] ==========================================="
echo "[SUCCESS] DingTalk channel configuration completed"
echo "[INFO] ==========================================="
"""
return script
def configure_channel_interactive():
print("="*60)
print(" JiuwenSwarm Message Channel Configuration")
print("="*60)
print("\nPlease select channel type:")
print(" 1. xiaoyi - Xiaoyi")
print(" 2. feishu - Feishu")
print(" 3. dingtalk - DingTalk")
while True:
choice = input("\nEnter your choice (1/2/3): ").strip()
if choice == '1':
channel_type = 'xiaoyi'
break
elif choice == '2':
channel_type = 'feishu'
break
elif choice == '3':
channel_type = 'dingtalk'
break
else:
print("[ERROR] Invalid choice, please enter 1, 2, or 3")
print(f"\n--- {channel_type} Channel Configuration ---")
if channel_type == 'xiaoyi':
ak = input("Xiaoyi AK: ").strip()
if not ak:
print("[ERROR] AK cannot be empty")
return None
sk = input("Xiaoyi SK: ").strip()
if not sk:
print("[ERROR] SK cannot be empty")
return None
agent_id = input("Xiaoyi Agent ID: ").strip()
if not agent_id:
print("[ERROR] Agent ID cannot be empty")
return None
print("\n" + "="*60)
print(" Configuration Confirmation")
print("="*60)
print(f"\n Channel Type: Xiaoyi")
print(f" AK: {ak}")
print(f" SK: {'*' * len(sk) if len(sk) > 8 else sk}")
print(f" Agent ID: {agent_id}")
confirm = input("\nConfirm configuration? (y/n): ").strip().lower()
if confirm != 'y':
print("[INFO] Configuration cancelled")
return None
return {
'channel_type': channel_type,
'config': (ak, sk, agent_id)
}
elif channel_type == 'feishu':
app_id = input("Feishu App ID: ").strip()
if not app_id:
print("[ERROR] App ID cannot be empty")
return None
app_secret = input("Feishu App Secret: ").strip()
if not app_secret:
print("[ERROR] App Secret cannot be empty")
return None
print("\n" + "="*60)
print(" Configuration Confirmation")
print("="*60)
print(f"\n Channel Type: Feishu")
print(f" App ID: {app_id}")
print(f" App Secret: {'*' * len(app_secret) if len(app_secret) > 8 else app_secret}")
confirm = input("\nConfirm configuration? (y/n): ").strip().lower()
if confirm != 'y':
print("[INFO] Configuration cancelled")
return None
return {
'channel_type': channel_type,
'config': (app_id, app_secret)
}
elif channel_type == 'dingtalk':
client_id = input("DingTalk Client ID: ").strip()
if not client_id:
print("[ERROR] Client ID cannot be empty")
return None
client_secret = input("DingTalk Client Secret: ").strip()
if not client_secret:
print("[ERROR] Client Secret cannot be empty")
return None
allow_from = input("DingTalk Allow From: ").strip()
if not allow_from:
print("[ERROR] Allow From cannot be empty")
return None
print("\n" + "="*60)
print(" Configuration Confirmation")
print("="*60)
print(f"\n Channel Type: DingTalk")
print(f" Client ID: {client_id}")
print(f" Client Secret: {'*' * len(client_secret) if len(client_secret) > 8 else client_secret}")
print(f" Allow From: {allow_from}")
confirm = input("\nConfirm configuration? (y/n): ").strip().lower()
if confirm != 'y':
print("[INFO] Configuration cancelled")
return None
return {
'channel_type': channel_type,
'config': (client_id, client_secret, allow_from)
}
def parse_args():
parser = argparse.ArgumentParser(description='Configure JiuwenSwarm Message Channels')
parser.add_argument('--channel', type=str, required=True, choices=CHANNEL_TYPES, help='Channel type: xiaoyi/feishu/dingtalk')
parser.add_argument('--xiaoyi-ak', type=str, help='Xiaoyi AK')
parser.add_argument('--xiaoyi-sk', type=str, help='Xiaoyi SK')
parser.add_argument('--xiaoyi-agent-id', type=str, help='Xiaoyi Agent ID')
parser.add_argument('--feishu-app-id', type=str, help='Feishu App ID')
parser.add_argument('--feishu-app-secret', type=str, help='Feishu App Secret')
parser.add_argument('--dingtalk-client-id', type=str, help='DingTalk Client ID')
parser.add_argument('--dingtalk-client-secret', type=str, help='DingTalk Client Secret')
parser.add_argument('--dingtalk-allow-from', type=str, help='DingTalk Allow From')
parser.add_argument('--instance-id', type=str, help='Instance RMS resource ID')
parser.add_argument('--ip', type=str, help='Instance public IP address')
parser.add_argument('--interactive', action='store_true', help='Interactive configuration mode')
return parser.parse_args()
def main():
args = parse_args()
try:
AK, SK, REGION, SECURITY_TOKEN = get_huaweicloud_credentials()
except ValueError as e:
print(f"[ERROR] {e}")
sys.exit(1)
if SECURITY_TOKEN:
print(f"[INFO] Using temporary security credentials (STS token)")
# Get configuration
config_result = None
if args.interactive:
config_result = configure_channel_interactive()
else:
channel_type = args.channel
config = None
if channel_type == 'xiaoyi':
if args.xiaoyi_ak and args.xiaoyi_sk and args.xiaoyi_agent_id:
config = (args.xiaoyi_ak, args.xiaoyi_sk, args.xiaoyi_agent_id)
elif channel_type == 'feishu':
if args.feishu_app_id and args.feishu_app_secret:
config = (args.feishu_app_id, args.feishu_app_secret)
elif channel_type == 'dingtalk':
if args.dingtalk_client_id and args.dingtalk_client_secret and args.dingtalk_allow_from:
config = (args.dingtalk_client_id, args.dingtalk_client_secret, args.dingtalk_allow_from)
if config:
config_result = {
'channel_type': channel_type,
'config': config
}
if not config_result:
print("[ERROR] Invalid configuration parameters")
sys.exit(1)
channel_type = config_result['channel_type']
channel_config = config_result['config']
# Get instance info
instance_info = None
if args.instance_id:
instance_info = {'instance_id': args.instance_id, 'public_ip': args.ip, 'instance_name': 'Unknown'}
elif args.ip:
print(f"[INFO] Querying instance info by public IP: {args.ip}")
instance_info = query_instance_by_ip(args.ip, AK, SK, REGION, SECURITY_TOKEN)
if not instance_info:
print(f"[ERROR] Cannot find instance with public IP: {args.ip}")
return
else:
instance_info = load_instance_info()
if not instance_info:
print("[ERROR] Cannot get instance info")
print("Please provide instance info via:")
print(" Method 1: --ip <public_ip>")
print(" Method 2: --instance-id <RMS_resource_id>")
return
instance_id = instance_info.get('instance_id')
instance_name = instance_info.get('instance_name', 'Unknown')
public_ip = instance_info.get('public_ip')
if not instance_id:
print("[ERROR] Missing instance_id")
return
print("\n" + "="*60)
print(" Phase 7: Message Channel Configuration")
print("="*60)
print(f"\nTarget Instance:")
print(f" Name: {instance_name}")
print(f" IP: {public_ip}")
print(f"\nChannel Configuration:")
print(f" Channel Type: {channel_type}")
# Generate configuration script
if channel_type == 'xiaoyi':
script_content = generate_xiaoyi_script(channel_config)
elif channel_type == 'feishu':
script_content = generate_feishu_script(channel_config)
elif channel_type == 'dingtalk':
script_content = generate_dingtalk_script(channel_config)
else:
print("[ERROR] Invalid channel type")
return
client = get_coc_client()
print("\n[INFO] Creating COC client... [OK]")
execute_uuid, script_uuid = create_and_execute_command(
client, script_content, instance_id, instance_name, REGION
)
if not execute_uuid:
print("\n[ERROR] Failed to submit configuration command")
return
print("\n" + "="*60)
print(" Configuration Progress")
print("="*60)
success = wait_for_completion(client, execute_uuid)
print("\n" + "="*60)
if success:
print(" [SUCCESS] Message channel configuration completed")
else:
print(" [ERROR] Message channel configuration failed")
sys.exit(1)
print("="*60)
print(f"\nWeb Access: http://{public_ip}:5173")
print("\nNext Steps:")
print(" 1. Check service status: sudo systemctl status jiuwenswarm")
print(" 2. View logs: sudo journalctl -u jiuwenswarm -f")
print(" 3. Verify configuration: curl http://localhost:5173/health")
result = {
'channel_type': channel_type,
'channel_config': {k: '***' for k in ['ak', 'sk', 'app_secret', 'client_secret']} if isinstance(channel_config, tuple) else '***',
'instance_id': instance_id,
'instance_name': instance_name,
'public_ip': public_ip,
'configure_time': datetime.now().isoformat(),
'success': success
}
output_path = Path(__file__).parent / "channel_config_result.json"
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(result, f, indent=2, ensure_ascii=False)
print(f"\n[INFO] Configuration result saved to {output_path}")
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
JiuwenSwarm Model Configuration Script
Configures AI model parameters (API base, key, model name, provider) for JiuwenSwarm deployment.
Uses Huawei Cloud COC (Cloud Operation Center) to execute configuration commands on target instances.
"""
import os
import sys
import json
import argparse
import logging
from pathlib import Path
from datetime import datetime
os.environ['PYTHONIOENCODING'] = 'utf-8'
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)
EXECUTION_TIMEOUT = 300
# Import utility modules
sys.path.insert(0, str(Path(__file__).parent))
try:
from utils import (
get_huaweicloud_credentials,
get_coc_client,
coc_query_execution,
print_header,
print_success,
print_error,
print_warning,
print_info
)
except ImportError as e:
log.error(f"Failed to import utility modules: {e}")
log.error("Please ensure utils.py exists")
sys.exit(1)
def query_instance_by_ip(public_ip, ak, sk, region, security_token=None):
from huaweicloudsdkcore.auth.credentials import GlobalCredentials, BasicCredentials
from huaweicloudsdkrms.v1 import RmsClient
from huaweicloudsdkrms.v1.region.rms_region import RmsRegion
# RMS requires GlobalCredentials
if security_token:
credentials = GlobalCredentials(ak, sk).with_security_token(security_token)
else:
credentials = GlobalCredentials(ak, sk)
client = RmsClient.new_builder() \
.with_credentials(credentials) \
.with_region(RmsRegion.value_of(region)) \
.build()
from huaweicloudsdkrms.v1 import model
request = model.ListAllResourcesRequest()
request.region_id = region
request.type = "hcss.l-instance"
request.limit = 200
response = client.list_all_resources(request)
resources = response.resources if hasattr(response, 'resources') else []
for r in resources:
name = getattr(r, 'name', '') or getattr(r, 'resource_name', '')
instance_id = getattr(r, 'id', '') or getattr(r, 'resource_id', '')
props = getattr(r, 'properties', None)
ip = None
ecs_instance_id = None
if props:
resources_list = props.get('resources', [])
for res in resources_list:
if isinstance(res, dict):
attrs = res.get('resource_attributes', [])
for attr in attrs:
if isinstance(attr, dict):
key = attr.get('key')
value = attr.get('value')
if key == 'public_ip_address':
ip = value
if key == 'associate_instance_id':
ecs_instance_id = value
if ip == public_ip:
return {
'instance_name': name,
'instance_id': instance_id,
'ecs_instance_id': ecs_instance_id,
'public_ip': ip,
'region': region,
'status': props.get('status') if props else 'UNKNOWN'
}
return None
def load_instance_info():
info_file = Path(__file__).parent / "new_instance_info.json"
if info_file.exists():
with open(info_file, 'r', encoding='utf-8') as f:
return json.load(f)
return None
def create_and_execute_command(client, command, instance_id, instance_name, region):
from huaweicloudsdkcoc.v1.model.create_script_request import CreateScriptRequest
from huaweicloudsdkcoc.v1.model.add_script_model import AddScriptModel
from huaweicloudsdkcoc.v1.model.script_properties_model import ScriptPropertiesModel
from huaweicloudsdkcoc.v1.model.execute_script_request import ExecuteScriptRequest
from huaweicloudsdkcoc.v1.model.script_execute_model import ScriptExecuteModel
from huaweicloudsdkcoc.v1.model.execute_instances_batch_info import ExecuteInstancesBatchInfo
from huaweicloudsdkcoc.v1.model.execute_resource_instance import ExecuteResourceInstance
from huaweicloudsdkcoc.v1.model.script_execute_param import ScriptExecuteParam
from huaweicloudsdkcore.exceptions import exceptions
script_name = f"jiuwenswarm-config-{datetime.now().strftime('%Y%m%d%H%M%S')}"
description = f"JiuwenSwarm model configuration on {instance_name}"
log.info("Creating COC script for model configuration...")
request = CreateScriptRequest()
properties = ScriptPropertiesModel(risk_level="LOW", version="1.0.0")
request.body = AddScriptModel(
name=script_name,
type="SHELL",
content=command,
description=description,
properties=properties
)
try:
response = client.create_script(request)
script_uuid = response.data if hasattr(response, 'data') else str(response)
log.info(f"[OK] Script created: {script_uuid}")
except exceptions.ClientRequestException as e:
log.error(f"Script creation failed: {e.error_code}: {e.error_msg}")
return None, None
log.info("Executing command on target instance...")
execute_request = ExecuteScriptRequest()
execute_request.script_uuid = script_uuid
execute_param = ScriptExecuteParam(timeout=EXECUTION_TIMEOUT, success_rate=100, execute_user="root")
instance = ExecuteResourceInstance(
resource_id=instance_id,
region_id=region,
provider="HCSS",
type="L-INSTANCE"
)
execute_request.body = ScriptExecuteModel(
execute_batches=[ExecuteInstancesBatchInfo(
batch_index=1,
target_instances=[instance],
rotation_strategy="CONTINUE"
)],
execute_param=execute_param
)
try:
execute_response = client.execute_script(execute_request)
execute_uuid = execute_response.data if hasattr(execute_response, 'data') else str(execute_response)
log.info(f"[OK] Execution submitted: {execute_uuid}")
return execute_uuid, script_uuid
except exceptions.ClientRequestException as e:
log.error(f"Script execution failed: {e.error_code}: {e.error_msg}")
return None, None
def wait_for_completion(client, execute_uuid, timeout=300, interval=10):
"""Wait for command execution to complete - using Huawei Cloud COC GetScriptJobInfo API"""
import time
print_info(f"\nWaiting for command execution...")
print_info(f"Timeout: {timeout}s, Polling Interval: {interval}s")
start_time = datetime.now()
while True:
elapsed = (datetime.now() - start_time).total_seconds()
if elapsed > timeout:
print_error(f"Command execution timeout ({timeout}s)")
return False
try:
# Query status using Huawei Cloud COC GetScriptJobInfo API
result = coc_query_execution(execute_uuid)
if not result.get("ok"):
error_info = result.get("error", {})
print_warning(f"Status query failed: {error_info.get('message', 'Unknown error')}")
time.sleep(interval)
continue
job_info = result.get("result", {})
status = job_info.get('status', 'UNKNOWN')
# Task status mapping
STATUS_MAP = {
'READY': 'Preparing',
'PROCESSING': 'Processing',
'FINISHED': 'Completed',
'ABNORMAL': 'Abnormal',
'CANCELED': 'Canceled'
}
status_display = STATUS_MAP.get(status, status)
print(f" Status: {status} ({status_display}) (Elapsed: {int(elapsed)}s)", end='\r')
# According to Huawei Cloud COC API, script execution ends when status is ABNORMAL, CANCELED, or FINISHED
if status == 'FINISHED':
success_count = job_info.get('success_count', 0)
fail_count = job_info.get('fail_count', 0)
print(f"\n[OK] Command execution completed. Success: {success_count}, Failed: {fail_count}")
return success_count > 0
elif status in ['ABNORMAL', 'CANCELED']:
error_msg = job_info.get('error', job_info.get('error_message', 'Unknown error'))
print(f"\n[ERROR] Command execution failed! Status: {status} ({status_display})")
if error_msg:
print_error(f"Error Message: {error_msg}")
return False
except Exception as e:
print(f"\n[WARN] Error checking status: {e}")
time.sleep(interval)
return False
def generate_config_script(config):
api_base = config['api_base']
api_key = config['api_key']
model_name = config['model_name']
model_provider = config['model_provider']
test_script = '''#!/bin/bash
set -e
echo "[INFO] Configuring JiuwenSwarm model..."
CONFIG_DIR="/root/.jiuwenswarm/config"
ENV_FILE="$CONFIG_DIR/.env"
# Ensure config directory exists
mkdir -p "$CONFIG_DIR"
# If config file doesn't exist, create a basic config file
if [ ! -f "$ENV_FILE" ]; then
echo "[INFO] Config file does not exist, creating new file"
cat > "$ENV_FILE" << 'EOF'
# JiuwenSwarm Configuration
EOF
fi
# Backup existing config file
BACKUP_FILE="$ENV_FILE.backup.$(date +%Y%m%d%H%M%S)"
cp "$ENV_FILE" "$BACKUP_FILE"
echo "[INFO] Config file backed up: $BACKUP_FILE"
# Define the four parameters to update
API_BASE_VALUE="''' + api_base + '''"
API_KEY_VALUE="''' + api_key + '''"
MODEL_NAME_VALUE="''' + model_name + '''"
MODEL_PROVIDER_VALUE="''' + model_provider + '''"
# Use sed to update or add config parameters while preserving other content
update_param() {
local key="$1"
local value="$2"
local env_file="$3"
if grep -q "^[[:space:]]*$key=" "$env_file"; then
# Parameter exists, update its value
sed -i "s|^\s*$key=.*|$key=\"$value\"|" "$env_file"
echo "[INFO] Updated $key"
else
# Parameter doesn't exist, add to end of file
echo "$key=\"$value\"" >> "$env_file"
echo "[INFO] Added $key"
fi
}
# Update the four core parameters
update_param "API_BASE" "$API_BASE_VALUE" "$ENV_FILE"
update_param "API_KEY" "$API_KEY_VALUE" "$ENV_FILE"
update_param "MODEL_NAME" "$MODEL_NAME_VALUE" "$ENV_FILE"
update_param "MODEL_PROVIDER" "$MODEL_PROVIDER_VALUE" "$ENV_FILE"
echo "[INFO] Config file updated:"
echo "-----------------------------------------"
cat "$ENV_FILE"
echo "-----------------------------------------"
chmod 600 "$ENV_FILE"
echo "[OK] Configuration file permissions set"
echo ""
echo "[INFO] ==========================================="
echo "[INFO] Stop JiuwenSwarm Service"
echo "[INFO] ==========================================="
if systemctl is-active --quiet jiuwenswarm; then
echo "[INFO] Stopping jiuwenswarm service..."
systemctl stop jiuwenswarm
echo "[OK] jiuwenswarm service stopped"
else
echo "[WARN] jiuwenswarm service is not running"
fi
echo ""
echo "[INFO] Waiting 3 seconds..."
sleep 3
echo ""
echo "[INFO] ==========================================="
echo "[INFO] Restart JiuwenSwarm Service"
echo "[INFO] ==========================================="
echo "[INFO] Starting jiuwenswarm service..."
systemctl start jiuwenswarm
echo "[INFO] Waiting for service to start..."
sleep 5
if systemctl is-active --quiet jiuwenswarm; then
echo "[OK] jiuwenswarm service started successfully"
systemctl status jiuwenswarm --no-pager
else
echo "[ERROR] Failed to start jiuwenswarm service"
systemctl status jiuwenswarm --no-pager
exit 1
fi
echo ""
echo "[INFO] ==========================================="
echo "[SUCCESS] Model configuration completed!"
echo "[INFO] ==========================================="
'''
return test_script
def configure_model_interactive():
print("="*60)
print(" JiuwenSwarm Model Configuration")
print("="*60)
print("\nPlease provide model configuration information:\n")
api_base = input("Model API URL (API_BASE): ").strip()
if not api_base:
print("[ERROR] API URL cannot be empty")
return None
api_key = input("Model API Key (API_KEY): ").strip()
if not api_key:
print("[ERROR] API Key cannot be empty")
return None
model_name = input("Model Name (MODEL_NAME): ").strip()
if not model_name:
print("[ERROR] Model name cannot be empty")
return None
model_provider = input("Model Provider (MODEL_PROVIDER): ").strip()
if not model_provider:
print("[ERROR] Model provider cannot be empty")
return None
print("\n" + "="*60)
print(" Configuration Confirmation")
print("="*60)
print(f"\n API_BASE: {api_base}")
print(f" API_KEY: {'*' * len(api_key) if len(api_key) > 8 else api_key}")
print(f" MODEL_NAME: {model_name}")
print(f" MODEL_PROVIDER: {model_provider}")
confirm = input("\nConfirm configuration? (y/n): ").strip().lower()
if confirm != 'y':
print("[INFO] Configuration cancelled")
return None
return {
'api_base': api_base,
'api_key': api_key,
'model_name': model_name,
'model_provider': model_provider
}
def parse_args():
parser = argparse.ArgumentParser(description='Configure JiuwenSwarm Model Parameters')
parser.add_argument('--api-base', type=str, help='Model API URL')
parser.add_argument('--api-key', type=str, help='Model API Key')
parser.add_argument('--model-name', type=str, help='Model Name')
parser.add_argument('--model-provider', type=str, help='Model Provider')
parser.add_argument('--config', type=str, help='JSON configuration file')
parser.add_argument('--instance-id', type=str, help='Instance RMS resource ID')
parser.add_argument('--ip', type=str, help='Instance public IP address')
parser.add_argument('--interactive', action='store_true', help='Interactive configuration mode')
return parser.parse_args()
def main():
args = parse_args()
try:
AK, SK, REGION, SECURITY_TOKEN = get_huaweicloud_credentials()
except ValueError as e:
print(f"[ERROR] {e}")
sys.exit(1)
if SECURITY_TOKEN:
print(f"[INFO] Using temporary security credentials (STS token)")
config = None
if args.config:
with open(args.config, 'r', encoding='utf-8') as f:
config = json.load(f)
elif args.api_base and args.api_key and args.model_name and args.model_provider:
config = {
'api_base': args.api_base,
'api_key': args.api_key,
'model_name': args.model_name,
'model_provider': args.model_provider
}
elif args.interactive:
config = configure_model_interactive()
else:
config = configure_model_interactive()
if not config:
return
instance_info = None
if args.instance_id:
instance_info = {'instance_id': args.instance_id, 'public_ip': args.ip, 'instance_name': 'Unknown'}
elif args.ip:
print(f"[INFO] Querying instance info by public IP: {args.ip}")
instance_info = query_instance_by_ip(args.ip, AK, SK, REGION, SECURITY_TOKEN)
if not instance_info:
print(f"[ERROR] Cannot find instance with public IP: {args.ip}")
return
else:
instance_info = load_instance_info()
if not instance_info:
print("[ERROR] Cannot get instance info")
print("Please provide instance info via:")
print(" Method 1: --ip <public_ip>")
print(" Method 2: --instance-id <RMS_resource_id>")
return
instance_id = instance_info.get('instance_id')
instance_name = instance_info.get('instance_name', 'Unknown')
public_ip = instance_info.get('public_ip')
if not instance_id:
print("[ERROR] Missing instance_id")
return
print("\n" + "="*60)
print(" Phase 6: Configure JiuwenSwarm Model")
print("="*60)
print(f"\nTarget Instance:")
print(f" Name: {instance_name}")
print(f" IP: {public_ip}")
print(f"\nModel Configuration:")
print(f" API_BASE: {config['api_base']}")
print(f" MODEL_NAME: {config['model_name']}")
print(f" MODEL_PROVIDER: {config['model_provider']}")
script_content = generate_config_script(config)
client = get_coc_client()
print("\n[INFO] Creating COC client... [OK]")
execute_uuid, script_uuid = create_and_execute_command(
client, script_content, instance_id, instance_name, REGION
)
if not execute_uuid:
print("\n[ERROR] Failed to submit configuration command")
return
print("\n" + "="*60)
print(" Configuration Progress")
print("="*60)
success = wait_for_completion(client, execute_uuid)
print("\n" + "="*60)
if success:
print(" [SUCCESS] Model configuration successful!")
else:
print(" [ERROR] Model configuration failed")
sys.exit(1)
print("="*60)
print(f"\nWeb Access: http://{public_ip}:5173")
print("\nNext Steps:")
print(" 1. Restart service to apply configuration:")
print(" # Method 1: Use pkill to stop and start")
print(" pkill -f jiuwen")
print(" source /opt/jiuwenswarm-env/bin/activate && jiuwenswarm-start")
print("")
print(" # Method 2: Use systemd restart")
print(" sudo systemctl restart jiuwenswarm")
print("")
print(" # Method 3: Use configuration update script (Recommended)")
print(" bash /opt/jiuwenswarm-env/configure-and-restart.sh model /root/.jiuwenswarm/config/.env")
print("")
print(" 2. Check service status: sudo systemctl status jiuwenswarm")
print(" 3. View logs: sudo journalctl -u jiuwenswarm -f")
print(" 4. Verify configuration: curl http://localhost:5173/health")
result = {
'config': config,
'instance_id': instance_id,
'instance_name': instance_name,
'public_ip': public_ip,
'configure_time': datetime.now().isoformat(),
'success': success
}
output_path = Path(__file__).parent / "model_config_result.json"
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(result, f, indent=2, ensure_ascii=False)
print(f"\n[INFO] Configuration result saved to {output_path}")
print("\nNext step: Run config_channel.py to configure message channels")
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Flexus L Instance Creation Script
Creates Huawei Cloud Flexus L instances for JiuwenSwarm deployment.
Handles instance provisioning, resource allocation, and status monitoring.
"""
import os
import sys
import json
import time
import uuid
import argparse
import logging
from datetime import datetime
from urllib.parse import urlparse
from pathlib import Path
os.environ['PYTHONIOENCODING'] = 'utf-8'
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)
try:
import requests
except ImportError:
log.error("requests module not installed")
sys.exit(1)
FLEXUS_API_ENDPOINT = "https://hcss.cn-north-4.myhuaweicloud.com/v1/light-instances"
sys.path.insert(0, str(Path(__file__).parent))
from utils import get_huaweicloud_credentials
def get_project_id_by_region(ak: str, sk: str, security_token: Optional[str], region: str) -> Optional[str]:
"""Get Project ID for a specified region"""
iam_endpoint = "https://iam.myhuaweicloud.com/v3/projects"
try:
from huaweicloudsdkcore.signer.signer import Signer
from huaweicloudsdkcore.sdk_request import SdkRequest
from huaweicloudsdkcore.auth.credentials import BasicCredentials, GlobalCredentials
if security_token:
credentials = BasicCredentials(ak, sk).with_security_token(security_token)
else:
credentials = BasicCredentials(ak, sk)
signer = Signer(credentials)
request = SdkRequest()
request.method = "GET"
request.schema = "https"
request.host = "iam.myhuaweicloud.com"
request.resource_path = "/v3/projects"
request.body = ""
request.header_params = {
"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)
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')
return None
except Exception as e:
print(f"Failed to get Project ID: {e}")
return None
def get_flexus_flavors_for_region(region: str):
return {
"small": "hf.small.1.linux",
"medium": "hf.medium.1.linux",
"large": "hf.large.1.linux",
"xlarge": "hf.xlarge.1.linux",
"2xlarge": "hf.2xlarge.1.linux"
}
def create_flexus_l_instance(ak, sk, security_token, project_id, region, instance_name, flavor="medium", wait=True, timeout=600):
flavors = get_flexus_flavors_for_region(region)
flavor_ref = flavors.get(flavor)
if not flavor_ref:
raise ValueError(f"Unsupported flavor: {flavor}")
request_body = {
"instance_name": instance_name,
"plan_spec": flavor_ref,
"image_ref": {
"image_name": "Ubuntu",
"image_version": "24.04"
},
"region": region,
"charging_mode": "prePaid",
"period_type": "month",
"period_num": 1,
"purchase_quantity": 1,
"description": f"JiuwenSwarm deployment - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
"is_auto_renew": True,
"is_auto_pay": True,
"extra_resources": [
{"type": "evs", "size": 50},
{"type": "cbr", "size": 50},
{"type": "hss"}
]
}
if not project_id:
project_id = get_project_id_by_region(ak, sk, security_token, region)
if not project_id:
raise ValueError(f"Failed to get Project ID for region {region}")
from huaweicloudsdkcore.signer.signer import Signer
from huaweicloudsdkcore.sdk_request import SdkRequest
from huaweicloudsdkcore.auth.credentials import GlobalCredentials, BasicCredentials
# Use AK/SK direct signature to call Flexus L API, add X-Project-Id header to identify project
credentials = BasicCredentials(ak, sk, project_id)
if security_token:
credentials = credentials.with_security_token(security_token)
signer = Signer(credentials)
parsed_url = urlparse(FLEXUS_API_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 = {
"Content-Type": "application/json",
"Client-Request-Id": str(uuid.uuid4()),
"X-Id": "/v1/light-instances",
"X-Project-Id": project_id
}
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)
# Manually add X-Security-Token header for temporary credentials (not automatically added by SDK signing)
if security_token:
headers["X-Security-Token"] = security_token
resp = requests.post(FLEXUS_API_ENDPOINT, headers=headers, data=body_str, timeout=30)
if resp.status_code in [200, 201, 202]:
result = resp.json()
order_id = result.get('order_id')
log.info(f"Instance creation request submitted, Order ID: {order_id}")
return order_id
else:
log.error(f"Instance creation failed: HTTP {resp.status_code}, {resp.text}")
return None
def query_instance_status(ak, sk, security_token, region, resource_id):
from huaweicloudsdkcore.auth.credentials import GlobalCredentials
from huaweicloudsdkrms.v1 import RmsClient
from huaweicloudsdkrms.v1.region.rms_region import RmsRegion
# RMS requires GlobalCredentials
if security_token:
credentials = GlobalCredentials(ak, sk).with_security_token(security_token)
else:
credentials = GlobalCredentials(ak, sk)
client = RmsClient.new_builder() \
.with_credentials(credentials) \
.with_region(RmsRegion.value_of(region)) \
.build()
from huaweicloudsdkrms.v1 import model
request = model.ListAllResourcesRequest()
request.region_id = region
request.type = "hcss.l-instance"
request.limit = 200
response = client.list_all_resources(request)
resources = response.resources if hasattr(response, 'resources') else []
for r in resources:
rid = getattr(r, 'id', '') or getattr(r, 'resource_id', '')
if rid == resource_id:
props = getattr(r, 'properties', None)
if props:
return props.get('status', 'UNKNOWN')
return 'UNKNOWN'
return None
def get_instance_info(ak, sk, security_token, region, resource_id):
from huaweicloudsdkcore.auth.credentials import GlobalCredentials
from huaweicloudsdkrms.v1 import RmsClient
from huaweicloudsdkrms.v1.region.rms_region import RmsRegion
# RMS requires GlobalCredentials
if security_token:
credentials = GlobalCredentials(ak, sk).with_security_token(security_token)
else:
credentials = GlobalCredentials(ak, sk)
client = RmsClient.new_builder() \
.with_credentials(credentials) \
.with_region(RmsRegion.value_of(region)) \
.build()
from huaweicloudsdkrms.v1 import model
request = model.ListAllResourcesRequest()
request.region_id = region
request.type = "hcss.l-instance"
request.limit = 200
response = client.list_all_resources(request)
resources = response.resources if hasattr(response, 'resources') else []
for r in resources:
rid = getattr(r, 'id', '') or getattr(r, 'resource_id', '')
if rid == resource_id:
name = getattr(r, 'name', '') or getattr(r, 'resource_name', '')
instance_id = rid
props = getattr(r, 'properties', None)
public_ip = None
ecs_instance_id = None
if props:
resources_list = props.get('resources', [])
for res in resources_list:
if isinstance(res, dict):
attrs = res.get('resource_attributes', [])
for attr in attrs:
if isinstance(attr, dict):
key = attr.get('key')
value = attr.get('value')
if key == 'public_ip_address':
public_ip = value
if key == 'associate_instance_id':
ecs_instance_id = value
return {
'instance_name': name,
'instance_id': instance_id,
'ecs_instance_id': ecs_instance_id,
'public_ip': public_ip,
'region': region,
'status': props.get('status') if props else 'UNKNOWN'
}
return None
def show_confirmation(instance_name, flavor, region):
flavor_display = {
"small": "small (1 vCPU, 2GB RAM)",
"medium": "medium (2 vCPU, 4GB RAM)",
"large": "large (4 vCPU, 8GB RAM)",
"xlarge": "xlarge (8 vCPU, 16GB RAM)",
"2xlarge": "2xlarge (16 vCPU, 32GB RAM)"
}
print("\n" + "=" * 60)
print(" ⚠️ Cloud Resource Creation Confirmation")
print("=" * 60)
print(f"\nOperation to perform: Create new Flexus L Instance\n")
print("Instance Specification:")
print(f" - Name: {instance_name}")
print(f" - Flavor: {flavor_display.get(flavor, flavor)}")
print(f" - Region: {region}")
print(f" - Estimated Cost: ~100 CNY/month (actual price subject to Huawei Cloud pricing)\n")
print("Resources will be created immediately after confirmation.")
print("=" * 60)
print("\nPlease enter 'confirm' or 'yes' to continue:")
print("> ", end="")
response = input().strip().lower()
return response in ['confirm', 'yes', 'ok', 'y']
def parse_args():
parser = argparse.ArgumentParser(description='Create Flexus L Instance')
parser.add_argument('--name', type=str, default=f"jiuwenSwarm-{datetime.now().strftime('%Y%m%d%H%M%S')}", help='Instance name')
parser.add_argument('--flavor', type=str, default='medium', choices=['small', 'medium', 'large', 'xlarge', '2xlarge'], help='Instance flavor')
parser.add_argument('--region', type=str, default='cn-north-4', help='Region (cn-north-4 only)')
parser.add_argument('--wait', action='store_true', help='Wait for instance creation to complete')
parser.add_argument('--timeout', type=int, default=600, help='Timeout in seconds')
parser.add_argument('--confirm', action='store_true', help='Skip confirmation prompt')
return parser.parse_args()
def main():
args = parse_args()
print("\n" + "=" * 60)
print(" Phase 2: Create Flexus L Instance")
print("=" * 60)
try:
AK, SK, REGION, SECURITY_TOKEN = get_huaweicloud_credentials()
except ValueError as e:
print(f"[ERROR] {e}")
sys.exit(1)
# Validate region - only cn-north-4 is supported
if args.region != 'cn-north-4':
print(f"[ERROR] Only cn-north-4 region is supported, current region: {args.region}")
print("[INFO] Please use --region cn-north-4 or use the default value")
sys.exit(1)
if SECURITY_TOKEN:
print(f"[INFO] Using temporary security credentials (STS token)")
if not args.confirm:
if not show_confirmation(args.name, args.flavor, args.region):
print("\n[INFO] User cancelled operation")
sys.exit(0)
print(f"\n[INFO] Starting to create Flexus L instance...")
print(f"[INFO] Instance name: {args.name}")
print(f"[INFO] Flavor: {args.flavor}")
print(f"[INFO] Region: {args.region}")
project_id = get_project_id_by_region(AK, SK, SECURITY_TOKEN, args.region)
if not project_id:
print("[ERROR] Failed to get Project ID")
sys.exit(1)
print(f"[INFO] Project ID: {project_id}")
order_id = create_flexus_l_instance(AK, SK, SECURITY_TOKEN, project_id, args.region, args.name, args.flavor, args.wait, args.timeout)
if not order_id:
print("[ERROR] Instance creation request failed")
sys.exit(1)
print(f"[INFO] Order ID: {order_id}")
result_file = Path(__file__).parent / "instance_order.json"
with open(result_file, 'w', encoding='utf-8') as f:
json.dump({'order_id': order_id, 'instance_name': args.name, 'flavor': args.flavor, 'region': args.region}, f, indent=2)
print(f"[INFO] Order information saved to: {result_file}")
if args.wait:
print(f"\n[INFO] Waiting for instance creation to complete (timeout: {args.timeout} seconds)...")
elapsed = 0
interval = 30
resource_id = None
while elapsed < args.timeout:
time.sleep(interval)
elapsed += interval
try:
from huaweicloudsdkcore.auth.credentials import GlobalCredentials, BasicCredentials
from huaweicloudsdkrms.v1 import RmsClient
from huaweicloudsdkrms.v1.region.rms_region import RmsRegion
from huaweicloudsdkrms.v1 import model
if SECURITY_TOKEN:
credentials = GlobalCredentials(AK, SK).with_security_token(SECURITY_TOKEN)
else:
credentials = GlobalCredentials(AK, SK)
client = RmsClient.new_builder() \
.with_credentials(credentials) \
.with_region(RmsRegion.value_of(args.region)) \
.build()
request = model.ListAllResourcesRequest()
request.region_id = args.region
request.type = "hcss.l-instance"
request.limit = 200
response = client.list_all_resources(request)
resources = response.resources if hasattr(response, 'resources') else []
for r in resources:
name = getattr(r, 'name', '') or getattr(r, 'resource_name', '')
if name == args.name:
resource_id = getattr(r, 'id', '') or getattr(r, 'resource_id', '')
props = getattr(r, 'properties', None)
status = props.get('status') if props else 'UNKNOWN'
print(f"[{elapsed}s] Instance status: {status}")
if status == 'RUNNING':
print("\n[SUCCESS] Instance created successfully!")
instance_info = get_instance_info(AK, SK, SECURITY_TOKEN, args.region, resource_id)
if instance_info:
info_file = Path(__file__).parent / "new_instance_info.json"
with open(info_file, 'w', encoding='utf-8') as f:
json.dump(instance_info, f, indent=2, ensure_ascii=False)
print(f"[INFO] Instance information saved to: {info_file}")
print(f"\nInstance Information:")
print(f" - Instance ID: {instance_info['instance_id']}")
print(f" - Public IP: {instance_info['public_ip']}")
print(f" - ECS Instance ID: {instance_info['ecs_instance_id']}")
print("\nNext step: Run install_deps.py for COC remote dependency installation")
sys.exit(0)
break
except Exception as e:
print(f"[WARN] Error querying instance status: {e}")
print("[ERROR] Instance creation timeout")
sys.exit(1)
print("\n[INFO] Instance creation request submitted, use RMS API to query instance status")
print("Next step: Run install_deps.py for COC remote dependency installation")
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
JiuwenSwarm Service Deployment Script
Deploys JiuwenSwarm service to Huawei Cloud Flexus instances using COC (Cloud Operation Center).
Manages remote script execution, status monitoring, and deployment verification.
"""
import os
import sys
import json
import argparse
import logging
import time
from pathlib import Path
from datetime import datetime
os.environ['PYTHONIOENCODING'] = 'utf-8'
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)
# Import utility modules
sys.path.insert(0, str(Path(__file__).parent))
try:
from utils import (
get_huaweicloud_credentials,
get_coc_client,
coc_query_execution,
coc_create_script,
coc_execute_script,
print_header,
print_success,
print_error,
print_warning,
print_info
)
except ImportError as e:
log.error(f"Failed to import utility modules: {e}")
log.error("Please ensure utils.py exists")
sys.exit(1)
SCRIPT_DIR = Path(__file__).parent.parent / "assets"
SCRIPT_PATH = SCRIPT_DIR / "deploy_script_template.sh"
EXECUTION_TIMEOUT = 1799 # Huawei Cloud COC API limit: must be less than 1800 seconds
EXECUTION_INTERVAL = 30
MAX_RETRIES = 3
# Global variables
AK = None
SK = None
REGION = None
SECURITY_TOKEN = None
def get_credentials():
"""Lazy credential retrieval"""
global AK, SK, REGION, SECURITY_TOKEN
if AK is None or SK is None:
AK, SK, REGION, SECURITY_TOKEN = get_huaweicloud_credentials()
return AK, SK, REGION, SECURITY_TOKEN
def query_instance_by_ip(public_ip):
from huaweicloudsdkcore.auth.credentials import GlobalCredentials, BasicCredentials
from huaweicloudsdkrms.v1 import RmsClient
from huaweicloudsdkrms.v1.region.rms_region import RmsRegion
# Get credentials
ak, sk, region, security_token = get_credentials()
# RMS requires GlobalCredentials
if security_token:
credentials = GlobalCredentials(ak, sk).with_security_token(security_token)
else:
credentials = GlobalCredentials(ak, sk)
client = RmsClient.new_builder() \
.with_credentials(credentials) \
.with_region(RmsRegion.value_of(region)) \
.build()
from huaweicloudsdkrms.v1 import model
request = model.ListAllResourcesRequest()
request.region_id = region
request.type = "hcss.l-instance"
request.limit = 200
response = client.list_all_resources(request)
resources = response.resources if hasattr(response, 'resources') else []
for r in resources:
name = getattr(r, 'name', '') or getattr(r, 'resource_name', '')
instance_id = getattr(r, 'id', '') or getattr(r, 'resource_id', '')
props = getattr(r, 'properties', None)
ip = None
ecs_instance_id = None
if props:
resources_list = props.get('resources', [])
for res in resources_list:
if isinstance(res, dict):
attrs = res.get('resource_attributes', [])
for attr in attrs:
if isinstance(attr, dict):
key = attr.get('key')
value = attr.get('value')
if key == 'public_ip_address':
ip = value
if key == 'associate_instance_id':
ecs_instance_id = value
if ip == public_ip:
return {
'instance_name': name,
'instance_id': instance_id,
'ecs_instance_id': ecs_instance_id,
'public_ip': ip,
'region': region,
'status': props.get('status') if props else 'UNKNOWN'
}
return None
def load_instance_info():
info_file = Path(__file__).parent / "new_instance_info.json"
if info_file.exists():
with open(info_file, 'r', encoding='utf-8') as f:
return json.load(f)
return None
def get_deploy_script():
script_path = Path(__file__).parent.parent / "assets" / "deploy_script_template.sh"
if script_path.exists():
with open(script_path, 'r', encoding='utf-8') as f:
return f.read()
return None
def execute_script_via_coc(client, instance_id, ecs_instance_id, script_content):
from huaweicloudsdkcoc.v1.model.create_script_request import CreateScriptRequest
from huaweicloudsdkcoc.v1.model.add_script_model import AddScriptModel
from huaweicloudsdkcoc.v1.model.script_properties_model import ScriptPropertiesModel
from huaweicloudsdkcoc.v1.model.execute_script_request import ExecuteScriptRequest
from huaweicloudsdkcoc.v1.model.script_execute_model import ScriptExecuteModel
from huaweicloudsdkcoc.v1.model.execute_instances_batch_info import ExecuteInstancesBatchInfo
from huaweicloudsdkcoc.v1.model.execute_resource_instance import ExecuteResourceInstance
from huaweicloudsdkcoc.v1.model.script_execute_param import ScriptExecuteParam
try:
log.info("Creating COC script...")
properties = ScriptPropertiesModel(risk_level="LOW", version="1.0.0")
script_name = f"jiuwenswarm_deploy_{datetime.now().strftime('%Y%m%d%H%M%S')}"
create_request = CreateScriptRequest()
create_request.body = AddScriptModel(
name=script_name,
type="SHELL",
content=script_content,
description="JiuwenSwarm deployment script",
properties=properties
)
create_response = client.create_script(create_request)
script_uuid = create_response.data if hasattr(create_response, 'data') else str(create_response)
log.info(f"Script created successfully: {script_uuid}")
log.info("Executing script on target instance...")
execute_request = ExecuteScriptRequest()
execute_request.script_uuid = script_uuid
execute_param = ScriptExecuteParam(timeout=1799, success_rate=100, execute_user="root")
# Get credentials
_, _, region, _ = get_credentials()
instance = ExecuteResourceInstance(
resource_id=instance_id,
region_id=region,
provider="HCSS",
type="L-INSTANCE"
)
execute_request.body = ScriptExecuteModel(
execute_batches=[ExecuteInstancesBatchInfo(
batch_index=1,
target_instances=[instance],
rotation_strategy="CONTINUE"
)],
execute_param=execute_param
)
execute_response = client.execute_script(execute_request)
# Check response status code, 200 or 202 indicates successful task submission
status_code = execute_response.status_code if hasattr(execute_response, 'status_code') else 200
if status_code not in [200, 202]:
log.error(f"Task submission failed, response status code: {status_code}")
return None
execute_uuid = execute_response.data if hasattr(execute_response, 'data') else str(execute_response)
log.info(f"Execution submitted successfully: {execute_uuid}")
return execute_response
except Exception as e:
log.error(f"COC script execution failed: {e}")
return None
def get_script_job_status(client, execute_uuid):
"""Get script job status - using Huawei Cloud COC GetScriptJobInfo API"""
result = coc_query_execution(execute_uuid)
if result.get("ok"):
job_info = result.get("result", {})
# 确保状态字段存在
status = job_info.get('status', 'UNKNOWN')
job_info['status'] = status
# 添加统计信息(如果API没有提供,则计算)
total_count = job_info.get('total_count', 0)
success_count = job_info.get('success_count', 0)
fail_count = job_info.get('fail_count', 0)
processing_count = job_info.get('processing_count', 0)
# 如果API没有提供统计信息,根据状态计算
if total_count == 0:
if status == 'FINISHED':
success_count = 1
total_count = 1
fail_count = 0
processing_count = 0
elif status in ['FAILED', 'ABNORMAL', 'TIMEOUT', 'CANCELED']:
success_count = 0
total_count = 1
fail_count = 1
processing_count = 0
elif status in ['PROCESSING', 'RUNNING', 'PENDING']:
success_count = 0
total_count = 1
fail_count = 0
processing_count = 1
# 计算进度
if total_count > 0:
progress = (success_count + fail_count) / total_count * 100
job_info['progress'] = f"{progress:.1f}%"
job_info['progress_percent'] = progress
job_info['total_count'] = total_count
job_info['success_count'] = success_count
job_info['fail_count'] = fail_count
job_info['processing_count'] = processing_count
else:
job_info['progress'] = "0%"
job_info['progress_percent'] = 0
return job_info
else:
# 查询失败,返回错误信息
error_info = result.get("error", {})
log.error(f"状态查询失败: {error_info.get('message', '未知错误')}")
log.error(f"错误码: {error_info.get('code', 'UNKNOWN')}")
return None
def deploy_jiuwenswarm(instance_id, ecs_instance_id, public_ip, wait=True, timeout=EXECUTION_TIMEOUT):
print_header("Phase 4: COC Remote Deployment of JiuwenSwarm Service")
client = get_coc_client()
deploy_script = get_deploy_script()
if not deploy_script:
print_error("无法读取部署脚本模板")
return None
print_info(f"在实例 {public_ip} 上执行JiuwenSwarm部署脚本...")
print_info(f"脚本类型: shell")
print_info(f"超时时间: {timeout}秒 ({timeout/60:.0f}分钟)")
result = execute_script_via_coc(client, instance_id, ecs_instance_id, deploy_script)
if not result:
print_error("部署任务提交失败")
return None
execute_uuid = None
if hasattr(result, 'data'):
execute_uuid = result.data
print_info("部署任务已提交")
print_info(f"Execute UUID: {execute_uuid}")
result_file = Path(__file__).parent / "coc_deploy_result.json"
with open(result_file, 'w', encoding='utf-8') as f:
json.dump({
'execute_uuid': execute_uuid,
'instance_id': instance_id,
'public_ip': public_ip
}, f, indent=2, ensure_ascii=False)
print_info(f"部署结果已保存到: {result_file}")
if wait:
print_info(f"等待部署完成 (超时: {timeout}秒)...")
print("=" * 60)
start_time = time.time()
retry_count = 0
last_status = None
while time.time() - start_time < timeout:
elapsed = int(time.time() - start_time)
job_info = get_script_job_status(client, execute_uuid)
if job_info:
status = job_info.get('status', 'UNKNOWN')
# Update status mapping according to Huawei Cloud COC API documentation
# Job status values: READY (Preparing), PROCESSING (Processing), ABNORMAL (Abnormal), CANCELED (Canceled), FINISHED (Completed)
status_display = {
'READY': 'Preparing',
'PROCESSING': 'Processing',
'FINISHED': 'Completed',
'ABNORMAL': 'Abnormal',
'CANCELED': 'Canceled'
}.get(status, status)
if status != last_status:
print(f"\n[{elapsed}s] Status: {status} ({status_display})")
last_status = status
# According to Huawei Cloud COC GetScriptJobInfo API, when status becomes FINISHED, CANCELED, or ABNORMAL, the script execution has ended
# Only FINISHED indicates successful execution
if status == 'FINISHED':
print_success("JiuwenSwarm deployment completed!")
print_info("="*50)
print_info(f"Execution UUID: {execute_uuid}")
print_info(f"Script Name: {job_info.get('script_name', 'N/A')}")
print_info(f"Execute User: {job_info.get('execute_user', 'N/A')}")
print_info(f"Execution Result: Total {job_info.get('total_count', 1)} instances")
print_info(f" Success: {job_info.get('success_count', 0)}")
print_info(f" Failed: {job_info.get('fail_count', 0)}")
# Display execution time
if job_info.get('execute_costs'):
execute_costs_ms = job_info.get('execute_costs', 0)
execute_costs_seconds = job_info.get('execute_costs_seconds', execute_costs_ms / 1000 if execute_costs_ms else 0)
print_info(f"Execution Time: {execute_costs_ms}ms ({execute_costs_seconds:.2f} seconds)")
# Display time information
if job_info.get('create_time'):
print_info(f"Create Time: {job_info['create_time']}")
if job_info.get('finish_time'):
print_info(f"Finish Time: {job_info['finish_time']}")
# Display script output
if job_info.get('output'):
output = job_info['output']
print_info("\nScript Output:")
print(output[:2000] if len(output) > 2000 else output)
if len(output) > 2000:
print_info(f"... (Output truncated, total {len(output)} characters)")
# Display error message (if any)
if job_info.get('error'):
print_error(f"\nError Message: {job_info['error']}")
print_info("="*50)
return execute_uuid
elif status in ['ABNORMAL', 'CANCELED']:
# According to GetScriptJobInfo API, CANCELED and ABNORMAL indicate script execution completed but failed
print_error("Deployment job failed!")
print_info("="*50)
print_info(f"Execution UUID: {execute_uuid}")
print_info(f"Status: {status} ({status_display})")
# Get detailed error information
error_msg = job_info.get('error', job_info.get('error_message', ''))
if error_msg:
print_error(f"Error Reason: {error_msg}")
# Display script output
if job_info.get('output'):
output = job_info['output']
print_info("\nScript Output:")
print(output[:2000] if len(output) > 2000 else output)
if len(output) > 2000:
print_info(f"... (Output truncated, total {len(output)} characters)")
print_info("="*50)
return None # 返回None表示执行失败
time.sleep(EXECUTION_INTERVAL)
print_error("Deployment timeout")
return None
return execute_uuid
def parse_args():
parser = argparse.ArgumentParser(description='COC Remote Deployment of JiuwenSwarm Service')
parser.add_argument('--instance-id', type=str, help='Instance RMS resource ID')
parser.add_argument('--ecs-instance-id', type=str, help='ECS instance ID')
parser.add_argument('--ip', type=str, help='Instance public IP address')
parser.add_argument('--wait', action='store_true', default=True, help='Wait for deployment to complete')
parser.add_argument('--timeout', type=int, default=1800, help='Timeout in seconds')
return parser.parse_args()
def main():
args = parse_args()
if not os.environ.get('HUAWEICLOUD_SDK_AK') or not os.environ.get('HUAWEICLOUD_SDK_SK'):
print("[ERROR] Please set environment variables HUAWEICLOUD_SDK_AK and HUAWEICLOUD_SDK_SK")
sys.exit(1)
get_credentials()
instance_info = None
if args.instance_id and args.ip:
instance_info = {
'instance_id': args.instance_id,
'ecs_instance_id': args.ecs_instance_id,
'public_ip': args.ip
}
elif args.ip:
print(f"[INFO] Querying instance info by public IP: {args.ip}")
instance_info = query_instance_by_ip(args.ip)
if not instance_info:
print("[ERROR] Cannot find instance with specified IP")
sys.exit(1)
else:
instance_info = load_instance_info()
if not instance_info:
print("[ERROR] Cannot get instance info")
print("[INFO] Please specify --instance-id and --ip parameters, or ensure new_instance_info.json exists")
sys.exit(1)
print(f"\nInstance Info:")
print(f" - Instance ID: {instance_info['instance_id']}")
print(f" - ECS Instance ID: {instance_info['ecs_instance_id']}")
print(f" - Public IP: {instance_info['public_ip']}")
execute_uuid = deploy_jiuwenswarm(
instance_info['instance_id'],
instance_info['ecs_instance_id'],
instance_info['public_ip'],
args.wait,
args.timeout
)
if execute_uuid:
print("\nNext step: Run verify_deployment.py to verify JiuwenSwarm service deployment result")
else:
print("\n[ERROR] Deployment job failed")
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Environment Preparation Script for JiuwenSwarm Deployment
Verifies Huawei Cloud credentials, checks dependencies, and prepares environment.
This is the first phase in the JiuwenSwarm deployment workflow.
"""
import os
import sys
import logging
from pathlib import Path
os.environ['PYTHONIOENCODING'] = 'utf-8'
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)
try:
import requests
except ImportError:
log.error("requests module not installed. Please run: pip install requests")
sys.exit(1)
try:
from huaweicloudsdkcore.signer.signer import Signer
from huaweicloudsdkcore.sdk_request import SdkRequest
except ImportError:
log.error("huaweicloudsdkcore module not installed. Please run: pip install huaweicloudsdkcore")
sys.exit(1)
try:
from huaweicloudsdkcore.auth.credentials import GlobalCredentials
from huaweicloudsdkcoc.v1.region.coc_region import CocRegion
from huaweicloudsdkcoc.v1 import CocClient
except ImportError:
log.error("Huawei Cloud SDK modules not installed. Please run: pip install huaweicloudsdkcoc huaweicloudsdkrms")
sys.exit(1)
sys.path.insert(0, str(Path(__file__).parent))
from utils import get_huaweicloud_credentials
def check_credentials():
print("\n" + "=" * 60)
print(" Phase 1: Environment Preparation")
print("=" * 60)
try:
AK, SK, REGION, SECURITY_TOKEN = get_huaweicloud_credentials()
except ValueError as e:
print(f"[ERROR] {e}")
print("\nSet command:")
print(" Windows: set HUAWEICLOUD_SDK_AK=your_ak && set HUAWEICLOUD_SDK_SK=your_sk && set HUAWEICLOUD_REGION=cn-north-4")
print(" Linux/Mac: export HUAWEICLOUD_SDK_AK=your_ak && export HUAWEICLOUD_SDK_SK=your_sk && export HUAWEICLOUD_REGION=cn-north-4")
print("\nFor temporary security credentials (STS token), also set:")
print(" Windows: set HUAWEICLOUD_SDK_SECURITY_TOKEN=your_token")
print(" Linux/Mac: export HUAWEICLOUD_SDK_SECURITY_TOKEN=your_token")
return False, None, None, None, None
print(f"[OK] AK: {AK[:4]}...{AK[-4:]}")
print(f"[OK] SK: {SK[:4]}...{SK[-4:]}")
print(f"[OK] Region: {REGION}")
if SECURITY_TOKEN:
print(f"[OK] Using temporary security credentials (STS token)")
return True, AK, SK, REGION, SECURITY_TOKEN
def check_dependencies():
print("\n[INFO] Checking dependency modules...")
modules = {
'requests': 'requests',
'huaweicloudsdkcore': 'huaweicloudsdkcore',
'huaweicloudsdkcoc': 'huaweicloudsdkcoc',
'huaweicloudsdkrms': 'huaweicloudsdkrms'
}
all_ok = True
for key, module_name in modules.items():
try:
__import__(module_name)
print(f"[OK] {key}")
except ImportError:
print(f"[ERROR] {key} not installed. Please run: pip install {module_name}")
all_ok = False
return all_ok
def verify_credentials(ak, sk, region, security_token=None):
print(f"\n[INFO] Verifying Huawei Cloud credentials...")
print(f"[INFO] Region: {region}")
try:
from huaweicloudsdkcore.signer.signer import Signer
from huaweicloudsdkcore.sdk_request import SdkRequest
from huaweicloudsdkcore.auth.credentials import BasicCredentials
import uuid
# 使用SDK原生凭据,原生支持security_token
credentials = BasicCredentials(ak, sk)
if security_token:
credentials.with_security_token(security_token)
signer = Signer(credentials)
iam_endpoint = f"https://iam.{region}.myhuaweicloud.com/v3/projects"
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())
}
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)
# 临时凭据手动补充X-Security-Token请求头(原生SDK签名后不会自动加,需主动注入)
if security_token:
headers["X-Security-Token"] = security_token
resp = requests.get(iam_endpoint, headers=headers, timeout=30)
if resp.status_code == 200:
print("[OK] Credentials verification successful!")
return True
else:
print(f"[ERROR] Credentials verification failed: HTTP {resp.status_code}, Resp:{resp.text}")
return False
except Exception as e:
print(f"[ERROR] Credentials verification exception: {e}")
import traceback
traceback.print_exc()
return False
def main():
print("=" * 60)
print(" JiuwenSwarm Deployment - Environment Preparation")
print("=" * 60)
credential_result = check_credentials()
if not credential_result[0]:
sys.exit(1)
_, AK, SK, REGION, SECURITY_TOKEN = credential_result
if not check_dependencies():
sys.exit(1)
if not verify_credentials(AK, SK, REGION, SECURITY_TOKEN):
sys.exit(1)
print("\n" + "=" * 60)
print(" Environment preparation completed!")
print("=" * 60)
print("\nNext step: Run create_instance.py to create Flexus L instance")
if __name__ == "__main__":
main()huaweicloudsdkcore>=3.1.0
huaweicloudsdkcoc>=3.1.0
huaweicloudsdkrms>=3.1.0
requests>=2.31.0
pyyaml>=6.0