forked from extern/dockge
WIP
This commit is contained in:
parent
d99f21fe93
commit
d655a8cc21
151
backend/agent-manager.ts
Normal file
151
backend/agent-manager.ts
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import { DockgeSocket } from "./util-server";
|
||||||
|
import { io, Socket as SocketClient } from "socket.io-client";
|
||||||
|
import { log } from "./log";
|
||||||
|
import { Agent } from "./models/agent";
|
||||||
|
import { LooseObject } from "../common/util-common";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dockge Instance Manager
|
||||||
|
*/
|
||||||
|
export class AgentManager {
|
||||||
|
|
||||||
|
protected socket : DockgeSocket;
|
||||||
|
protected instanceSocketList : Record<string, SocketClient> = {};
|
||||||
|
|
||||||
|
constructor(socket: DockgeSocket) {
|
||||||
|
this.socket = socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(url : string, username : string, password : string) {
|
||||||
|
let obj = new URL(url);
|
||||||
|
let endpoint = obj.host;
|
||||||
|
|
||||||
|
this.socket.emit("agentStatus", {
|
||||||
|
endpoint: endpoint,
|
||||||
|
status: "connecting",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!endpoint) {
|
||||||
|
log.error("agent-manager", "Invalid endpoint: " + endpoint + " URL: " + url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.instanceSocketList[endpoint]) {
|
||||||
|
log.debug("agent-manager", "Already connected to the socket server: " + endpoint);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("agent-manager", "Connecting to the socket server: " + endpoint);
|
||||||
|
let client = io(url, {
|
||||||
|
extraHeaders: {
|
||||||
|
endpoint,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("connect", () => {
|
||||||
|
log.info("agent-manager", "Connected to the socket server: " + endpoint);
|
||||||
|
|
||||||
|
client.emit("login", {
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
}, (res) => {
|
||||||
|
if (res.ok) {
|
||||||
|
log.info("agent-manager", "Logged in to the socket server: " + endpoint);
|
||||||
|
this.socket.emit("agentStatus", {
|
||||||
|
endpoint: endpoint,
|
||||||
|
status: "online",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
log.error("agent-manager", "Failed to login to the socket server: " + endpoint);
|
||||||
|
this.socket.emit("agentStatus", {
|
||||||
|
endpoint: endpoint,
|
||||||
|
status: "offline",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("error", (err) => {
|
||||||
|
log.error("agent-manager", "Error from the socket server: " + endpoint);
|
||||||
|
log.error("agent-manager", err);
|
||||||
|
this.socket.emit("agentStatus", {
|
||||||
|
endpoint: endpoint,
|
||||||
|
status: "offline",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("disconnect", () => {
|
||||||
|
log.info("agent-manager", "Disconnected from the socket server: " + endpoint);
|
||||||
|
this.socket.emit("agentStatus", {
|
||||||
|
endpoint: endpoint,
|
||||||
|
status: "offline",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("agent", (...args : unknown[]) => {
|
||||||
|
log.debug("agent-manager", "Forward event");
|
||||||
|
this.socket.emit("agent", ...args);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.instanceSocketList[endpoint] = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect(endpoint : string) {
|
||||||
|
let client = this.instanceSocketList[endpoint];
|
||||||
|
client?.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectAll() {
|
||||||
|
if (this.socket.endpoint) {
|
||||||
|
log.info("agent-manager", "This connection is connected as an agent, skip connectAll()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let list : Record<string, Agent> = await Agent.getAgentList();
|
||||||
|
|
||||||
|
if (Object.keys(list).length !== 0) {
|
||||||
|
log.info("agent-manager", "Connecting to all instance socket server(s)...");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let endpoint in list) {
|
||||||
|
let agent = list[endpoint];
|
||||||
|
this.connect(agent.url, agent.username, agent.password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectAll() {
|
||||||
|
for (let endpoint in this.instanceSocketList) {
|
||||||
|
this.disconnect(endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emitToEndpoint(endpoint: string, eventName: string, ...args : unknown[]) {
|
||||||
|
log.debug("agent-manager", "Emitting event to endpoint: " + endpoint);
|
||||||
|
let client = this.instanceSocketList[endpoint];
|
||||||
|
if (!client) {
|
||||||
|
log.error("agent-manager", "Socket client not found for endpoint: " + endpoint);
|
||||||
|
throw new Error("Socket client not found for endpoint: " + endpoint);
|
||||||
|
}
|
||||||
|
client?.emit("agent", endpoint, eventName, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
emitToAllEndpoints(eventName: string, ...args : unknown[]) {
|
||||||
|
log.debug("agent-manager", "Emitting event to all endpoints");
|
||||||
|
for (let endpoint in this.instanceSocketList) {
|
||||||
|
this.emitToEndpoint(endpoint, eventName, ...args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendAgentList() {
|
||||||
|
let list = await Agent.getAgentList();
|
||||||
|
let result : Record<string, LooseObject> = {};
|
||||||
|
for (let endpoint in list) {
|
||||||
|
let agent = list[endpoint];
|
||||||
|
result[endpoint] = agent.toJSON();
|
||||||
|
}
|
||||||
|
this.socket.emit("agentList", {
|
||||||
|
ok: true,
|
||||||
|
agentList: result,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,121 +0,0 @@
|
|||||||
import { DockgeSocket } from "./util-server";
|
|
||||||
import { io, Socket as SocketClient } from "socket.io-client";
|
|
||||||
import { log } from "./log";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dockge Instance Manager
|
|
||||||
*/
|
|
||||||
export class DockgeInstanceManager {
|
|
||||||
|
|
||||||
protected socket : DockgeSocket;
|
|
||||||
protected instanceSocketList : Record<string, SocketClient> = {};
|
|
||||||
|
|
||||||
constructor(socket: DockgeSocket) {
|
|
||||||
this.socket = socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(endpoint : string, tls : boolean, username : string, password : string) {
|
|
||||||
if (this.instanceSocketList[endpoint]) {
|
|
||||||
log.debug("INSTANCEMANAGER", "Already connected to the socket server: " + endpoint);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let url = ((tls) ? "wss://" : "ws://") + endpoint;
|
|
||||||
|
|
||||||
log.info("INSTANCEMANAGER", "Connecting to the socket server: " + endpoint);
|
|
||||||
let client = io(url, {
|
|
||||||
transports: [ "websocket", "polling" ],
|
|
||||||
extraHeaders: {
|
|
||||||
endpoint,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on("connect", () => {
|
|
||||||
log.info("INSTANCEMANAGER", "Connected to the socket server: " + endpoint);
|
|
||||||
|
|
||||||
client.emit("login", {
|
|
||||||
username: username,
|
|
||||||
password: password,
|
|
||||||
}, (res) => {
|
|
||||||
if (res.ok) {
|
|
||||||
log.info("INSTANCEMANAGER", "Logged in to the socket server: " + endpoint);
|
|
||||||
} else {
|
|
||||||
log.error("INSTANCEMANAGER", "Failed to login to the socket server: " + endpoint);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on("error", (err) => {
|
|
||||||
log.error("INSTANCEMANAGER", "Error from the socket server: " + endpoint);
|
|
||||||
log.error("INSTANCEMANAGER", err);
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on("disconnect", () => {
|
|
||||||
log.info("INSTANCEMANAGER", "Disconnected from the socket server: " + endpoint);
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on("agent", (...args : unknown[]) => {
|
|
||||||
log.debug("INSTANCEMANAGER", "Forward event");
|
|
||||||
this.socket.emit("agent", ...args);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.instanceSocketList[endpoint] = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnect(endpoint : string) {
|
|
||||||
let client = this.instanceSocketList[endpoint];
|
|
||||||
client?.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
connectAll() {
|
|
||||||
if (this.socket.endpoint) {
|
|
||||||
log.info("INSTANCEMANAGER", "This connection is connected as an agent, skip connectAll()");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let list : Record<string, {tls : boolean, username : string, password : string}> = {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.DOCKGE_TEST_REMOTE_HOST) {
|
|
||||||
list[process.env.DOCKGE_TEST_REMOTE_HOST] = {
|
|
||||||
tls: false,
|
|
||||||
username: "admin",
|
|
||||||
password: process.env.DOCKGE_TEST_REMOTE_PW || "",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.keys(list).length !== 0) {
|
|
||||||
log.info("INSTANCEMANAGER", "Connecting to all instance socket server(s)...");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let endpoint in list) {
|
|
||||||
let item = list[endpoint];
|
|
||||||
this.connect(endpoint, item.tls, item.username, item.password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnectAll() {
|
|
||||||
for (let endpoint in this.instanceSocketList) {
|
|
||||||
this.disconnect(endpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emitToEndpoint(endpoint: string, eventName: string, ...args : unknown[]) {
|
|
||||||
log.debug("INSTANCEMANAGER", "Emitting event to endpoint: " + endpoint);
|
|
||||||
let client = this.instanceSocketList[endpoint];
|
|
||||||
if (!client) {
|
|
||||||
log.error("INSTANCEMANAGER", "Socket client not found for endpoint: " + endpoint);
|
|
||||||
throw new Error("Socket client not found for endpoint: " + endpoint);
|
|
||||||
}
|
|
||||||
client?.emit("agent", endpoint, eventName, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
emitToAllEndpoints(eventName: string, ...args : unknown[]) {
|
|
||||||
log.debug("INSTANCEMANAGER", "Emitting event to all endpoints");
|
|
||||||
for (let endpoint in this.instanceSocketList) {
|
|
||||||
this.emitToEndpoint(endpoint, eventName, ...args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -31,10 +31,11 @@ import { Cron } from "croner";
|
|||||||
import gracefulShutdown from "http-graceful-shutdown";
|
import gracefulShutdown from "http-graceful-shutdown";
|
||||||
import User from "./models/user";
|
import User from "./models/user";
|
||||||
import childProcessAsync from "promisify-child-process";
|
import childProcessAsync from "promisify-child-process";
|
||||||
import { DockgeInstanceManager } from "./dockge-instance-manager";
|
import { AgentManager } from "./agent-manager";
|
||||||
import { AgentProxySocketHandler } from "./socket-handlers/agent-proxy-socket-handler";
|
import { AgentProxySocketHandler } from "./socket-handlers/agent-proxy-socket-handler";
|
||||||
import { AgentSocketHandler } from "./agent-socket-handler";
|
import { AgentSocketHandler } from "./agent-socket-handler";
|
||||||
import { AgentSocket } from "../common/agent-socket";
|
import { AgentSocket } from "../common/agent-socket";
|
||||||
|
import { ManageAgentSocketHandler } from "./socket-handlers/manage-agent-socket-handler";
|
||||||
|
|
||||||
export class DockgeServer {
|
export class DockgeServer {
|
||||||
app : Express;
|
app : Express;
|
||||||
@ -56,6 +57,7 @@ export class DockgeServer {
|
|||||||
*/
|
*/
|
||||||
socketHandlerList : SocketHandler[] = [
|
socketHandlerList : SocketHandler[] = [
|
||||||
new MainSocketHandler(),
|
new MainSocketHandler(),
|
||||||
|
new ManageAgentSocketHandler(),
|
||||||
];
|
];
|
||||||
|
|
||||||
agentProxySocketHandler = new AgentProxySocketHandler();
|
agentProxySocketHandler = new AgentProxySocketHandler();
|
||||||
@ -206,7 +208,7 @@ export class DockgeServer {
|
|||||||
cors,
|
cors,
|
||||||
allowRequest: (req, callback) => {
|
allowRequest: (req, callback) => {
|
||||||
let isOriginValid = true;
|
let isOriginValid = true;
|
||||||
const bypass = isDev;
|
const bypass = isDev || process.env.UPTIME_KUMA_WS_ORIGIN_CHECK === "bypass";
|
||||||
|
|
||||||
if (!bypass) {
|
if (!bypass) {
|
||||||
let host = req.headers.host;
|
let host = req.headers.host;
|
||||||
@ -241,14 +243,14 @@ export class DockgeServer {
|
|||||||
|
|
||||||
this.io.on("connection", async (socket: Socket) => {
|
this.io.on("connection", async (socket: Socket) => {
|
||||||
let dockgeSocket = socket as DockgeSocket;
|
let dockgeSocket = socket as DockgeSocket;
|
||||||
dockgeSocket.instanceManager = new DockgeInstanceManager(dockgeSocket);
|
dockgeSocket.instanceManager = new AgentManager(dockgeSocket);
|
||||||
dockgeSocket.emitAgent = (event : string, ...args : unknown[]) => {
|
dockgeSocket.emitAgent = (event : string, ...args : unknown[]) => {
|
||||||
let obj = args[0];
|
let obj = args[0];
|
||||||
if (typeof(obj) === "object") {
|
if (typeof(obj) === "object") {
|
||||||
let obj2 = obj as LooseObject;
|
let obj2 = obj as LooseObject;
|
||||||
obj2.endpoint = dockgeSocket.endpoint;
|
obj2.endpoint = dockgeSocket.endpoint;
|
||||||
}
|
}
|
||||||
dockgeSocket.emit("agent", event, ...args);
|
this.io.to(dockgeSocket.userID + "").emit("agent", event, ...args);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof(socket.request.headers.endpoint) === "string") {
|
if (typeof(socket.request.headers.endpoint) === "string") {
|
||||||
@ -330,6 +332,8 @@ export class DockgeServer {
|
|||||||
log.error("server", e);
|
log.error("server", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socket.instanceManager.sendAgentList();
|
||||||
|
|
||||||
// Also connect to other dockge instances
|
// Also connect to other dockge instances
|
||||||
socket.instanceManager.connectAll();
|
socket.instanceManager.connectAll();
|
||||||
}
|
}
|
||||||
@ -605,25 +609,6 @@ export class DockgeServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendStackStatusList() {
|
|
||||||
let statusList = await Stack.getStatusList();
|
|
||||||
|
|
||||||
let roomList = this.io.sockets.adapter.rooms.keys();
|
|
||||||
|
|
||||||
for (let room of roomList) {
|
|
||||||
// Check if the room is a number (user id)
|
|
||||||
if (Number(room)) {
|
|
||||||
log.debug("server", "Send stack status list to room " + room);
|
|
||||||
this.io.to(room).emit("stackStatusList", {
|
|
||||||
ok: true,
|
|
||||||
stackStatusList: Object.fromEntries(statusList),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
log.debug("server", "Skip sending stack status list to room " + room);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDockerNetworkList() : Promise<string[]> {
|
async getDockerNetworkList() : Promise<string[]> {
|
||||||
let res = await childProcessAsync.spawn("docker", [ "network", "ls", "--format", "{{.Name}}" ], {
|
let res = await childProcessAsync.spawn("docker", [ "network", "ls", "--format", "{{.Name}}" ], {
|
||||||
encoding: "utf-8",
|
encoding: "utf-8",
|
||||||
|
16
backend/migrations/2023-12-20-2117-agent-table.ts
Normal file
16
backend/migrations/2023-12-20-2117-agent-table.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
// Create the user table
|
||||||
|
return knex.schema.createTable("agent", (table) => {
|
||||||
|
table.increments("id");
|
||||||
|
table.string("url", 255).notNullable().unique();
|
||||||
|
table.string("username", 255).notNullable();
|
||||||
|
table.string("password", 255).notNullable();
|
||||||
|
table.boolean("active").notNullable().defaultTo(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
return knex.schema.dropTable("agent");
|
||||||
|
}
|
33
backend/models/agent.ts
Normal file
33
backend/models/agent.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { BeanModel } from "redbean-node/dist/bean-model";
|
||||||
|
import { R } from "redbean-node";
|
||||||
|
import { LooseObject } from "../../common/util-common";
|
||||||
|
import User from "./user";
|
||||||
|
|
||||||
|
export class Agent extends BeanModel {
|
||||||
|
|
||||||
|
static async getAgentList() : Promise<Record<string, Agent>> {
|
||||||
|
let list = await R.findAll("agent") as Agent[];
|
||||||
|
let result : Record<string, Agent> = {};
|
||||||
|
for (let agent of list) {
|
||||||
|
result[agent.endpoint] = agent;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
get endpoint() : string {
|
||||||
|
let obj = new URL(this.url);
|
||||||
|
return obj.host;
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() : LooseObject {
|
||||||
|
return {
|
||||||
|
url: this.url,
|
||||||
|
username: this.username,
|
||||||
|
password: this.password,
|
||||||
|
endpoint: this.endpoint,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Agent;
|
13
backend/socket-handlers/manage-agent-socket-handler.ts
Normal file
13
backend/socket-handlers/manage-agent-socket-handler.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { SocketHandler } from "../socket-handler.js";
|
||||||
|
import { DockgeServer } from "../dockge-server";
|
||||||
|
import { log } from "../log";
|
||||||
|
import { checkLogin, DockgeSocket } from "../util-server";
|
||||||
|
import { AgentSocket } from "../../common/agent-socket";
|
||||||
|
import { ALL_ENDPOINTS } from "../../common/util-common";
|
||||||
|
|
||||||
|
export class ManageAgentSocketHandler extends SocketHandler {
|
||||||
|
|
||||||
|
create(socket : DockgeSocket, server : DockgeServer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ import { ERROR_TYPE_VALIDATION } from "../common/util-common";
|
|||||||
import { R } from "redbean-node";
|
import { R } from "redbean-node";
|
||||||
import { verifyPassword } from "./password-hash";
|
import { verifyPassword } from "./password-hash";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { DockgeInstanceManager } from "./dockge-instance-manager";
|
import { AgentManager } from "./agent-manager";
|
||||||
|
|
||||||
export interface JWTDecoded {
|
export interface JWTDecoded {
|
||||||
username : string;
|
username : string;
|
||||||
@ -16,7 +16,7 @@ export interface JWTDecoded {
|
|||||||
export interface DockgeSocket extends Socket {
|
export interface DockgeSocket extends Socket {
|
||||||
userID: number;
|
userID: number;
|
||||||
consoleTerminal? : Terminal;
|
consoleTerminal? : Terminal;
|
||||||
instanceManager : DockgeInstanceManager;
|
instanceManager : AgentManager;
|
||||||
endpoint : string;
|
endpoint : string;
|
||||||
emitAgent : (eventName : string, ...args : unknown[]) => void;
|
emitAgent : (eventName : string, ...args : unknown[]) => void;
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,6 @@ function disconnectAllSocketClients(username : string, password : string) : Prom
|
|||||||
|
|
||||||
// Disconnect all socket connections
|
// Disconnect all socket connections
|
||||||
const socket = io(url, {
|
const socket = io(url, {
|
||||||
transports: [ "websocket" ],
|
|
||||||
reconnection: false,
|
reconnection: false,
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
});
|
});
|
||||||
|
@ -3,13 +3,12 @@
|
|||||||
<Uptime :stack="stack" :fixed-width="true" class="me-2" />
|
<Uptime :stack="stack" :fixed-width="true" class="me-2" />
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<span>{{ stackName }}</span>
|
<span>{{ stackName }}</span>
|
||||||
<div class="endpoint">{{ endpointDisplay }}</div>
|
<div v-if="Object.keys($root.agentList).length > 1" class="endpoint">{{ endpointDisplay }}</div>
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Uptime from "./Uptime.vue";
|
import Uptime from "./Uptime.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -101,5 +101,9 @@
|
|||||||
"extra": "Extra",
|
"extra": "Extra",
|
||||||
"newUpdate": "New Update",
|
"newUpdate": "New Update",
|
||||||
"dockgeAgent": "Dockge Agent | Dockge Agents",
|
"dockgeAgent": "Dockge Agent | Dockge Agents",
|
||||||
"currentEndpoint": "Current"
|
"currentEndpoint": "Current",
|
||||||
|
"dockgeURL": "Dockge URL (e.g. http://127.0.0.1:5001)",
|
||||||
|
"agentOnline": "Online",
|
||||||
|
"agentOffline": "Offline",
|
||||||
|
"agentConnecting": "Connecting"
|
||||||
}
|
}
|
||||||
|
@ -29,17 +29,35 @@ export default defineComponent({
|
|||||||
loggedIn: false,
|
loggedIn: false,
|
||||||
allowLoginDialog: false,
|
allowLoginDialog: false,
|
||||||
username: null,
|
username: null,
|
||||||
instanceList: {} as Record<string, any>,
|
|
||||||
stackList: {},
|
|
||||||
composeTemplate: "",
|
composeTemplate: "",
|
||||||
|
|
||||||
|
stackList: {},
|
||||||
|
|
||||||
|
// All stack list from all agents
|
||||||
|
allAgentStackList: {} as Record<string, any>,
|
||||||
|
|
||||||
|
// online / offline / connecting
|
||||||
|
agentStatusList: {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
// Agent List
|
||||||
|
agentList: {
|
||||||
|
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
||||||
completeStackList() {
|
completeStackList() {
|
||||||
let list : Record<string, any> = this.stackList;
|
let list : Record<string, any> = {};
|
||||||
for (let endpoint in this.instanceList) {
|
|
||||||
let instance = this.instanceList[endpoint];
|
for (let stackName in this.stackList) {
|
||||||
|
list[stackName + "_"] = this.stackList[stackName];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let endpoint in this.allAgentStackList) {
|
||||||
|
let instance = this.allAgentStackList[endpoint];
|
||||||
for (let stackName in instance.stackList) {
|
for (let stackName in instance.stackList) {
|
||||||
list[stackName + "_" + endpoint] = instance.stackList[stackName];
|
list[stackName + "_" + endpoint] = instance.stackList[stackName];
|
||||||
}
|
}
|
||||||
@ -79,6 +97,15 @@ export default defineComponent({
|
|||||||
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
||||||
|
"socketIO.connected"() {
|
||||||
|
if (this.socketIO.connected) {
|
||||||
|
this.agentStatusList[""] = "online";
|
||||||
|
} else {
|
||||||
|
this.agentStatusList[""] = "offline";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
remember() {
|
remember() {
|
||||||
localStorage.remember = (this.remember) ? "1" : "0";
|
localStorage.remember = (this.remember) ? "1" : "0";
|
||||||
},
|
},
|
||||||
@ -122,9 +149,7 @@ export default defineComponent({
|
|||||||
this.socketIO.connecting = true;
|
this.socketIO.connecting = true;
|
||||||
}, 1500);
|
}, 1500);
|
||||||
|
|
||||||
socket = io(url, {
|
socket = io(url);
|
||||||
transports: [ "websocket", "polling" ]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handling events from agents
|
// Handling events from agents
|
||||||
let agentSocket = new AgentSocket();
|
let agentSocket = new AgentSocket();
|
||||||
@ -198,9 +223,6 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
agentSocket.on("terminalWrite", (terminalName, data) => {
|
agentSocket.on("terminalWrite", (terminalName, data) => {
|
||||||
|
|
||||||
console.log(terminalName, data);
|
|
||||||
|
|
||||||
const terminal = terminalMap.get(terminalName);
|
const terminal = terminalMap.get(terminalName);
|
||||||
if (!terminal) {
|
if (!terminal) {
|
||||||
//console.error("Terminal not found: " + terminalName);
|
//console.error("Terminal not found: " + terminalName);
|
||||||
@ -210,18 +232,16 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
agentSocket.on("stackList", (res) => {
|
agentSocket.on("stackList", (res) => {
|
||||||
console.log(res);
|
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
if (!res.endpoint) {
|
if (!res.endpoint) {
|
||||||
this.stackList = res.stackList;
|
this.stackList = res.stackList;
|
||||||
} else {
|
} else {
|
||||||
if (!this.instanceList[res.endpoint]) {
|
if (!this.allAgentStackList[res.endpoint]) {
|
||||||
this.instanceList[res.endpoint] = {
|
this.allAgentStackList[res.endpoint] = {
|
||||||
stackList: {},
|
stackList: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.instanceList[res.endpoint].stackList = res.stackList;
|
this.allAgentStackList[res.endpoint].stackList = res.stackList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -237,6 +257,17 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("agentStatus", (res) => {
|
||||||
|
this.agentStatusList[res.endpoint] = res.status;
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("agentList", (res) => {
|
||||||
|
console.log(res);
|
||||||
|
if (res.ok) {
|
||||||
|
this.agentList = res.agentList;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
socket.on("refresh", () => {
|
socket.on("refresh", () => {
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
|
@ -345,7 +345,7 @@ export default {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
globalStack() {
|
globalStack() {
|
||||||
return this.$root.stackList[this.stack.name];
|
return this.$root.completeStackList[this.stack.name + "_" + this.endpoint];
|
||||||
},
|
},
|
||||||
|
|
||||||
status() {
|
status() {
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="row first-row">
|
<div class="row first-row">
|
||||||
<div class="col-md-6">
|
<!-- Left -->
|
||||||
|
<div class="col-md-7">
|
||||||
<div class="shadow-box big-padding text-center mb-4">
|
<div class="shadow-box big-padding text-center mb-4">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@ -23,19 +24,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="shadow-box big-padding">
|
|
||||||
<h3 class="mb-3">{{ $tc("dockgeAgent", 2) }} </h3>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
Current
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button class="btn btn-normal">Add Agent</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 class="mb-3">{{ $t("Docker Run") }}</h2>
|
<h2 class="mb-3">{{ $t("Docker Run") }}</h2>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@ -44,6 +32,40 @@
|
|||||||
|
|
||||||
<button class="btn-normal btn mb-4" @click="convertDockerRun">{{ $t("Convert to Compose") }}</button>
|
<button class="btn-normal btn mb-4" @click="convertDockerRun">{{ $t("Convert to Compose") }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Right -->
|
||||||
|
<div class="col-md-5">
|
||||||
|
<div class="shadow-box big-padding">
|
||||||
|
<h4 class="mb-3">{{ $tc("dockgeAgent", 2) }} <span class="badge bg-warning" style="font-size: 12px;">beta</span></h4>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
Current
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button v-if="!showAgentForm" class="btn btn-normal" @click="showAgentForm = !showAgentForm">Add Agent</button>
|
||||||
|
|
||||||
|
<!-- Add Agent Form -->
|
||||||
|
<form v-if="showAgentForm" @submit.prevent="addAgent">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="url" class="form-label">{{ $t("dockgeURL") }}</label>
|
||||||
|
<input id="url" v-model="agent.url" type="text" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="username" class="form-label">{{ $t("Username") }}</label>
|
||||||
|
<input id="username" v-model="agent.username" type="text" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">{{ $t("Password") }}</label>
|
||||||
|
<input id="password" v-model="agent.password" type="password" class="form-control" required autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-normal">Add Agent</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
<router-view ref="child" />
|
<router-view ref="child" />
|
||||||
</template>
|
</template>
|
||||||
@ -73,6 +95,12 @@ export default {
|
|||||||
importantHeartBeatListLength: 0,
|
importantHeartBeatListLength: 0,
|
||||||
displayedRecords: [],
|
displayedRecords: [],
|
||||||
dockerRunCommand: "",
|
dockerRunCommand: "",
|
||||||
|
showAgentForm: false,
|
||||||
|
agent: {
|
||||||
|
url: "http://",
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -113,6 +141,12 @@ export default {
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
addAgent() {
|
||||||
|
alert(123);
|
||||||
|
|
||||||
|
this.showAgentForm = false;
|
||||||
|
},
|
||||||
|
|
||||||
getStatusNum(statusName) {
|
getStatusNum(statusName) {
|
||||||
let num = 0;
|
let num = 0;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user