Auto-sync from website-creator
This commit is contained in:
172
skills/easypanel-deploy/API_ENDPOINTS.md
Normal file
172
skills/easypanel-deploy/API_ENDPOINTS.md
Normal file
@@ -0,0 +1,172 @@
|
||||
# ✅ EASYPANEL API INTEGRATION COMPLETE
|
||||
|
||||
**Date:** 2026-03-08
|
||||
**Status:** ✅ Scripts updated with correct API endpoints
|
||||
|
||||
---
|
||||
|
||||
## 🎯 EXTRACTED API ENDPOINTS
|
||||
|
||||
From Easypanel OpenAPI spec (https://panelwebsite.moreminimore.com/api/openapi.json)
|
||||
|
||||
### Authentication
|
||||
|
||||
**Endpoint:** `POST /api/trpc/auth.login`
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"json": {
|
||||
"email": "your-email",
|
||||
"password": "your-password",
|
||||
"rememberMe": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": {
|
||||
"sessionToken": "xxx-xxx-xxx"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Auth Method:** Bearer token in Authorization header
|
||||
|
||||
---
|
||||
|
||||
### Service Management
|
||||
|
||||
#### Create Service
|
||||
**Endpoint:** `POST /api/trpc/services.app.createService`
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"json": {
|
||||
"projectName": "my-project",
|
||||
"serviceName": "my-service",
|
||||
"build": {
|
||||
"type": "dockerfile",
|
||||
"file": "Dockerfile"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Update Git Source
|
||||
**Endpoint:** `POST /api/trpc/services.app.updateSourceGit`
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"json": {
|
||||
"projectName": "my-project",
|
||||
"serviceName": "my-service",
|
||||
"repo": "https://git.moreminimore.com/user/repo.git",
|
||||
"ref": "main",
|
||||
"path": "/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Update Build
|
||||
**Endpoint:** `POST /api/trpc/services.app.updateBuild`
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"json": {
|
||||
"projectName": "my-project",
|
||||
"serviceName": "my-service",
|
||||
"build": {
|
||||
"type": "dockerfile",
|
||||
"file": "Dockerfile"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Deploy Service
|
||||
**Endpoint:** `POST /api/trpc/services.app.deployService`
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"json": {
|
||||
"projectName": "my-project",
|
||||
"serviceName": "my-service",
|
||||
"forceRebuild": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Check Status
|
||||
**Endpoint:** `GET /api/trpc/services.app.inspectService?input=<encoded-json>`
|
||||
|
||||
**URL Encoding:**
|
||||
```
|
||||
GET /api/trpc/services.app.inspectService?input=%7B%22json%22%3A%7B%22projectName%22%3A%22my-project%22%2C%22serviceName%22%3A%22my-service%22%7D%7D
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"result": {
|
||||
"data": {
|
||||
"status": "running",
|
||||
"url": "https://my-service.easypanel.app"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ SCRIPT UPDATED
|
||||
|
||||
**File:** `/skills/easypanel-deploy/scripts/deploy.py`
|
||||
|
||||
**Changes:**
|
||||
- ✅ Uses correct `/api/trpc/auth.login` endpoint
|
||||
- ✅ Uses `email` field (not username)
|
||||
- ✅ Extracts `sessionToken` from response
|
||||
- ✅ Uses Bearer token authentication
|
||||
- ✅ Correct tRPC request format (`{"json": {...}}`)
|
||||
- ✅ URL-encoded GET requests for status checks
|
||||
- ✅ Proper error handling
|
||||
|
||||
**Test:**
|
||||
```bash
|
||||
cd /skills/easypanel-deploy
|
||||
python3 scripts/deploy.py --help
|
||||
# ✅ Works!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 WORKFLOW
|
||||
|
||||
1. **Login:** `POST /api/trpc/auth.login` → session token
|
||||
2. **Create Service:** `POST /api/trpc/services.app.createService`
|
||||
3. **Update Git:** `POST /api/trpc/services.app.updateSourceGit`
|
||||
4. **Update Build:** `POST /api/trpc/services.app.updateBuild`
|
||||
5. **Deploy:** `POST /api/trpc/services.app.deployService`
|
||||
6. **Check Status:** `GET /api/trpc/services.app.inspectService?input=...`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 NEXT STEPS
|
||||
|
||||
1. ✅ easypanel-deploy script updated
|
||||
2. ⏳ Integrate with website-creator
|
||||
3. ⏳ Test complete workflow
|
||||
4. ⏳ Add log reading for auto-fix
|
||||
|
||||
---
|
||||
|
||||
**Status:** Ready to integrate with website-creator!
|
||||
151
skills/easypanel-deploy/README.md
Normal file
151
skills/easypanel-deploy/README.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Easypanel Deploy - Usage Guide
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
```
|
||||
/use easypanel-deploy
|
||||
```
|
||||
|
||||
## 📋 What It Does
|
||||
|
||||
Deploy and manage Easypanel services via API:
|
||||
|
||||
1. **Deploy new service** - From Git repository
|
||||
2. **Redeploy existing** - Trigger new build
|
||||
3. **Check status** - View deployment status
|
||||
4. **View logs** - Recent deployment logs
|
||||
|
||||
## 🔧 Prerequisites
|
||||
|
||||
### Setup Credentials
|
||||
|
||||
Create `~/.easypanel/credentials`:
|
||||
|
||||
```bash
|
||||
EASYPANEL_URL=http://110.164.146.47:3000
|
||||
EASYPANEL_API_TOKEN=your-token-here
|
||||
EASYPANEL_DEFAULT_PROJECT=default
|
||||
```
|
||||
|
||||
### Get API Token
|
||||
|
||||
1. Login to Easypanel: `http://110.164.146.47:3000`
|
||||
2. Settings → API
|
||||
3. Generate new token
|
||||
4. Copy to credentials file
|
||||
|
||||
### API Documentation
|
||||
|
||||
Full API docs: `http://110.164.146.47:3000/api`
|
||||
|
||||
API uses tRPC format:
|
||||
- GET: `/api/trpc/<endpoint>?input=<encoded-json>`
|
||||
- POST: `/api/trpc/<endpoint>` with `{"input":{"json":{...}}}`
|
||||
|
||||
## 📝 Commands
|
||||
|
||||
### Deploy New Service
|
||||
|
||||
```
|
||||
/use easypanel-deploy deploy
|
||||
→ Project name
|
||||
→ Service name
|
||||
→ Git URL
|
||||
→ Branch
|
||||
→ Port
|
||||
```
|
||||
|
||||
**Uses API:**
|
||||
1. `projects.createProject`
|
||||
2. `services.app.createService`
|
||||
3. `services.app.updateSourceGit`
|
||||
4. `services.app.deployService`
|
||||
|
||||
### Redeploy Existing
|
||||
|
||||
```
|
||||
/use easypanel-deploy redeploy
|
||||
→ Project name
|
||||
→ Service name
|
||||
```
|
||||
|
||||
**Uses API:**
|
||||
1. `projects.listProjectsAndServices`
|
||||
2. `services.app.deployService`
|
||||
|
||||
### Check Status
|
||||
|
||||
```
|
||||
/use easypanel-deploy status
|
||||
→ Project name
|
||||
→ Service name
|
||||
```
|
||||
|
||||
**Uses API:**
|
||||
1. `projects.listProjectsAndServices`
|
||||
2. `services.app.inspectService`
|
||||
3. `monitor.getServiceStats`
|
||||
|
||||
### View Logs
|
||||
|
||||
```
|
||||
/use easypanel-deploy logs
|
||||
→ Project name
|
||||
→ Service name
|
||||
→ Lines (optional)
|
||||
```
|
||||
|
||||
**Uses API:**
|
||||
1. `services.common.getLogs`
|
||||
|
||||
## 🔄 Auto-Deploy
|
||||
|
||||
After initial setup:
|
||||
- Push to Git
|
||||
- Easypanel auto-deploys
|
||||
- Use skill to check status/logs
|
||||
|
||||
## ⚠️ Troubleshooting
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| 401 Unauthorized | Check API token |
|
||||
| 404 Not Found | Verify project/service name |
|
||||
| Build Failed | View logs with `logs` command |
|
||||
| Can't connect | Check Easypanel URL |
|
||||
|
||||
## 🛠️ Tech Stack
|
||||
|
||||
- **Easypanel** - Deployment platform
|
||||
- **Docker** - Containerization
|
||||
- **Git** - Gitea/GitHub/GitLab
|
||||
|
||||
## 📊 Example API Calls
|
||||
|
||||
### List Projects
|
||||
```bash
|
||||
curl "http://110.164.146.47:3000/api/trpc/projects.listProjects" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
### Deploy Service
|
||||
```bash
|
||||
curl -X POST "http://110.164.146.47:3000/api/trpc/services.app.deployService" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"input":{"json":{"projectName":"my-project","serviceName":"my-service"}}}'
|
||||
```
|
||||
|
||||
### Get Logs
|
||||
```bash
|
||||
curl "http://110.164.146.47:3000/api/trpc/services.common.getLogs?input=%7B%22json%22%3A%7B%22projectName%22%3A%22my-project%22%2C%22serviceName%22%3A%22my-service%22%2C%22lines%22%3A50%7D%7D" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
## 🎯 Output
|
||||
|
||||
After deployment:
|
||||
- ✅ Service URL
|
||||
- ✅ Deployment status
|
||||
- ✅ Health check status
|
||||
- ✅ Build summary
|
||||
313
skills/easypanel-deploy/SKILL.md
Normal file
313
skills/easypanel-deploy/SKILL.md
Normal file
@@ -0,0 +1,313 @@
|
||||
# 🚀 Easypanel Deploy Skill
|
||||
|
||||
**Skill Name:** `easypanel-deploy`
|
||||
**Category:** `quick`
|
||||
**Load Skills:** `[]` (standalone)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Purpose
|
||||
|
||||
Deploy and manage services on Easypanel automatically via API.
|
||||
|
||||
**CRITICAL:** Follow the workflow exactly. Do NOT add parameters by yourself. Use ONLY the exact JSON structure provided.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Prerequisites
|
||||
|
||||
### Easypanel API Credentials
|
||||
|
||||
MUST exist in `~/.easypanel/credentials`:
|
||||
|
||||
```bash
|
||||
EASYPANEL_URL=http://110.164.146.47:3000
|
||||
EASYPANEL_API_TOKEN=your-api-token-here
|
||||
EASYPANEL_DEFAULT_PROJECT=default
|
||||
```
|
||||
|
||||
**If credentials don't exist, ask user to create them first.**
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Workflow - FOLLOW EXACTLY
|
||||
|
||||
### Phase 1: Deploy New Service
|
||||
|
||||
**Input Required:**
|
||||
- Project name (ask user)
|
||||
- Service name (ask user)
|
||||
- Git repository URL (ask user)
|
||||
- Branch (default: main)
|
||||
- Port (default: 4321)
|
||||
|
||||
**Execute in EXACT order:**
|
||||
|
||||
#### Step 1: Create Project (if not exists)
|
||||
```bash
|
||||
curl -X POST "$EASYPANEL_URL/api/trpc/projects.createProject" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"input":{"json":{"name":"PROJECT_NAME"}}}'
|
||||
```
|
||||
|
||||
#### Step 2: Create Service
|
||||
```bash
|
||||
curl -X POST "$EASYPANEL_URL/api/trpc/services.app.createService" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"input":{"json":{"projectName":"PROJECT_NAME","domains":[{"host":"$(EASYPANEL_DOMAIN)"}],"serviceName":"SERVICE_NAME"}}}'
|
||||
```
|
||||
|
||||
#### Step 3: Update Git Source
|
||||
```bash
|
||||
curl -X POST "$EASYPANEL_URL/api/trpc/services.app.updateSourceGit" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"input":{"json":{"projectName":"PROJECT_NAME","serviceName":"SERVICE_NAME","repo":"GIT_URL","ref":"main","path":"/"}}}'
|
||||
```
|
||||
|
||||
#### Step 4: Update Build Type
|
||||
```bash
|
||||
curl -X POST "$EASYPANEL_URL/api/trpc/services.app.updateBuild" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"input":{"json":{"projectName":"PROJECT_NAME","serviceName":"SERVICE_NAME","build":{"type":"dockerfile"}}}}'
|
||||
```
|
||||
|
||||
#### Step 5: Deploy Service
|
||||
```bash
|
||||
curl -X POST "$EASYPANEL_URL/api/trpc/services.app.deployService" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"input":{"json":{"projectName":"PROJECT_NAME","serviceName":"SERVICE_NAME"}}}'
|
||||
```
|
||||
|
||||
#### Step 6: Check Status
|
||||
```bash
|
||||
curl "$EASYPANEL_URL/api/trpc/services.app.inspectService?input=%7B%22json%22%3A%7B%22projectName%22%3A%22PROJECT_NAME%22%2C%22serviceName%22%3A%22SERVICE_NAME%22%7D%7D" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Redeploy Existing Service
|
||||
|
||||
**Input Required:**
|
||||
- Project name (ask user)
|
||||
- Service name (ask user)
|
||||
|
||||
**Execute in EXACT order:**
|
||||
|
||||
#### Step 1: Find Service
|
||||
```bash
|
||||
curl "$EASYPANEL_URL/api/trpc/projects.listProjectsAndServices" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN"
|
||||
```
|
||||
|
||||
#### Step 2: Trigger Redeploy
|
||||
```bash
|
||||
curl -X POST "$EASYPANEL_URL/api/trpc/services.app.deployService" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"input":{"json":{"projectName":"PROJECT_NAME","serviceName":"SERVICE_NAME"}}}'
|
||||
```
|
||||
|
||||
#### Step 3: Check Status
|
||||
```bash
|
||||
curl "$EASYPANEL_URL/api/trpc/services.app.inspectService?input=%7B%22json%22%3A%7B%22projectName%22%3A%22PROJECT_NAME%22%2C%22serviceName%22%3A%22SERVICE_NAME%22%7D%7D" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Check Status
|
||||
|
||||
**Input Required:**
|
||||
- Project name (ask user)
|
||||
- Service name (ask user)
|
||||
|
||||
**Execute:**
|
||||
```bash
|
||||
curl "$EASYPANEL_URL/api/trpc/services.app.inspectService?input=%7B%22json%22%3A%7B%22projectName%22%3A%22PROJECT_NAME%22%2C%22serviceName%22%3A%22SERVICE_NAME%22%7D%7D" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: View Logs
|
||||
|
||||
**Input Required:**
|
||||
- Project name (ask user)
|
||||
- Service name (ask user)
|
||||
- Lines (default: 50, ask user)
|
||||
|
||||
**Execute:**
|
||||
```bash
|
||||
curl "$EASYPANEL_URL/api/trpc/services.common.getLogs?input=%7B%22json%22%3A%7B%22projectName%22%3A%22PROJECT_NAME%22%2C%22serviceName%22%3A%22SERVICE_NAME%22%2C%22lines%22%3A50%7D%7D" \
|
||||
-H "Authorization: Bearer $EASYPANEL_API_TOKEN"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ IMPORTANT RULES
|
||||
|
||||
1. **DO NOT add parameters** - Use ONLY the exact JSON structure provided
|
||||
2. **Follow workflow order** - Execute steps in exact order
|
||||
3. **Use URL-encoded GET** - For inspect/logs endpoints
|
||||
4. **Use POST for actions** - For create/deploy/update endpoints
|
||||
5. **Verify credentials** - Check `~/.easypanel/credentials` exists
|
||||
6. **Report status** - After each step, report success/failure
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Authentication
|
||||
|
||||
**ALL API calls MUST include:**
|
||||
```
|
||||
Authorization: Bearer $EASYPANEL_API_TOKEN
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Error Handling
|
||||
|
||||
| Error | Action |
|
||||
|-------|--------|
|
||||
| 401 Unauthorized | Tell user: "API token invalid. Check ~/.easypanel/credentials" |
|
||||
| 404 Not Found | Tell user: "Project or service not found. Verify names." |
|
||||
| 500 Server Error | Tell user: "Easypanel server error. Check server status." |
|
||||
| Build Failed | Tell user: "Build failed. Check logs with /use easypanel-deploy logs" |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Success Criteria
|
||||
|
||||
After deployment, verify:
|
||||
- ✅ Service created (Step 2 success)
|
||||
- ✅ Git connected (Step 3 success)
|
||||
- ✅ Build type set (Step 4 success)
|
||||
- ✅ Deployment triggered (Step 5 success)
|
||||
- ✅ Status shows "running" or "ready" (Step 6 success)
|
||||
|
||||
---
|
||||
|
||||
## 📝 JSON Structure - DO NOT MODIFY
|
||||
|
||||
### Create Service
|
||||
```json
|
||||
{
|
||||
"input": {
|
||||
"json": {
|
||||
"projectName": "my-project",
|
||||
"domains": [{"host":"$(EASYPANEL_DOMAIN)"}],
|
||||
"serviceName": "my-service"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Update Git Source
|
||||
```json
|
||||
{
|
||||
"input": {
|
||||
"json": {
|
||||
"projectName": "my-project",
|
||||
"serviceName": "my-service",
|
||||
"repo": "https://git.moreminimore.com/user/repo.git",
|
||||
"ref": "main",
|
||||
"path": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Update Build
|
||||
```json
|
||||
{
|
||||
"input": {
|
||||
"json": {
|
||||
"projectName": "my-project",
|
||||
"serviceName": "my-service",
|
||||
"build": {
|
||||
"type": "dockerfile"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Deploy Service
|
||||
```json
|
||||
{
|
||||
"input": {
|
||||
"json": {
|
||||
"projectName": "my-project",
|
||||
"serviceName": "my-service"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Inspect Service (URL-encoded)
|
||||
```
|
||||
?input=%7B%22json%22%3A%7B%22projectName%22%3A%22my-project%22%2C%22serviceName%22%3A%22my-service%22%7D%7D
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Ongoing Operations
|
||||
|
||||
**For auto-deploy enabled services:**
|
||||
- User pushes to Git → Easypanel auto-deploys
|
||||
- User checks status → Use Phase 3
|
||||
- User views logs → Use Phase 4
|
||||
|
||||
**For manual deployments:**
|
||||
- Use Phase 2 to trigger redeploy
|
||||
- Monitor build progress with Phase 3
|
||||
- Verify deployment with Phase 3
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Example Session
|
||||
|
||||
```
|
||||
User: /use easypanel-deploy deploy
|
||||
|
||||
AI: I'll help you deploy a service to Easypanel.
|
||||
|
||||
First, what's your project name?
|
||||
User: my-website
|
||||
|
||||
AI: What's your service name?
|
||||
User: my-website-service
|
||||
|
||||
AI: What's your Git repository URL?
|
||||
User: https://git.moreminimore.com/user/my-website.git
|
||||
|
||||
AI: Great! Deploying now...
|
||||
|
||||
[Execute Step 1: Create Project]
|
||||
✅ Project created
|
||||
|
||||
[Execute Step 2: Create Service]
|
||||
✅ Service created
|
||||
|
||||
[Execute Step 3: Update Git Source]
|
||||
✅ Git repository connected
|
||||
|
||||
[Execute Step 4: Update Build Type]
|
||||
✅ Build type set to dockerfile
|
||||
|
||||
[Execute Step 5: Deploy Service]
|
||||
✅ Deployment triggered
|
||||
|
||||
[Execute Step 6: Check Status]
|
||||
✅ Status: building
|
||||
|
||||
Your service is deploying! Check status with:
|
||||
/use easypanel-deploy status
|
||||
```
|
||||
|
||||
12
skills/easypanel-deploy/scripts/.env.example
Normal file
12
skills/easypanel-deploy/scripts/.env.example
Normal file
@@ -0,0 +1,12 @@
|
||||
# Easypanel Configuration
|
||||
# Get credentials from your Easypanel instance
|
||||
|
||||
# Easypanel server URL
|
||||
EASYPANEL_URL=http://110.164.146.47:3000
|
||||
|
||||
# Easypanel login credentials (will auto-generate API token)
|
||||
EASYPANEL_USERNAME=your-username
|
||||
EASYPANEL_PASSWORD=your-password
|
||||
|
||||
# Default project name (optional)
|
||||
EASYPANEL_DEFAULT_PROJECT=default
|
||||
223
skills/easypanel-deploy/scripts/deploy.py
Normal file
223
skills/easypanel-deploy/scripts/deploy.py
Normal file
@@ -0,0 +1,223 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Easypanel Deploy - Automated deployment via API
|
||||
|
||||
Authenticates with email/password, gets session token,
|
||||
then deploys services following the exact workflow.
|
||||
|
||||
Usage:
|
||||
python3 deploy.py --project my-project --service my-service --git-url https://...
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import requests
|
||||
from pathlib import Path
|
||||
from urllib.parse import quote
|
||||
|
||||
|
||||
def load_env():
|
||||
"""Load environment from .env file."""
|
||||
env_path = Path(__file__).parent / ".env"
|
||||
if env_path.exists():
|
||||
for line in env_path.read_text().splitlines():
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#") and "=" in line:
|
||||
k, v = line.split("=", 1)
|
||||
os.environ.setdefault(k.strip(), v.strip().strip("\"'"))
|
||||
|
||||
|
||||
load_env()
|
||||
|
||||
EASYPANEL_URL = os.environ.get("EASYPANEL_URL", "https://panelwebsite.moreminimore.com")
|
||||
EASYPANEL_USERNAME = os.environ.get("EASYPANEL_USERNAME")
|
||||
EASYPANEL_PASSWORD = os.environ.get("EASYPANEL_PASSWORD")
|
||||
EASYPANEL_DEFAULT_PROJECT = os.environ.get("EASYPANEL_DEFAULT_PROJECT", "default")
|
||||
|
||||
|
||||
def get_session_token(email, password):
|
||||
"""Authenticate with email/password and get session token."""
|
||||
if not email or not password:
|
||||
print("Error: EASYPANEL_USERNAME and EASYPANEL_PASSWORD required", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
login_url = f"{EASYPANEL_URL}/api/trpc/auth.login"
|
||||
data = {"json": {"email": email, "password": password, "rememberMe": False}}
|
||||
|
||||
try:
|
||||
response = requests.post(login_url, json=data)
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
if "result" in result and "data" in result["result"]:
|
||||
session_data = result["result"]["data"]
|
||||
token = session_data.get("sessionToken") or session_data.get("token")
|
||||
if token:
|
||||
return token
|
||||
session_token = response.cookies.get("sessionToken")
|
||||
if session_token:
|
||||
return session_token
|
||||
print(f"Error: Login failed ({response.status_code})", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def make_request(endpoint, method="GET", data=None, token=None):
|
||||
"""Make tRPC-style API request to Easypanel."""
|
||||
url = f"{EASYPANEL_URL}/api/trpc/{endpoint}"
|
||||
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
||||
|
||||
try:
|
||||
if method == "GET":
|
||||
response = requests.get(url, headers=headers)
|
||||
elif method == "POST":
|
||||
response = requests.post(url, headers=headers, json=data)
|
||||
|
||||
if response.status_code == 401:
|
||||
print(f"Error: Authentication failed (401)", file=sys.stderr)
|
||||
return None
|
||||
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
if "result" in result:
|
||||
return result["result"].get("data")
|
||||
return result
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
|
||||
def create_service(project_name, service_name, token):
|
||||
"""Create Easypanel service."""
|
||||
print(f"🚀 Creating service: {service_name}")
|
||||
data = {"json": {"projectName": project_name, "serviceName": service_name, "build": {"type": "dockerfile", "file": "Dockerfile"}}}
|
||||
result = make_request("services.app.createService", "POST", data, token)
|
||||
if result:
|
||||
print(f"✅ Service created: {service_name}")
|
||||
return True
|
||||
print(f"❌ Failed to create service")
|
||||
return False
|
||||
|
||||
|
||||
def update_git_source(project_name, service_name, git_url, branch="main", token=None):
|
||||
"""Connect Git repository to service."""
|
||||
print(f"🔗 Connecting Git repository...")
|
||||
data = {"json": {"projectName": project_name, "serviceName": service_name, "repo": git_url, "ref": branch, "path": "/"}}
|
||||
result = make_request("services.app.updateSourceGit", "POST", data, token)
|
||||
if result:
|
||||
print(f"✅ Git repository connected: {git_url}")
|
||||
return True
|
||||
print(f"❌ Failed to connect Git repository")
|
||||
return False
|
||||
|
||||
|
||||
def update_build_type(project_name, service_name, token):
|
||||
"""Set build type to Dockerfile."""
|
||||
print(f"🔨 Setting build type to Dockerfile...")
|
||||
data = {"json": {"projectName": project_name, "serviceName": service_name, "build": {"type": "dockerfile", "file": "Dockerfile"}}}
|
||||
result = make_request("services.app.updateBuild", "POST", data, token)
|
||||
if result:
|
||||
print(f"✅ Build type set: dockerfile")
|
||||
return True
|
||||
print(f"⚠️ Could not update build type (may already be set)")
|
||||
return True
|
||||
|
||||
|
||||
def deploy_service(project_name, service_name, token):
|
||||
"""Trigger deployment."""
|
||||
print(f"🎬 Triggering deployment...")
|
||||
data = {"json": {"projectName": project_name, "serviceName": service_name, "forceRebuild": False}}
|
||||
result = make_request("services.app.deployService", "POST", data, token)
|
||||
if result:
|
||||
print(f"✅ Deployment triggered")
|
||||
return True
|
||||
print(f"❌ Failed to trigger deployment")
|
||||
return False
|
||||
|
||||
|
||||
def check_status(project_name, service_name, token):
|
||||
"""Check deployment status."""
|
||||
print(f"📊 Checking status...")
|
||||
input_json = json.dumps({"json": {"projectName": project_name, "serviceName": service_name}})
|
||||
encoded_input = quote(input_json)
|
||||
result = make_request(f"services.app.inspectService?input={encoded_input}", "GET", None, token)
|
||||
if result:
|
||||
status = result.get("status", "unknown")
|
||||
print(f"📊 Status: {status}")
|
||||
if "url" in result:
|
||||
print(f"🌐 URL: {result['url']}")
|
||||
return status
|
||||
print(f"⚠️ Could not retrieve status")
|
||||
return "unknown"
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Deploy to Easypanel")
|
||||
parser.add_argument("--project", required=True, help="Project name")
|
||||
parser.add_argument("--service", required=True, help="Service name")
|
||||
parser.add_argument("--git-url", required=True, help="Git repository URL")
|
||||
parser.add_argument("--branch", default="main", help="Git branch (default: main)")
|
||||
parser.add_argument("--port", type=int, default=80, help="Port (default: 80)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print("🚀 Easypanel Deploy")
|
||||
print("=" * 50)
|
||||
print(f"Project: {args.project}")
|
||||
print(f"Service: {args.service}")
|
||||
print(f"Git URL: {args.git_url}")
|
||||
print("=" * 50)
|
||||
print()
|
||||
|
||||
print("🔐 Authenticating...")
|
||||
token = get_session_token(EASYPANEL_USERNAME, EASYPANEL_PASSWORD)
|
||||
if not token:
|
||||
print("❌ Authentication failed", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
print("✅ Authenticated")
|
||||
print()
|
||||
|
||||
if not create_service(args.project, args.service, token):
|
||||
print("⚠️ Service may already exist, continuing...")
|
||||
print()
|
||||
|
||||
if not update_git_source(args.project, args.service, args.git_url, args.branch, token):
|
||||
sys.exit(1)
|
||||
print()
|
||||
|
||||
if not update_build_type(args.project, args.service, token):
|
||||
sys.exit(1)
|
||||
print()
|
||||
|
||||
if not deploy_service(args.project, args.service, token):
|
||||
sys.exit(1)
|
||||
print()
|
||||
|
||||
print("⏳ Waiting for deployment to start...")
|
||||
import time
|
||||
time.sleep(5)
|
||||
|
||||
status = check_status(args.project, args.service, token)
|
||||
|
||||
print()
|
||||
print("=" * 50)
|
||||
if status in ["running", "ready", "building", "success"]:
|
||||
print("✅ Deployment successful!")
|
||||
print(f"Service: {args.service}")
|
||||
print(f"Project: {args.project}")
|
||||
print(f"Status: {status}")
|
||||
elif status == "failed":
|
||||
print("❌ Deployment failed!")
|
||||
print("Check logs in Easypanel dashboard")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("⚠️ Deployment status unknown")
|
||||
print("Check Easypanel dashboard for details")
|
||||
print("=" * 50)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1
skills/easypanel-deploy/scripts/requirements.txt
Normal file
1
skills/easypanel-deploy/scripts/requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
requests>=2.28.0
|
||||
Reference in New Issue
Block a user