599 lines
No EOL
21 KiB
YAML
599 lines
No EOL
21 KiB
YAML
---
|
|
# Deploy Veza V5 Ultra applications in containers
|
|
# Builds and runs backend, chat, stream, and web services
|
|
|
|
- name: Deploy Veza V5 Ultra applications
|
|
hosts: edge
|
|
become: true
|
|
gather_facts: true
|
|
|
|
vars:
|
|
domain: "{{ domain | default('veza.talas.fr') }}"
|
|
backend_container: "veza-backend"
|
|
chat_container: "veza-chat"
|
|
stream_container: "veza-stream"
|
|
web_container: "veza-web"
|
|
|
|
tasks:
|
|
- name: Deploy Go Backend API
|
|
block:
|
|
- name: Install Go in backend container
|
|
command: |
|
|
incus exec {{ backend_container }} -- apt update
|
|
incus exec {{ backend_container }} -- apt install -y wget git
|
|
incus exec {{ backend_container }} -- wget https://go.dev/dl/go1.21.5.linux-amd64.tar.gz
|
|
incus exec {{ backend_container }} -- tar -C /usr/local -xzf go1.21.5.linux-amd64.tar.gz
|
|
incus exec {{ backend_container }} -- echo 'export PATH=$PATH:/usr/local/go/bin' >> /root/.bashrc
|
|
register: go_install_result
|
|
failed_when: false
|
|
|
|
- name: Display Go installation result
|
|
debug:
|
|
var: go_install_result.stdout_lines
|
|
|
|
- name: Create backend application directory
|
|
command: |
|
|
incus exec {{ backend_container }} -- mkdir -p /opt/veza-backend
|
|
register: backend_dir_result
|
|
failed_when: false
|
|
|
|
- name: Copy backend source code (placeholder)
|
|
command: |
|
|
incus exec {{ backend_container }} -- bash -c 'cat > /opt/veza-backend/main.go << "EOF"
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
)
|
|
|
|
func main() {
|
|
port := os.Getenv("PORT")
|
|
if port == "" {
|
|
port = "8080"
|
|
}
|
|
|
|
http.HandleFunc("/api/health", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
fmt.Fprintf(w, `{"status":"ok","service":"veza-backend"}`)
|
|
})
|
|
|
|
http.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
fmt.Fprintf(w, `{"message":"Veza V5 Ultra Backend API","version":"1.0.0"}`)
|
|
})
|
|
|
|
log.Printf("Backend API server starting on port %s", port)
|
|
log.Fatal(http.ListenAndServe(":"+port, nil))
|
|
}
|
|
EOF'
|
|
register: backend_code_result
|
|
failed_when: false
|
|
|
|
- name: Build backend application
|
|
command: |
|
|
incus exec {{ backend_container }} -- bash -c "cd /opt/veza-backend && /usr/local/go/bin/go mod init veza-backend && /usr/local/go/bin/go build -ldflags '-s -w' -o veza-backend main.go"
|
|
register: backend_build_result
|
|
failed_when: false
|
|
|
|
- name: Create backend systemd service
|
|
command: |
|
|
incus exec {{ backend_container }} -- bash -c 'cat > /etc/systemd/system/veza-backend.service << "EOF"
|
|
[Unit]
|
|
Description=Veza V5 Ultra Backend API
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=root
|
|
WorkingDirectory=/opt/veza-backend
|
|
ExecStart=/opt/veza-backend/veza-backend
|
|
Restart=always
|
|
RestartSec=5
|
|
Environment=PORT=8080
|
|
Environment=DATABASE_URL=postgresql://veza:password@localhost:5432/veza_db
|
|
Environment=REDIS_URL=redis://localhost:6379
|
|
Environment=JWT_SECRET=super-secret-jwt-key
|
|
Environment=JWT_REFRESH_SECRET=super-secret-refresh-key
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF'
|
|
register: backend_service_result
|
|
failed_when: false
|
|
|
|
- name: Start backend service
|
|
command: |
|
|
incus exec {{ backend_container }} -- systemctl daemon-reload
|
|
incus exec {{ backend_container }} -- systemctl enable veza-backend
|
|
incus exec {{ backend_container }} -- systemctl start veza-backend
|
|
register: backend_start_result
|
|
failed_when: false
|
|
|
|
- name: Check backend service status
|
|
command: |
|
|
incus exec {{ backend_container }} -- systemctl status veza-backend
|
|
register: backend_status
|
|
failed_when: false
|
|
|
|
- name: Display backend status
|
|
debug:
|
|
var: backend_status.stdout_lines
|
|
|
|
rescue:
|
|
- name: Backend deployment failed
|
|
debug:
|
|
msg: "Backend deployment failed, continuing with other services"
|
|
|
|
- name: Deploy Rust Chat Server
|
|
block:
|
|
- name: Install Rust in chat container
|
|
command: |
|
|
incus exec {{ chat_container }} -- apt update
|
|
incus exec {{ chat_container }} -- apt install -y curl git
|
|
incus exec {{ chat_container }} -- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
|
incus exec {{ chat_container }} -- bash -c "source /root/.cargo/env && cargo --version"
|
|
register: rust_install_result
|
|
failed_when: false
|
|
|
|
- name: Display Rust installation result
|
|
debug:
|
|
var: rust_install_result.stdout_lines
|
|
|
|
- name: Create chat application directory
|
|
command: |
|
|
incus exec {{ chat_container }} -- mkdir -p /opt/veza-chat
|
|
register: chat_dir_result
|
|
failed_when: false
|
|
|
|
- name: Copy chat source code (placeholder)
|
|
command: |
|
|
incus exec {{ chat_container }} -- bash -c 'cat > /opt/veza-chat/Cargo.toml << "EOF"
|
|
[package]
|
|
name = "veza-chat"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
|
|
[dependencies]
|
|
tokio = { version = "1.0", features = ["full"] }
|
|
axum = "0.7"
|
|
tower = "0.4"
|
|
tower-http = { version = "0.5", features = ["cors"] }
|
|
serde = { version = "1.0", features = ["derive"] }
|
|
serde_json = "1.0"
|
|
uuid = { version = "1.0", features = ["v4"] }
|
|
tracing = "0.1"
|
|
tracing-subscriber = "0.3"
|
|
EOF'
|
|
register: chat_cargo_result
|
|
failed_when: false
|
|
|
|
- name: Create chat main.rs
|
|
command: |
|
|
incus exec {{ chat_container }} -- tee /opt/veza-chat/src/main.rs << 'EOF'
|
|
use axum::{
|
|
extract::ws::{Message, WebSocket, WebSocketUpgrade},
|
|
response::Response,
|
|
routing::get,
|
|
Router,
|
|
};
|
|
use std::net::SocketAddr;
|
|
use tokio::net::TcpListener;
|
|
use tracing::{info, warn};
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
tracing_subscriber::init();
|
|
|
|
let app = Router::new()
|
|
.route("/ws", get(websocket_handler))
|
|
.route("/health", get(health_handler));
|
|
|
|
let addr = SocketAddr::from(([0, 0, 0, 0], 8081));
|
|
info!("Chat server starting on {}", addr);
|
|
|
|
let listener = TcpListener::bind(addr).await.unwrap();
|
|
axum::serve(listener, app).await.unwrap();
|
|
}
|
|
|
|
async fn websocket_handler(ws: WebSocketUpgrade) -> Response {
|
|
ws.on_upgrade(handle_websocket)
|
|
}
|
|
|
|
async fn handle_websocket(socket: WebSocket) {
|
|
info!("New WebSocket connection");
|
|
|
|
// Simple echo server for now
|
|
let (mut sender, mut receiver) = socket.split();
|
|
|
|
while let Some(msg) = receiver.recv().await {
|
|
match msg {
|
|
Ok(Message::Text(text)) => {
|
|
info!("Received: {}", text);
|
|
if sender.send(Message::Text(format!("Echo: {}", text))).await.is_err() {
|
|
break;
|
|
}
|
|
}
|
|
Ok(Message::Close(_)) => break,
|
|
Err(e) => {
|
|
warn!("WebSocket error: {}", e);
|
|
break;
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
info!("WebSocket connection closed");
|
|
}
|
|
|
|
async fn health_handler() -> &'static str {
|
|
"OK"
|
|
}
|
|
EOF
|
|
register: chat_main_result
|
|
failed_when: false
|
|
|
|
- name: Build chat application
|
|
command: |
|
|
incus exec {{ chat_container }} -- bash -c "cd /opt/veza-chat && source /root/.cargo/env && cargo build --release"
|
|
register: chat_build_result
|
|
failed_when: false
|
|
|
|
- name: Create chat systemd service
|
|
command: |
|
|
incus exec {{ chat_container }} -- tee /etc/systemd/system/veza-chat.service << 'EOF'
|
|
[Unit]
|
|
Description=Veza V5 Ultra Chat Server
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=root
|
|
WorkingDirectory=/opt/veza-chat
|
|
ExecStart=/opt/veza-chat/target/release/veza-chat
|
|
Restart=always
|
|
RestartSec=5
|
|
Environment=SQLX_OFFLINE=true
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
register: chat_service_result
|
|
failed_when: false
|
|
|
|
- name: Start chat service
|
|
command: |
|
|
incus exec {{ chat_container }} -- systemctl daemon-reload
|
|
incus exec {{ chat_container }} -- systemctl enable veza-chat
|
|
incus exec {{ chat_container }} -- systemctl start veza-chat
|
|
register: chat_start_result
|
|
failed_when: false
|
|
|
|
- name: Check chat service status
|
|
command: |
|
|
incus exec {{ chat_container }} -- systemctl status veza-chat
|
|
register: chat_status
|
|
failed_when: false
|
|
|
|
- name: Display chat status
|
|
debug:
|
|
var: chat_status.stdout_lines
|
|
|
|
rescue:
|
|
- name: Chat deployment failed
|
|
debug:
|
|
msg: "Chat deployment failed, continuing with other services"
|
|
|
|
- name: Deploy Rust Stream Server
|
|
block:
|
|
- name: Install Rust in stream container
|
|
command: |
|
|
incus exec {{ stream_container }} -- apt update
|
|
incus exec {{ stream_container }} -- apt install -y curl git
|
|
incus exec {{ stream_container }} -- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
|
register: stream_rust_install_result
|
|
failed_when: false
|
|
|
|
- name: Create stream application directory
|
|
command: |
|
|
incus exec {{ stream_container }} -- mkdir -p /opt/veza-stream
|
|
register: stream_dir_result
|
|
failed_when: false
|
|
|
|
- name: Copy stream source code (placeholder)
|
|
command: |
|
|
incus exec {{ stream_container }} -- tee /opt/veza-stream/Cargo.toml << 'EOF'
|
|
[package]
|
|
name = "veza-stream"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
|
|
[dependencies]
|
|
tokio = { version = "1.0", features = ["full"] }
|
|
axum = "0.7"
|
|
tower = "0.4"
|
|
tower-http = { version = "0.5", features = ["cors", "fs"] }
|
|
serde = { version = "1.0", features = ["derive"] }
|
|
serde_json = "1.0"
|
|
tracing = "0.1"
|
|
tracing-subscriber = "0.3"
|
|
EOF
|
|
register: stream_cargo_result
|
|
failed_when: false
|
|
|
|
- name: Create stream main.rs
|
|
command: |
|
|
incus exec {{ stream_container }} -- tee /opt/veza-stream/src/main.rs << 'EOF'
|
|
use axum::{
|
|
extract::Path,
|
|
http::StatusCode,
|
|
response::Response,
|
|
routing::get,
|
|
Router,
|
|
};
|
|
use std::net::SocketAddr;
|
|
use tokio::net::TcpListener;
|
|
use tracing::{info, warn};
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
tracing_subscriber::init();
|
|
|
|
let app = Router::new()
|
|
.route("/stream/health", get(health_handler))
|
|
.route("/stream/:file", get(stream_handler));
|
|
|
|
let addr = SocketAddr::from(([0, 0, 0, 0], 8082));
|
|
info!("Stream server starting on {}", addr);
|
|
|
|
let listener = TcpListener::bind(addr).await.unwrap();
|
|
axum::serve(listener, app).await.unwrap();
|
|
}
|
|
|
|
async fn health_handler() -> &'static str {
|
|
"OK"
|
|
}
|
|
|
|
async fn stream_handler(Path(file): Path<String>) -> Result<Response, StatusCode> {
|
|
info!("Stream request for: {}", file);
|
|
|
|
// Simple file serving for now
|
|
if file.ends_with(".m3u8") {
|
|
Ok(Response::builder()
|
|
.status(200)
|
|
.header("Content-Type", "application/vnd.apple.mpegurl")
|
|
.body(format!("#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-TARGETDURATION:10\n#EXTINF:10.0,\n{}.ts\n#EXT-X-ENDLIST\n", file.replace(".m3u8", "")))
|
|
.unwrap())
|
|
} else {
|
|
Err(StatusCode::NOT_FOUND)
|
|
}
|
|
}
|
|
EOF
|
|
register: stream_main_result
|
|
failed_when: false
|
|
|
|
- name: Build stream application
|
|
command: |
|
|
incus exec {{ stream_container }} -- bash -c "cd /opt/veza-stream && source /root/.cargo/env && cargo build --release"
|
|
register: stream_build_result
|
|
failed_when: false
|
|
|
|
- name: Create stream systemd service
|
|
command: |
|
|
incus exec {{ stream_container }} -- tee /etc/systemd/system/veza-stream.service << 'EOF'
|
|
[Unit]
|
|
Description=Veza V5 Ultra Stream Server
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=root
|
|
WorkingDirectory=/opt/veza-stream
|
|
ExecStart=/opt/veza-stream/target/release/veza-stream
|
|
Restart=always
|
|
RestartSec=5
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
register: stream_service_result
|
|
failed_when: false
|
|
|
|
- name: Start stream service
|
|
command: |
|
|
incus exec {{ stream_container }} -- systemctl daemon-reload
|
|
incus exec {{ stream_container }} -- systemctl enable veza-stream
|
|
incus exec {{ stream_container }} -- systemctl start veza-stream
|
|
register: stream_start_result
|
|
failed_when: false
|
|
|
|
- name: Check stream service status
|
|
command: |
|
|
incus exec {{ stream_container }} -- systemctl status veza-stream
|
|
register: stream_status
|
|
failed_when: false
|
|
|
|
- name: Display stream status
|
|
debug:
|
|
var: stream_status.stdout_lines
|
|
|
|
rescue:
|
|
- name: Stream deployment failed
|
|
debug:
|
|
msg: "Stream deployment failed, continuing with web service"
|
|
|
|
- name: Deploy React Web Application
|
|
block:
|
|
- name: Install Node.js in web container
|
|
command: |
|
|
incus exec {{ web_container }} -- apt update
|
|
incus exec {{ web_container }} -- apt install -y curl
|
|
incus exec {{ web_container }} -- curl -fsSL https://deb.nodesource.com/setup_18.x | bash -
|
|
incus exec {{ web_container }} -- apt install -y nodejs nginx
|
|
register: node_install_result
|
|
failed_when: false
|
|
|
|
- name: Display Node.js installation result
|
|
debug:
|
|
var: node_install_result.stdout_lines
|
|
|
|
- name: Create web application directory
|
|
command: |
|
|
incus exec {{ web_container }} -- mkdir -p /opt/veza-web
|
|
register: web_dir_result
|
|
failed_when: false
|
|
|
|
- name: Create simple React app (placeholder)
|
|
command: |
|
|
incus exec {{ web_container }} -- tee /opt/veza-web/package.json << 'EOF'
|
|
{
|
|
"name": "veza-web",
|
|
"version": "1.0.0",
|
|
"description": "Veza V5 Ultra Web Application",
|
|
"main": "index.js",
|
|
"scripts": {
|
|
"start": "node server.js",
|
|
"build": "echo 'Build completed'"
|
|
},
|
|
"dependencies": {
|
|
"express": "^4.18.2"
|
|
}
|
|
}
|
|
EOF
|
|
register: web_package_result
|
|
failed_when: false
|
|
|
|
- name: Create simple web server
|
|
command: |
|
|
incus exec {{ web_container }} -- tee /opt/veza-web/server.js << 'EOF'
|
|
const express = require('express');
|
|
const app = express();
|
|
const port = process.env.PORT || 3000;
|
|
|
|
app.use(express.static('public'));
|
|
|
|
app.get('/', (req, res) => {
|
|
res.send(`
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Veza V5 Ultra</title>
|
|
<style>
|
|
body { font-family: Arial, sans-serif; margin: 40px; }
|
|
.container { max-width: 800px; margin: 0 auto; }
|
|
.header { background: #2c3e50; color: white; padding: 20px; border-radius: 5px; }
|
|
.content { padding: 20px; }
|
|
.status { background: #27ae60; color: white; padding: 10px; border-radius: 3px; margin: 10px 0; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<h1>🎵 Veza V5 Ultra</h1>
|
|
<p>Collaborative Audio Streaming Platform</p>
|
|
</div>
|
|
<div class="content">
|
|
<div class="status">✅ System Online</div>
|
|
<h2>Services Status</h2>
|
|
<ul>
|
|
<li>Backend API: <span id="api-status">Checking...</span></li>
|
|
<li>Chat WebSocket: <span id="chat-status">Checking...</span></li>
|
|
<li>Stream HLS: <span id="stream-status">Checking...</span></li>
|
|
</ul>
|
|
<h2>Features</h2>
|
|
<ul>
|
|
<li>Real-time collaborative audio streaming</li>
|
|
<li>WebSocket chat integration</li>
|
|
<li>HLS video streaming</li>
|
|
<li>Modern React frontend</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
// Simple health checks
|
|
fetch('/api/health').then(r => r.json()).then(d => {
|
|
document.getElementById('api-status').textContent = '✅ Online';
|
|
}).catch(() => {
|
|
document.getElementById('api-status').textContent = '❌ Offline';
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|
|
`);
|
|
});
|
|
|
|
app.listen(port, '0.0.0.0', () => {
|
|
console.log(`Veza V5 Ultra web server running on port ${port}`);
|
|
});
|
|
EOF
|
|
register: web_server_result
|
|
failed_when: false
|
|
|
|
- name: Install web dependencies
|
|
command: |
|
|
incus exec {{ web_container }} -- bash -c "cd /opt/veza-web && npm install"
|
|
register: web_install_result
|
|
failed_when: false
|
|
|
|
- name: Create web systemd service
|
|
command: |
|
|
incus exec {{ web_container }} -- tee /etc/systemd/system/veza-web.service << 'EOF'
|
|
[Unit]
|
|
Description=Veza V5 Ultra Web Application
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=root
|
|
WorkingDirectory=/opt/veza-web
|
|
ExecStart=/usr/bin/node server.js
|
|
Restart=always
|
|
RestartSec=5
|
|
Environment=PORT=3000
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
register: web_service_result
|
|
failed_when: false
|
|
|
|
- name: Start web service
|
|
command: |
|
|
incus exec {{ web_container }} -- systemctl daemon-reload
|
|
incus exec {{ web_container }} -- systemctl enable veza-web
|
|
incus exec {{ web_container }} -- systemctl start veza-web
|
|
register: web_start_result
|
|
failed_when: false
|
|
|
|
- name: Check web service status
|
|
command: |
|
|
incus exec {{ web_container }} -- systemctl status veza-web
|
|
register: web_status
|
|
failed_when: false
|
|
|
|
- name: Display web status
|
|
debug:
|
|
var: web_status.stdout_lines
|
|
|
|
rescue:
|
|
- name: Web deployment failed
|
|
debug:
|
|
msg: "Web deployment failed"
|
|
|
|
post_tasks:
|
|
- name: Show all running services
|
|
command: |
|
|
incus exec {{ backend_container }} -- systemctl list-units --type=service --state=running | grep veza || true
|
|
incus exec {{ chat_container }} -- systemctl list-units --type=service --state=running | grep veza || true
|
|
incus exec {{ stream_container }} -- systemctl list-units --type=service --state=running | grep veza || true
|
|
incus exec {{ web_container }} -- systemctl list-units --type=service --state=running | grep veza || true
|
|
register: all_services
|
|
failed_when: false
|
|
|
|
- name: Display all services
|
|
debug:
|
|
var: all_services.stdout_lines |