Compare commits
3 Commits
fix/orches
...
feat/ci-au
| Author | SHA1 | Date | |
|---|---|---|---|
| 9fe44ae560 | |||
| da9dbd7827 | |||
| 7f94ecdc7a |
@@ -337,3 +337,35 @@ steps:
|
|||||||
- security-trivy-api
|
- security-trivy-api
|
||||||
- security-trivy-orchestrator
|
- security-trivy-orchestrator
|
||||||
- security-trivy-web
|
- security-trivy-web
|
||||||
|
|
||||||
|
# ─── Deploy to Docker Swarm (main only) ─────────────────────
|
||||||
|
|
||||||
|
deploy-swarm:
|
||||||
|
image: alpine:3
|
||||||
|
environment:
|
||||||
|
SSH_PRIVATE_KEY:
|
||||||
|
from_secret: ssh_private_key
|
||||||
|
SSH_KNOWN_HOSTS:
|
||||||
|
from_secret: ssh_known_hosts
|
||||||
|
commands:
|
||||||
|
- apk add --no-cache openssh-client
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
# Setup SSH
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
|
||||||
|
chmod 600 ~/.ssh/known_hosts
|
||||||
|
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
|
||||||
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
|
|
||||||
|
# Deploy to swarm
|
||||||
|
echo "🚀 Deploying to Docker Swarm..."
|
||||||
|
ssh -o StrictHostKeyChecking=no mosaic@10.1.1.45 \
|
||||||
|
"cd /opt/mosaic-stack && \
|
||||||
|
docker login git.mosaicstack.dev -u \$(echo \$GITEA_USER) -p \$GITEA_TOKEN || true && \
|
||||||
|
docker stack deploy -c docker-compose.yml mosaic"
|
||||||
|
when:
|
||||||
|
- branch: [main]
|
||||||
|
event: [push, manual, tag]
|
||||||
|
depends_on:
|
||||||
|
- link-packages
|
||||||
|
|||||||
@@ -16,6 +16,21 @@ interface Agent {
|
|||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isWorking(status: string): boolean {
|
||||||
|
const s = status.toLowerCase();
|
||||||
|
return s === "running" || s === "working";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isIdle(status: string): boolean {
|
||||||
|
const s = status.toLowerCase();
|
||||||
|
return s === "idle" || s === "spawning" || s === "waiting" || s === "queued";
|
||||||
|
}
|
||||||
|
|
||||||
|
function isErrored(status: string): boolean {
|
||||||
|
const s = status.toLowerCase();
|
||||||
|
return s === "failed" || s === "error";
|
||||||
|
}
|
||||||
|
|
||||||
export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): React.JSX.Element {
|
export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): React.JSX.Element {
|
||||||
const [agents, setAgents] = useState<Agent[]>([]);
|
const [agents, setAgents] = useState<Agent[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
@@ -74,25 +89,20 @@ export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): Re
|
|||||||
}, [fetchAgents]);
|
}, [fetchAgents]);
|
||||||
|
|
||||||
const getStatusIcon = (status: string): React.JSX.Element => {
|
const getStatusIcon = (status: string): React.JSX.Element => {
|
||||||
const statusLower = status.toLowerCase();
|
if (isWorking(status)) {
|
||||||
switch (statusLower) {
|
|
||||||
case "running":
|
|
||||||
case "working":
|
|
||||||
return <Activity className="w-4 h-4 text-blue-500 animate-pulse" />;
|
return <Activity className="w-4 h-4 text-blue-500 animate-pulse" />;
|
||||||
case "spawning":
|
|
||||||
case "queued":
|
|
||||||
return <Clock className="w-4 h-4 text-yellow-500" />;
|
|
||||||
case "completed":
|
|
||||||
return <CheckCircle className="w-4 h-4 text-green-500" />;
|
|
||||||
case "failed":
|
|
||||||
case "error":
|
|
||||||
return <AlertCircle className="w-4 h-4 text-red-500" />;
|
|
||||||
case "terminated":
|
|
||||||
case "killed":
|
|
||||||
return <CheckCircle className="w-4 h-4 text-gray-500" />;
|
|
||||||
default:
|
|
||||||
return <Clock className="w-4 h-4 text-gray-400" />;
|
|
||||||
}
|
}
|
||||||
|
if (isIdle(status)) {
|
||||||
|
return <Clock className="w-4 h-4 text-yellow-500" />;
|
||||||
|
}
|
||||||
|
if (isErrored(status)) {
|
||||||
|
return <AlertCircle className="w-4 h-4 text-red-500" />;
|
||||||
|
}
|
||||||
|
const s = status.toLowerCase();
|
||||||
|
if (s === "completed" || s === "terminated" || s === "killed") {
|
||||||
|
return <CheckCircle className="w-4 h-4 text-gray-500" />;
|
||||||
|
}
|
||||||
|
return <Clock className="w-4 h-4 text-gray-400" />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStatusText = (status: string): string => {
|
const getStatusText = (status: string): string => {
|
||||||
@@ -121,9 +131,9 @@ export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): Re
|
|||||||
|
|
||||||
const stats = {
|
const stats = {
|
||||||
total: agents.length,
|
total: agents.length,
|
||||||
working: agents.filter((a) => a.status.toLowerCase() === "running").length,
|
working: agents.filter((a) => isWorking(a.status)).length,
|
||||||
idle: agents.filter((a) => a.status.toLowerCase() === "spawning").length,
|
idle: agents.filter((a) => isIdle(a.status)).length,
|
||||||
error: agents.filter((a) => a.status.toLowerCase() === "failed").length,
|
error: agents.filter((a) => isErrored(a.status)).length,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
@@ -176,9 +186,9 @@ export function AgentStatusWidget({ id: _id, config: _config }: WidgetProps): Re
|
|||||||
<div
|
<div
|
||||||
key={agent.agentId}
|
key={agent.agentId}
|
||||||
className={`p-3 rounded-lg border ${
|
className={`p-3 rounded-lg border ${
|
||||||
agent.status.toLowerCase() === "failed"
|
isErrored(agent.status)
|
||||||
? "bg-red-50 border-red-200"
|
? "bg-red-50 border-red-200"
|
||||||
: agent.status.toLowerCase() === "running"
|
: isWorking(agent.status)
|
||||||
? "bg-blue-50 border-blue-200"
|
? "bg-blue-50 border-blue-200"
|
||||||
: "bg-gray-50 border-gray-200"
|
: "bg-gray-50 border-gray-200"
|
||||||
}`}
|
}`}
|
||||||
|
|||||||
Reference in New Issue
Block a user