mirror of
https://github.com/YuzuZensai/Minikura.git
synced 2026-09-13 18:59:25 +00:00
♻️ refactor: remove unused code
This commit is contained in:
@@ -2,11 +2,8 @@ import type { UpdateSuspensionInput, UpdateUserInput, User } from "@minikura/db"
|
||||
|
||||
export interface IUserService {
|
||||
getUserById(id: string): Promise<User>;
|
||||
getUserByEmail(email: string): Promise<User | null>;
|
||||
getAllUsers(): Promise<User[]>;
|
||||
updateUser(id: string, input: UpdateUserInput): Promise<User>;
|
||||
updateSuspension(id: string, input: UpdateSuspensionInput): Promise<User>;
|
||||
suspendUser(id: string, suspendedUntil?: Date | null): Promise<User>;
|
||||
unsuspendUser(id: string): Promise<User>;
|
||||
deleteUser(requestingUserId: string, targetUserId: string): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { BusinessRuleError, NotFoundError } from "../../domain/errors/base.error
|
||||
import {
|
||||
UserSuspendedEvent,
|
||||
UserUnsuspendedEvent,
|
||||
} from "../../domain/events/server-lifecycle.events";
|
||||
} from "../../domain/events/user-lifecycle.events";
|
||||
import type { UserRepository } from "../../domain/repositories/user.repository";
|
||||
import { eventBus } from "../../infrastructure/event-bus";
|
||||
import type { IUserService } from "../interfaces/user.service.interface";
|
||||
@@ -19,10 +19,6 @@ export class UserService implements IUserService {
|
||||
return user;
|
||||
}
|
||||
|
||||
async getUserByEmail(email: string): Promise<User | null> {
|
||||
return this.userRepo.findByEmail(email);
|
||||
}
|
||||
|
||||
async getAllUsers(): Promise<User[]> {
|
||||
return this.userRepo.findAll();
|
||||
}
|
||||
@@ -42,20 +38,6 @@ export class UserService implements IUserService {
|
||||
return user;
|
||||
}
|
||||
|
||||
async suspendUser(id: string, suspendedUntil?: Date | null): Promise<User> {
|
||||
return this.updateSuspension(id, {
|
||||
isSuspended: true,
|
||||
suspendedUntil: suspendedUntil ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
async unsuspendUser(id: string): Promise<User> {
|
||||
return this.updateSuspension(id, {
|
||||
isSuspended: false,
|
||||
suspendedUntil: null,
|
||||
});
|
||||
}
|
||||
|
||||
async deleteUser(requestingUserId: string, targetUserId: string): Promise<void> {
|
||||
if (requestingUserId === targetUserId) {
|
||||
throw new BusinessRuleError("Cannot delete yourself");
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
export const API_KEY_PREFIXES = {
|
||||
SERVER: "minikura_server_api_key_",
|
||||
REVERSE_PROXY: "minikura_reverse_proxy_server_api_key_",
|
||||
} as const;
|
||||
|
||||
export const DEFAULT_PORTS = {
|
||||
MINECRAFT: 25565,
|
||||
} as const;
|
||||
|
||||
export const DEFAULT_MEMORY = {
|
||||
SERVER: 2048,
|
||||
REVERSE_PROXY: 512,
|
||||
} as const;
|
||||
|
||||
export const DEFAULT_MEMORY_REQUEST = {
|
||||
SERVER: 1024,
|
||||
REVERSE_PROXY: 512,
|
||||
} as const;
|
||||
|
||||
export const DEFAULT_CPU = {
|
||||
SERVER: {
|
||||
REQUEST: "500m",
|
||||
LIMIT: "2",
|
||||
},
|
||||
REVERSE_PROXY: {
|
||||
REQUEST: "250m",
|
||||
LIMIT: "500m",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const VALIDATION = {
|
||||
ID_PATTERN: /^[a-zA-Z0-9-_]+$/,
|
||||
ID_ERROR_MESSAGE: "ID must be alphanumeric with - or _",
|
||||
PORT_MIN: 1,
|
||||
PORT_MAX: 65535,
|
||||
} as const;
|
||||
@@ -26,18 +26,3 @@ export class ServerDeletedEvent extends DomainEvent {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
export class UserSuspendedEvent extends DomainEvent {
|
||||
constructor(
|
||||
public readonly userId: string,
|
||||
public readonly suspendedUntil: Date | null
|
||||
) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
export class UserUnsuspendedEvent extends DomainEvent {
|
||||
constructor(public readonly userId: string) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { DomainEvent } from "./domain-event";
|
||||
|
||||
export class UserSuspendedEvent extends DomainEvent {
|
||||
constructor(
|
||||
public readonly userId: string,
|
||||
public readonly suspendedUntil: Date | null
|
||||
) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
export class UserUnsuspendedEvent extends DomainEvent {
|
||||
constructor(public readonly userId: string) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,8 @@ import type { UpdateSuspensionInput, UpdateUserInput, User } from "@minikura/db"
|
||||
|
||||
export interface UserRepository {
|
||||
findById(id: string): Promise<User | null>;
|
||||
findByEmail(email: string): Promise<User | null>;
|
||||
findAll(): Promise<User[]>;
|
||||
update(id: string, input: UpdateUserInput): Promise<User>;
|
||||
updateSuspension(id: string, input: UpdateSuspensionInput): Promise<User>;
|
||||
delete(id: string): Promise<void>;
|
||||
count(): Promise<number>;
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
export class ApiKey {
|
||||
private static readonly SERVER_PREFIX = "minikura_srv_";
|
||||
private static readonly REVERSE_PROXY_PREFIX = "minikura_proxy_";
|
||||
private static readonly TOKEN_BYTES = 32;
|
||||
|
||||
private constructor(private readonly value: string) {}
|
||||
|
||||
static generate(type: "server" | "reverse-proxy"): ApiKey {
|
||||
const prefix = type === "server" ? ApiKey.SERVER_PREFIX : ApiKey.REVERSE_PROXY_PREFIX;
|
||||
const token = Buffer.from(crypto.randomUUID())
|
||||
.toString("base64")
|
||||
.replace(/[^a-zA-Z0-9]/g, "")
|
||||
.substring(0, ApiKey.TOKEN_BYTES);
|
||||
return new ApiKey(`${prefix}${token}`);
|
||||
}
|
||||
|
||||
static validate(value: string): boolean {
|
||||
const patterns = [
|
||||
new RegExp(`^${ApiKey.SERVER_PREFIX}[a-zA-Z0-9]{32}$`),
|
||||
new RegExp(`^${ApiKey.REVERSE_PROXY_PREFIX}[a-zA-Z0-9]{32}$`),
|
||||
];
|
||||
return patterns.some((pattern) => pattern.test(value));
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
getType(): "server" | "reverse-proxy" {
|
||||
if (this.value.startsWith(ApiKey.SERVER_PREFIX)) return "server";
|
||||
return "reverse-proxy";
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
export class K8sConnectionInfo {
|
||||
constructor(
|
||||
public readonly host: string,
|
||||
public readonly port: number,
|
||||
public readonly namespace: string
|
||||
) {}
|
||||
|
||||
toUrl(): string {
|
||||
return `${this.host}:${this.port}`;
|
||||
}
|
||||
|
||||
toConnectionString(): string {
|
||||
return `Host: ${this.host}, Port: ${this.port}, Namespace: ${this.namespace}`;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
export class ServerConfig {
|
||||
constructor(
|
||||
public readonly memory: number,
|
||||
public readonly memoryRequest: number,
|
||||
public readonly cpuRequest: string,
|
||||
public readonly cpuLimit: string,
|
||||
public readonly jvmOpts: string | null
|
||||
) {}
|
||||
|
||||
static fromDefaults(): ServerConfig {
|
||||
return new ServerConfig(2048, 1024, "250m", "500m", null);
|
||||
}
|
||||
|
||||
static fromInput(input: {
|
||||
memory?: number;
|
||||
memoryRequest?: number;
|
||||
cpuRequest?: string;
|
||||
cpuLimit?: string;
|
||||
jvmOpts?: string;
|
||||
}): ServerConfig {
|
||||
return new ServerConfig(
|
||||
input.memory ?? 2048,
|
||||
input.memoryRequest ?? 1024,
|
||||
input.cpuRequest ?? "250m",
|
||||
input.cpuLimit ?? "500m",
|
||||
input.jvmOpts ?? null
|
||||
);
|
||||
}
|
||||
|
||||
getJvmArgs(): string {
|
||||
const args: string[] = [`-Xmx${this.memory}M`];
|
||||
|
||||
if (this.jvmOpts) {
|
||||
args.push(this.jvmOpts);
|
||||
}
|
||||
|
||||
return args.join(" ");
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ type EventHandler<T extends DomainEvent = DomainEvent> = (event: T) => void | Pr
|
||||
|
||||
export class EventBus {
|
||||
private handlers = new Map<string, Set<EventHandler>>();
|
||||
private eventHistory: DomainEvent[] = [];
|
||||
|
||||
subscribe<T extends DomainEvent>(
|
||||
eventClass: { new (...args: any[]): T },
|
||||
@@ -22,7 +21,6 @@ export class EventBus {
|
||||
}
|
||||
|
||||
async publish<T extends DomainEvent>(event: T): Promise<void> {
|
||||
this.eventHistory.push(event);
|
||||
const eventName = event.constructor.name;
|
||||
const handlers = this.handlers.get(eventName) || [];
|
||||
for (const handler of handlers) {
|
||||
@@ -33,14 +31,6 @@ export class EventBus {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getHistory(): DomainEvent[] {
|
||||
return [...this.eventHistory];
|
||||
}
|
||||
|
||||
clearHistory(): void {
|
||||
this.eventHistory = [];
|
||||
}
|
||||
}
|
||||
|
||||
export const eventBus = new EventBus();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
UserSuspendedEvent,
|
||||
UserUnsuspendedEvent,
|
||||
} from "../../domain/events/server-lifecycle.events";
|
||||
} from "../../domain/events/user-lifecycle.events";
|
||||
import { eventBus } from "../event-bus";
|
||||
import { logger } from "../logger";
|
||||
|
||||
|
||||
@@ -8,12 +8,6 @@ export class PrismaUserRepository implements UserRepository {
|
||||
});
|
||||
}
|
||||
|
||||
async findByEmail(email: string): Promise<User | null> {
|
||||
return await prisma.user.findUnique({
|
||||
where: { email },
|
||||
});
|
||||
}
|
||||
|
||||
async findAll(): Promise<User[]> {
|
||||
return await prisma.user.findMany({
|
||||
orderBy: { createdAt: "desc" },
|
||||
@@ -39,8 +33,4 @@ export class PrismaUserRepository implements UserRepository {
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
|
||||
async count(): Promise<number> {
|
||||
return await prisma.user.count();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +1,41 @@
|
||||
import type { User } from "@minikura/db";
|
||||
import type { Elysia } from "elysia";
|
||||
import { ForbiddenError, UnauthorizedError } from "../domain/errors/base.error";
|
||||
import { bearerToken, findApiKeyOwner } from "./api-key";
|
||||
|
||||
function authenticatedUser(ctx: { user?: User | null; isSuspended?: boolean }) {
|
||||
const { user, isSuspended } = ctx;
|
||||
if (!user) {
|
||||
throw new UnauthorizedError();
|
||||
}
|
||||
if (isSuspended) {
|
||||
throw new ForbiddenError("Account is suspended");
|
||||
}
|
||||
return { user };
|
||||
}
|
||||
|
||||
export const requireAuth = (app: Elysia) => {
|
||||
return app.derive((ctx: any) => {
|
||||
const { user, isSuspended } = ctx as {
|
||||
user: User | null;
|
||||
isSuspended: boolean;
|
||||
};
|
||||
if (!user) {
|
||||
throw new UnauthorizedError();
|
||||
}
|
||||
if (isSuspended) {
|
||||
throw new ForbiddenError("Account is suspended");
|
||||
}
|
||||
return { user };
|
||||
});
|
||||
};
|
||||
|
||||
export const requireAdmin = (app: Elysia) => {
|
||||
return app.derive((ctx: any) => {
|
||||
const { user, isSuspended } = ctx as {
|
||||
user: User | null;
|
||||
isSuspended: boolean;
|
||||
};
|
||||
if (!user) {
|
||||
throw new UnauthorizedError();
|
||||
}
|
||||
if (isSuspended) {
|
||||
throw new ForbiddenError("Account is suspended");
|
||||
}
|
||||
if (user.role !== "admin") {
|
||||
throw new ForbiddenError("Admin access required");
|
||||
}
|
||||
return { user };
|
||||
});
|
||||
return app.derive((ctx: any) => authenticatedUser(ctx));
|
||||
};
|
||||
|
||||
export const requireRole = (role: string) => (app: Elysia) => {
|
||||
return app.derive((ctx: any) => {
|
||||
const { user, isSuspended } = ctx as {
|
||||
user: User | null;
|
||||
isSuspended: boolean;
|
||||
};
|
||||
if (!user) {
|
||||
throw new UnauthorizedError();
|
||||
}
|
||||
if (isSuspended) {
|
||||
throw new ForbiddenError("Account is suspended");
|
||||
}
|
||||
const { user } = authenticatedUser(ctx);
|
||||
if (user.role !== role) {
|
||||
throw new ForbiddenError(`${role} access required`);
|
||||
}
|
||||
return { user };
|
||||
});
|
||||
};
|
||||
|
||||
export const requireAdmin = requireRole("admin");
|
||||
|
||||
export const requirePluginApiKey = (app: Elysia) => {
|
||||
return app.derive(async ({ request }) => {
|
||||
const owner = await findApiKeyOwner(bearerToken(request.headers.get("authorization")));
|
||||
if (!owner) {
|
||||
throw new UnauthorizedError();
|
||||
}
|
||||
return { pluginAuth: owner };
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import type { z } from "zod";
|
||||
|
||||
type ErrorHandler = (code: number, value: unknown) => never;
|
||||
|
||||
export function validateBody<T extends z.ZodType>(
|
||||
schema: T,
|
||||
body: unknown,
|
||||
error: ErrorHandler
|
||||
): z.infer<T> {
|
||||
const result = schema.safeParse(body);
|
||||
|
||||
if (!result.success) {
|
||||
const firstError = result.error.issues[0];
|
||||
const message = `${firstError.path.join(".")}: ${firstError.message}`;
|
||||
throw error(400, { message });
|
||||
}
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
export function zodValidate<T extends z.ZodType>(schema: T) {
|
||||
return (context: { body: unknown; error: ErrorHandler }) => {
|
||||
return validateBody(schema, context.body, context.error);
|
||||
};
|
||||
}
|
||||
@@ -2,10 +2,8 @@ import { labelKeys } from "@minikura/api";
|
||||
import { Elysia } from "elysia";
|
||||
import { k8sService } from "../application/di-container";
|
||||
import { requireAuth } from "../middleware/auth-guards";
|
||||
import { authPlugin } from "../middleware/auth-plugin";
|
||||
|
||||
export const k8sRoutes = new Elysia({ prefix: "/k8s" })
|
||||
.use(authPlugin)
|
||||
.use(requireAuth)
|
||||
.get("/status", async () => {
|
||||
return k8sService.getConnectionInfo();
|
||||
|
||||
@@ -54,49 +54,7 @@ export const createServerSchema = z.object({
|
||||
level_type: z.string().optional(),
|
||||
});
|
||||
|
||||
export const updateServerSchema = z.object({
|
||||
description: z.string().nullable().optional(),
|
||||
listen_port: z.number().int().min(1).max(65535).optional(),
|
||||
service_type: z.nativeEnum(ServiceType).optional(),
|
||||
node_port: z
|
||||
.union([
|
||||
z
|
||||
.number()
|
||||
.int()
|
||||
.min(30000, "Node port must be at least 30000")
|
||||
.max(32767, "Node port must be at most 32767"),
|
||||
z.null(),
|
||||
])
|
||||
.optional(),
|
||||
env_variables: z
|
||||
.array(
|
||||
z.object({
|
||||
key: z.string().min(1),
|
||||
value: z.string(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
memory: z.number().int().min(256).optional(),
|
||||
memory_request: z.number().int().min(256).optional(),
|
||||
cpu_request: z.string().optional(),
|
||||
cpu_limit: z.string().optional(),
|
||||
|
||||
jar_type: z.nativeEnum(MinecraftServerJarType).optional(),
|
||||
minecraft_version: z.string().optional(),
|
||||
|
||||
jvm_opts: z.string().optional(),
|
||||
use_aikar_flags: z.boolean().optional(),
|
||||
use_meowice_flags: z.boolean().optional(),
|
||||
|
||||
difficulty: z.nativeEnum(ServerDifficulty).optional(),
|
||||
game_mode: z.nativeEnum(GameMode).optional(),
|
||||
max_players: z.number().int().min(1).max(1000).optional(),
|
||||
pvp: z.boolean().optional(),
|
||||
online_mode: z.boolean().optional(),
|
||||
motd: z.string().optional(),
|
||||
level_seed: z.string().optional(),
|
||||
level_type: z.string().optional(),
|
||||
});
|
||||
export const updateServerSchema = createServerSchema.omit({ id: true, type: true }).partial();
|
||||
|
||||
export const createReverseProxySchema = z.object({
|
||||
id: z
|
||||
@@ -123,18 +81,9 @@ export const createReverseProxySchema = z.object({
|
||||
cpu_limit: z.string().optional(),
|
||||
});
|
||||
|
||||
export const updateReverseProxySchema = z.object({
|
||||
description: z.string().nullable().optional(),
|
||||
external_address: z.string().optional(),
|
||||
external_port: z.number().int().min(1).max(65535).optional(),
|
||||
listen_port: z.number().int().min(1).max(65535).optional(),
|
||||
type: z.nativeEnum(ReverseProxyServerType).optional(),
|
||||
service_type: z.nativeEnum(ServiceType).optional(),
|
||||
node_port: z.union([z.number().int().min(30000).max(32767), z.null()]).optional(),
|
||||
memory: z.number().int().min(256).optional(),
|
||||
cpu_request: z.string().optional(),
|
||||
cpu_limit: z.string().optional(),
|
||||
});
|
||||
export const updateReverseProxySchema = createReverseProxySchema
|
||||
.omit({ id: true, env_variables: true })
|
||||
.partial();
|
||||
|
||||
export const envVariableSchema = z.object({
|
||||
key: z.string().min(1, "Key is required"),
|
||||
|
||||
@@ -10,10 +10,5 @@ export const updateSuspensionSchema = z.object({
|
||||
suspendedUntil: z.string().nullable().optional(),
|
||||
});
|
||||
|
||||
export const suspendUserSchema = z.object({
|
||||
suspendedUntil: z.string().nullable().optional(),
|
||||
});
|
||||
|
||||
export type UpdateUserInput = z.infer<typeof updateUserSchema>;
|
||||
export type UpdateSuspensionInput = z.infer<typeof updateSuspensionSchema>;
|
||||
export type SuspendUserInput = z.infer<typeof suspendUserSchema>;
|
||||
|
||||
@@ -54,7 +54,7 @@ export class K8sService implements IK8sService {
|
||||
|
||||
private initializeOperations(): void {
|
||||
this.podOps = new PodOperations(this.coreApi, this.namespace);
|
||||
this.clusterOps = new ClusterOperations(this.coreApi, this.customObjectsApi, this.namespace);
|
||||
this.clusterOps = new ClusterOperations(this.customObjectsApi, this.namespace);
|
||||
this.customResourceOps = new CustomResourceOperations(this.customObjectsApi, this.namespace);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,20 +3,12 @@ import { BaseK8sOperations } from "./base.operations";
|
||||
|
||||
export class ClusterOperations extends BaseK8sOperations {
|
||||
constructor(
|
||||
private coreApi: k8s.CoreV1Api,
|
||||
private customObjectsApi: k8s.CustomObjectsApi,
|
||||
namespace: string
|
||||
) {
|
||||
super(namespace);
|
||||
}
|
||||
|
||||
async listNodes() {
|
||||
return this.executeOperation(
|
||||
() => this.coreApi.listNode().then((r) => r.items),
|
||||
"Failed to fetch nodes"
|
||||
);
|
||||
}
|
||||
|
||||
async getNodeMetrics() {
|
||||
return this.executeOperation(
|
||||
() =>
|
||||
@@ -28,12 +20,4 @@ export class ClusterOperations extends BaseK8sOperations {
|
||||
"Failed to fetch node metrics"
|
||||
);
|
||||
}
|
||||
|
||||
async listConfigMaps(namespace?: string) {
|
||||
const ns = namespace || this.namespace;
|
||||
return this.executeOperation(
|
||||
() => this.coreApi.listNamespacedConfigMap({ namespace: ns }).then((r) => r.items),
|
||||
"Failed to fetch configmaps"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
export { BaseK8sOperations } from "./base.operations";
|
||||
export { ClusterOperations } from "./cluster.operations";
|
||||
export { CustomResourceOperations } from "./custom-resource.operations";
|
||||
export { NetworkOperations } from "./network.operations";
|
||||
export { PodOperations } from "./pod.operations";
|
||||
export { WorkloadOperations } from "./workload.operations";
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
import type * as k8s from "@kubernetes/client-node";
|
||||
import { BaseK8sOperations } from "./base.operations";
|
||||
|
||||
export class NetworkOperations extends BaseK8sOperations {
|
||||
constructor(
|
||||
private coreApi: k8s.CoreV1Api,
|
||||
private networkingApi: k8s.NetworkingV1Api,
|
||||
namespace: string
|
||||
) {
|
||||
super(namespace);
|
||||
}
|
||||
|
||||
async listServices() {
|
||||
return this.executeOperation(
|
||||
() => this.coreApi.listNamespacedService({ namespace: this.namespace }).then((r) => r.items),
|
||||
"Failed to fetch services"
|
||||
);
|
||||
}
|
||||
|
||||
async listIngresses() {
|
||||
return this.executeOperation(
|
||||
() =>
|
||||
this.networkingApi
|
||||
.listNamespacedIngress({ namespace: this.namespace })
|
||||
.then((r) => r.items),
|
||||
"Failed to fetch ingresses"
|
||||
);
|
||||
}
|
||||
|
||||
async getServiceInfo(serviceName: string) {
|
||||
return this.executeOperation(
|
||||
() => this.coreApi.readNamespacedService({ name: serviceName, namespace: this.namespace }),
|
||||
`Failed to fetch service info for ${serviceName}`
|
||||
);
|
||||
}
|
||||
|
||||
async getServerConnectionInfo(serviceName: string) {
|
||||
return this.executeOperation(async () => {
|
||||
const service = await this.coreApi.readNamespacedService({
|
||||
name: serviceName,
|
||||
namespace: this.namespace,
|
||||
});
|
||||
|
||||
const serviceType = service.spec?.type || "ClusterIP";
|
||||
const ports = service.spec?.ports || [];
|
||||
|
||||
let host: string;
|
||||
let externalHost: string | undefined;
|
||||
|
||||
switch (serviceType) {
|
||||
case "LoadBalancer": {
|
||||
const ingress = service.status?.loadBalancer?.ingress?.[0];
|
||||
host =
|
||||
ingress?.hostname ||
|
||||
ingress?.ip ||
|
||||
`${serviceName}.${this.namespace}.svc.cluster.local`;
|
||||
externalHost = ingress?.hostname || ingress?.ip;
|
||||
break;
|
||||
}
|
||||
|
||||
case "NodePort":
|
||||
host = `${serviceName}.${this.namespace}.svc.cluster.local`;
|
||||
externalHost = "<node-ip>";
|
||||
break;
|
||||
|
||||
default:
|
||||
host = `${serviceName}.${this.namespace}.svc.cluster.local`;
|
||||
externalHost = undefined;
|
||||
}
|
||||
|
||||
const portMappings = ports.map((port) => ({
|
||||
name: port.name,
|
||||
port: port.port,
|
||||
targetPort: port.targetPort,
|
||||
nodePort: port.nodePort,
|
||||
protocol: port.protocol || "TCP",
|
||||
}));
|
||||
|
||||
return {
|
||||
serviceName,
|
||||
namespace: this.namespace,
|
||||
serviceType,
|
||||
internalHost: host,
|
||||
externalHost,
|
||||
ports: portMappings,
|
||||
};
|
||||
}, `Failed to fetch connection info for service ${serviceName}`);
|
||||
}
|
||||
}
|
||||
@@ -9,30 +9,6 @@ export class PodOperations extends BaseK8sOperations {
|
||||
super(namespace);
|
||||
}
|
||||
|
||||
async listPods() {
|
||||
return this.executeOperation(
|
||||
() => this.coreApi.listNamespacedPod({ namespace: this.namespace }).then((r) => r.items),
|
||||
"Failed to fetch pods"
|
||||
);
|
||||
}
|
||||
|
||||
async listPodsByLabel(labelSelector: string) {
|
||||
return this.executeOperation(
|
||||
() =>
|
||||
this.coreApi
|
||||
.listNamespacedPod({ namespace: this.namespace, labelSelector })
|
||||
.then((r) => r.items),
|
||||
"Failed to fetch pods by label"
|
||||
);
|
||||
}
|
||||
|
||||
async getPodInfo(podName: string) {
|
||||
return this.executeOperation(
|
||||
() => this.coreApi.readNamespacedPod({ name: podName, namespace: this.namespace }),
|
||||
`Failed to fetch pod info for ${podName}`
|
||||
);
|
||||
}
|
||||
|
||||
async getPodLogs(
|
||||
podName: string,
|
||||
options?: {
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import type * as k8s from "@kubernetes/client-node";
|
||||
import { BaseK8sOperations } from "./base.operations";
|
||||
|
||||
export class WorkloadOperations extends BaseK8sOperations {
|
||||
constructor(
|
||||
private appsApi: k8s.AppsV1Api,
|
||||
namespace: string
|
||||
) {
|
||||
super(namespace);
|
||||
}
|
||||
|
||||
async listDeployments() {
|
||||
return this.executeOperation(
|
||||
() =>
|
||||
this.appsApi.listNamespacedDeployment({ namespace: this.namespace }).then((r) => r.items),
|
||||
"Failed to fetch deployments"
|
||||
);
|
||||
}
|
||||
|
||||
async listStatefulSets() {
|
||||
return this.executeOperation(
|
||||
() =>
|
||||
this.appsApi.listNamespacedStatefulSet({ namespace: this.namespace }).then((r) => r.items),
|
||||
"Failed to fetch statefulsets"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
import * as k8s from "@kubernetes/client-node";
|
||||
import { API_GROUP } from "@minikura/api";
|
||||
import { prisma, type ReverseProxyWithEnvVars, type ServerWithEnvVars } from "@minikura/db";
|
||||
import { buildKubeConfig } from "@minikura/shared/kube-auth";
|
||||
import { logger } from "../infrastructure/logger";
|
||||
|
||||
const API_GROUP = "minikura.kirameki.cafe";
|
||||
const API_VERSION = "v1alpha1";
|
||||
const FIELD_MANAGER = "minikura-backend";
|
||||
const SYNC_INTERVAL_MS = 30_000;
|
||||
|
||||
Reference in New Issue
Block a user