models

package
v0.0.178 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2025 License: MIT Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const BuiltinLuaScriptsVersion = "v1"

BuiltinLuaScriptsVersion 统一管理所有内置脚本的版本号

Variables

View Source
var BuiltinAIPrompts = []AIPrompt{
	{
		Name:        "K8s事件分析",
		Description: "分析Kubernetes事件信息,提供问题诊断和解决建议",
		PromptType:  constants.AIPromptTypeEvent,
		Content: `请你作为k8s专家,对下面的Event做出分析:
				note:   ${Note},
				source: ${Source},
				reason: ${Reason},
				type:   ${Type},
				kind:   ${RegardingKind},
		\n注意:
		\n- 不要使用工具tools
`,
		IsBuiltin: true,
		IsEnabled: true,
	},
	{
		Name:        "K8s资源描述分析",
		Description: "分析Kubernetes资源的describe信息,识别问题并提供解决方案",
		PromptType:  constants.AIPromptTypeDescribe,
		Content: `我正在查看关于k8s ${Group} ${Kind} 资源的Describe (kubectl describe )信息。
		请你作为kubernetes k8s 技术专家,对这个describe的文本进行分析。
		\n 请给出分析结论,如果有问题,请指出问题,并给出可能得解决方案。
		\n注意:
		\n0、使用中文进行回答。
		\n1、你我之间只进行这一轮交互,后面不要再问问题了。
		\n2、请你在给出答案前反思下回答是否逻辑正确,如有问题请先修正,再返回。回答要直接,不要加入上下衔接、开篇语气词、结尾语气词等啰嗦的信息。
		\n3、请不要向我提问,也不要向我确认信息,请不要让我检查markdown格式,不要让我确认markdown格式是否正确。
		\n4、不要使用工具tools。
		\n\nDescribe信息如下:${DescribeInfo}`,
		IsBuiltin: true,
		IsEnabled: true,
	},
	{
		Name:        "K8s资源使用示例",
		Description: "提供Kubernetes资源的详细使用指南和YAML示例",
		PromptType:  constants.AIPromptTypeExample,
		Content: `我正在浏览k8s资源管理页面,资源定义Kind=${Kind},Group=${Group},version=${Version}。
		\n请你作为kubernetes k8s 技术专家,给我一份关于这个k8s资源的使用指南。
		\n要求包括资源说明、使用场景(举例说明)、最佳实践、典型示例(配合前面的场景举例,编写yaml文件,每一行yaml都增加简体中文注释)、关键字段及其含义、常见问题、官方文档链接、引用文档链接等你认为对我有帮助的信息。
		\n最后给出一份关于这个资源的yaml样例。
		\n要求先假设一个简单场景、一个复杂场景。1、分别概要介绍这两个场景,2、为这两个场景书写yaml文件,每一行yaml都增加简体中文注释。
		\n注意:
		\n0、使用中文进行回答。
		\n1、你我之间只进行这一轮交互,后面不要再问问题了。
		\n2、请你在给出答案前反思下回答是否逻辑正确,如有问题请先修正,再返回。回答要直接,不要加入上下衔接、开篇语气词、结尾语气词等啰嗦的信息。
		\n3、请不要向我提问,也不要向我确认信息,请不要让我检查markdown格式,不要让我确认markdown格式是否正确。
		\n4、不要使用工具tools。`,
		IsBuiltin: true,
		IsEnabled: true,
	},
	{
		Name:        "K8s字段使用示例",
		Description: "详细解释Kubernetes资源中特定字段的用法和示例",
		PromptType:  constants.AIPromptTypeFieldExample,
		Content: `我正在浏览k8s资源管理页面,资源定义Kind=${Kind},Group=${Group},version=${Version}。
		\n请你作为kubernetes k8s 技术专家,给出一份关于  ${Field}  这个具体字段的使用场景。请在回答中使用 "该字段" 代替这个具体的字段。
		请详细解释该字段的含义、用法、并给出一个假设的使用场景,为这个场景书写yaml文件,每一行yaml都增加简体中文注释。
		\n注意:
		\n0、使用中文进行回答。
		\n1、你我之间只进行这一轮交互,后面不要再问问题了。
		\n2、请你在给出答案前反思下回答是否逻辑正确,如有问题请先修正,再返回。回答要直接,不要加入上下衔接、开篇语气词、结尾语气词等啰嗦的信息。
		\n3、请不要向我提问,也不要向我确认信息,请不要让我检查markdown格式,不要让我确认markdown格式是否正确。
		\n4、不要使用工具tools。`,
		IsBuiltin: true,
		IsEnabled: true,
	},
	{
		Name:        "K8s资源使用指南",
		Description: "提供Kubernetes资源的完整使用指南",
		PromptType:  constants.AIPromptTypeResource,
		Content: `我正在浏览k8s资源管理页面,资源定义Kind=${Kind},Group=${Group},version=${Version}。
		\n请你作为kubernetes k8s 技术专家,给我一份关于这个k8s资源的使用指南。
		要求包括资源说明、使用场景(举例说明)、最佳实践、典型示例(配合前面的场景举例,编写yaml文件,每一行yaml都增加简体中文注释)、关键字段及其含义、常见问题、官方文档链接、引用文档链接等你认为对我有帮助的信息。
		\n注意:
		\n0、使用中文进行回答。
		\n1、你我之间只进行这一轮交互,后面不要再问问题了。
		\n2、请你在给出答案前反思下回答是否逻辑正确,如有问题请先修正,再返回。回答要直接,不要加入上下衔接、开篇语气词、结尾语气词等啰嗦的信息。
		\n3、请不要向我提问,也不要向我确认信息,请不要让我检查markdown格式,不要让我确认markdown格式是否正确。
		\n4、不要使用工具tools。`,
		IsBuiltin: true,
		IsEnabled: true,
	},
	{
		Name:        "K8s错误信息分析",
		Description: "分析Kubernetes错误信息并提供解决方案",
		PromptType:  constants.AIPromptTypeK8sGPTResource,
		Content: `简化以下由三个破折号分隔的Kubernetes错误信息,
		错误内容:--- ${Data} ---。
		资源名称:--- ${Name} ---。
		资源类型:--- ${Kind} ---。
		相关字段k8s官方文档解释:--- ${Field} ---。
		请以分步形式提供最可能的解决方案,字符数不超过280。
		输出格式:
		错误信息: {此处解释错误}
		解决方案: {此处分步说明解决方案}
		\n注意:
		\n0、使用中文进行回答。
		\n1、你我之间只进行这一轮交互,后面不要再问问题了。
		\n2、请你在给出答案前反思下回答是否逻辑正确,如有问题请先修正,再返回。回答要直接,不要加入上下衔接、开篇语气词、结尾语气词等啰嗦的信息。
		\n3、请不要向我提问,也不要向我确认信息,请不要让我检查markdown格式,不要让我确认markdown格式是否正确。
		\n4、不要使用工具tools。`,
		IsBuiltin: true,
		IsEnabled: true,
	},

	{
		Name:        "K8s问题解答",
		Description: "回答Kubernetes相关的任意问题",
		PromptType:  constants.AIPromptTypeAnyQuestion,
		Content: `我正在浏览k8s资源管理页面,资源定义Kind=${Kind},Group=${Group},version=${Version}。
		\n请你作为kubernetes k8s 技术专家,请你详细解释下我的疑问: ${Question} 。
		\n要求包括关键名词解释、作用、典型示例(以场景举例,编写yaml文件,每一行yaml都增加简体中文注释)、关键字段及其含义、常见问题、官方文档链接、引用文档链接等你认为对我有帮助的信息。
		\n注意:
		\n0、使用中文进行回答。
		\n1、你我之间只进行这一轮交互,后面不要再问问题了。
		\n2、请你在给出答案前反思下回答是否逻辑正确,如有问题请先修正,再返回。回答要直接,不要加入上下衔接、开篇语气词、结尾语气词等啰嗦的信息。
		\n3、请不要向我提问,也不要向我确认信息,请不要让我检查markdown格式,不要让我确认markdown格式是否正确。
		\n4、不要使用工具tools。`,
		IsBuiltin: true,
		IsEnabled: true,
	},
	{
		Name:        "Cron表达式分析",
		Description: "分析和解释Cron表达式的含义",
		PromptType:  constants.AIPromptTypeCron,
		Content: `我正在查看k8s cronjob 中的schedule 表达式:${Cron}。
		\n请你作为k8s技术专家,对 ${Cron} 这个表达式进行分析,给出详细的解释。
		\n注意:
		\n0、使用中文进行回答。
		\n1、你我之间只进行这一轮交互,后面不要再问问题了。
		\n2、请你在给出答案前反思下回答是否逻辑正确,如有问题请先修正,再返回。回答要直接,不要加入上下衔接、开篇语气词、结尾语气词等啰嗦的信息。
		\n3、请不要向我提问,也不要向我确认信息,请不要让我检查markdown格式,不要让我确认markdown格式是否正确。
		\n4、不要使用工具tools。`,
		IsBuiltin: true,
		IsEnabled: true,
	},
	{
		Name:        "日志分析",
		Description: "分析应用程序或系统日志",
		PromptType:  constants.AIPromptTypeLog,
		Content: `请你作为k8s、Devops、软件工程专家,对下面的Log做出分析:
		\n${Data}
		\n请提供:
		\n1. 日志级别和类型分析
		\n2. 关键信息提取
		\n3. 问题识别和诊断
		\n4. 解决建议和后续行动
		\n注意:
		\n- 使用中文进行回答
		\n- 回答要直接,不要加入啰嗦的信息
		\n- 不要向我提问或确认信息
		\n- 不要使用工具tools`,
		IsBuiltin: true,
		IsEnabled: true,
	},
	{
		Name:        "任意选择",
		Description: "对任意选择的文字内容进行详细解释",
		PromptType:  constants.AIPromptTypeAnySelection,
		Content: `请你作为kubernetes k8s 技术专家,请你详细解释下面的文字: ${Question} 。
		\n注意:
		\n- 使用中文进行回答
		\n- 你我之间只进行这一轮交互,后面不要再问问题了
		\n- 请你在给出答案前反思下回答是否逻辑正确,如有问题请先修正,再返回
		\n- 回答要直接,不要加入上下衔接、开篇语气词、结尾语气词等啰嗦的信息
		\n- 请不要向我提问,也不要向我确认信息,请不要让我检查markdown格式
		\n- 不要使用工具tools`,
		IsBuiltin: true,
		IsEnabled: true,
	},
}

BuiltinAIPrompts 内置AI提示词

View Source
var BuiltinLuaScripts = []InspectionLuaScript{
	{
		Name:           "Service Selector 检查",
		Description:    "检查每个 Service 的 selector 是否有对应 Pod",
		Group:          "",
		Version:        "v1",
		Kind:           "Service",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Service_001",
		TimeoutSeconds: 30,
		Script: `
		    -- 获取Selector 定义文档
			local doc, err = kubectl:GVK("", "v1", "Service"):Cache(10):Doc("spec.selector")
			if err then
				print( "获取 Service Doc 失败".. tostring(err))
				return
			end
			-- 检查每个 Service 的 selector 是否有对应 Pod,Pod 查询限定在 Service 所在的 namespace
			local svcs, err = kubectl:GVK("", "v1", "Service"):AllNamespace(""):List()
			if not err and svcs then
				for _, svc in ipairs(svcs) do
					if svc.spec and svc.spec.selector then
						local selector = svc.spec.selector
						local labelSelector = ""
						for k, v in pairs(selector) do
							if labelSelector ~= "" then
								labelSelector = labelSelector .. ","
							end
							labelSelector = labelSelector .. k .. "=" .. v
						end
						-- 这里使用 Namespace(svc.metadata.namespace) 保证只查找与 Service 相同命名空间下的 Pod
						local pods, err = kubectl:GVK("", "v1", "Pod"):Namespace(svc.metadata.namespace):Cache(10):WithLabelSelector(labelSelector):List()
						local count = 0
						if not err and pods then
							for _, _ in pairs(pods) do count = count + 1 end
						end
						if count == 0 then
							check_event("失败", "Service " .. svc.metadata.name .. " selector " .. labelSelector .. " 应该至少一个pod, 但是现在没有。" .. "spec.selector定义" .. doc, {name=svc.metadata.name, selector=labelSelector, namespace=svc.metadata.namespace})
						end
					end
				end
			else
				print("Service 列表获取失败: " .. tostring(err))
			end
			print("Service Selector 检查完成")
		`,
	},

	{
		Name:           "ConfigMap 未被使用检测",
		Description:    "检测所有未被 Pod 使用的 ConfigMap",
		Group:          "",
		Version:        "v1",
		Kind:           "ConfigMap",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_ConfigMap_002",
		TimeoutSeconds: 90,
		Script: `
			local configmaps, err = kubectl:GVK("", "v1", "ConfigMap"):AllNamespace(""):List()
			if err then
				print("获取 ConfigMap 失败".. tostring(err))
				return
			end
			local pods, err = kubectl:GVK("", "v1", "Pod"):Cache(10):AllNamespace(""):List()
			if err then
				print("获取 Pod 失败".. tostring(err))
				return
			end
			local usedConfigMaps = {}
			for _, pod in ipairs(pods) do
				if pod.spec and pod.spec.volumes then
					for _, volume in ipairs(pod.spec.volumes) do
						if volume.configMap and volume.configMap.name then
							local key = pod.metadata.namespace .. "/" .. volume.configMap.name
							usedConfigMaps[key] = true
						end
					end
				end
				if pod.spec and pod.spec.containers then
					for _, container in ipairs(pod.spec.containers) do
						if container.env then
							for _, env in ipairs(container.env) do
								if env.valueFrom and env.valueFrom.configMapKeyRef and env.valueFrom.configMapKeyRef.name then
									local key = pod.metadata.namespace .. "/" .. env.valueFrom.configMapKeyRef.name
									usedConfigMaps[key] = true
								end
							end
						end
						if container.envFrom then
							for _, envFrom in ipairs(container.envFrom) do
								if envFrom.configMapRef and envFrom.configMapRef.name then
									local key = pod.metadata.namespace .. "/" .. envFrom.configMapRef.name
									usedConfigMaps[key] = true
								end
							end
						end
					end
				end
			end
			for _, cm in ipairs(configmaps) do
				local cmKey = cm.metadata.namespace .. "/" .. cm.metadata.name
				local cmName = cm.metadata.name
				local cmNamespace = cm.metadata.namespace
				if not usedConfigMaps[cmKey] then
					check_event("失败", "[未使用] ConfigMap " .. cmNamespace .. "/" .. cmName .. " 没有被任何 Pod 使用", {namespace=cmNamespace, name=cmName})
				end
			end
			print("ConfigMap 未被使用检测完成")
		`,
	},
	{
		Name:           "ConfigMap 空数据检测",
		Description:    "检测所有 data 和 binaryData 字段都为空的 ConfigMap",
		Group:          "",
		Version:        "v1",
		Kind:           "ConfigMap",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_ConfigMap_003",
		TimeoutSeconds: 30,
		Script: `
			local configmaps, err = kubectl:GVK("", "v1", "ConfigMap"):AllNamespace(""):List()
			if err then
				print("获取 ConfigMap 失败".. tostring(err))
				return
			end
			for _, cm in ipairs(configmaps) do
				local cmName = cm.metadata.name
				local cmNamespace = cm.metadata.namespace
				local isEmpty = true
				if cm.data then
					for k, v in pairs(cm.data) do
						isEmpty = false
						break
					end
				end
				if isEmpty and cm.binaryData then
					for k, v in pairs(cm.binaryData) do
						isEmpty = false
						break
					end
				end
				if isEmpty then
					check_event("失败", "[空数据] ConfigMap " .. cmNamespace .. "/" .. cmName .. " 的 data 和 binaryData 字段都为空", {namespace=cmNamespace, name=cmName})
				end
			end
			print("ConfigMap 空数据检测完成")
		`,
	},
	{
		Name:           "ConfigMap 超大检测",
		Description:    "检测所有超过 1MB 的 ConfigMap",
		Group:          "",
		Version:        "v1",
		Kind:           "ConfigMap",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_ConfigMap_004",
		TimeoutSeconds: 45,
		Script: `
			local configmaps, err = kubectl:GVK("", "v1", "ConfigMap"):AllNamespace(""):List()
			if err then
				print( "获取 ConfigMap 失败".. tostring(err))
				return
			end
			for _, cm in ipairs(configmaps) do
				local cmName = cm.metadata.name
				local cmNamespace = cm.metadata.namespace
				local totalSize = 0
				if cm.data then
					for k, v in pairs(cm.data) do
						if type(v) == "string" then
							totalSize = totalSize + string.len(v)
						end
					end
				end
				if cm.binaryData then
					for k, v in pairs(cm.binaryData) do
						if type(v) == "string" then
							totalSize = totalSize + string.len(v)
						end
					end
				end
				local maxSize = 1024 * 1024
				if totalSize > maxSize then
					local sizeMB = string.format("%.2f", totalSize / (1024 * 1024))
					check_event("失败", "[超大] ConfigMap " .. cmNamespace .. "/" .. cmName .. " 大小为 " .. sizeMB .. "MB,超过 1MB 限制", {namespace=cmNamespace, name=cmName, size=sizeMB})
				end
			end
			print("ConfigMap 超大检测完成")
		`,
	},

	{
		Name:           "Deployment 配置检查",
		Description:    "分析 Deployment 配置问题",
		Group:          "apps",
		Version:        "v1",
		Kind:           "Deployment",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Deployment_005",
		TimeoutSeconds: 60,
		Script: `
			local doc, err = kubectl:GVK("apps", "v1", "Deployment"):Cache(10):Doc("spec.replicas")
			if err then
				print( "获取 Deployment Doc 失败".. tostring(err))
				return
			end
			print("Deployment Doc 获取成功: " .. doc)
			local deployments, err = kubectl:GVK("apps", "v1", "Deployment"):Cache(10):AllNamespace(""):List()
			if err then
				print( "获取 Deployment 失败".. tostring(err))
				return
			end
			local problemCount = 0
			for _, deployment in ipairs(deployments) do
				local deploymentName = deployment.metadata.name
				local deploymentNamespace = deployment.metadata.namespace
				local specReplicas = 0
				local statusReplicas = 0
				local readyReplicas = 0
				if deployment.spec and deployment.spec.replicas ~= nil then
					specReplicas = tonumber(deployment.spec.replicas) or 0
				end
				if deployment.status then
					if deployment.status.replicas ~= nil then
						statusReplicas = tonumber(deployment.status.replicas) or 0
					end
					if deployment.status.readyReplicas ~= nil then
						readyReplicas = tonumber(deployment.status.readyReplicas) or 0
					end
				end
				if specReplicas ~= readyReplicas then
					problemCount = problemCount + 1
					if statusReplicas > specReplicas then
						check_event("失败", "[副本数不匹配] Deployment " .. deploymentNamespace .. "/" .. deploymentName ..
							" 期望副本数: " .. specReplicas ..
							", 状态副本数: " .. statusReplicas ..
							", 就绪副本数: " .. readyReplicas ..
							" (状态字段尚未更新,缩容进行中)", {namespace=deploymentNamespace, name=deploymentName, specReplicas=specReplicas, statusReplicas=statusReplicas, readyReplicas=readyReplicas})
					else
						check_event("失败", "[副本数不足] Deployment " .. deploymentNamespace .. "/" .. deploymentName ..
							" 期望副本数: " .. specReplicas ..
							", 就绪副本数: " .. readyReplicas ..
							" (可能存在 Pod 启动失败或资源不足)", {namespace=deploymentNamespace, name=deploymentName, specReplicas=specReplicas, readyReplicas=readyReplicas})
					end
					if readyReplicas == 0 and specReplicas > 0 then
						check_event("失败", "没有就绪的副本,可能存在严重问题", {namespace=deploymentNamespace, name=deploymentName})
					elseif readyReplicas < specReplicas then
						local missingReplicas = specReplicas - readyReplicas
						check_event("失败", "缺少 " .. missingReplicas .. " 个副本,建议检查 Pod 状态和资源限制", {namespace=deploymentNamespace, name=deploymentName, missingReplicas=missingReplicas})
					end
				end
				if deployment.status and deployment.status.conditions then
					for _, condition in ipairs(deployment.status.conditions) do
						if condition.type == "Progressing" and condition.status == "False" then
							check_event("失败", "进度停滞: " .. (condition.reason or "未知原因") ..
								" - " .. (condition.message or "无详细信息"), {namespace=deploymentNamespace, name=deploymentName, reason=condition.reason, message=condition.message})
						elseif condition.type == "Available" and condition.status == "False" then
							check_event("失败", "不可用状态: " .. (condition.reason or "未知原因") ..
								" - " .. (condition.message or "无详细信息"), {namespace=deploymentNamespace, name=deploymentName, reason=condition.reason, message=condition.message})
						end
					end
				end
			end
		`,
	},
	{
		Name:           "CronJob 合规性检查",
		Description:    "检查 CronJob 是否被挂起、调度表达式是否合法、startingDeadlineSeconds 是否为负数",
		Group:          "",
		Version:        "v1",
		Kind:           "CronJob",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_CronJob_006",
		TimeoutSeconds: 45,
		Script: `
			-- 内置 Cron 表达式基本校验(Kubernetes 使用标准 5 字段)
			local function split_fields(expr)
				local fields = {}
				for token in string.gmatch(expr or "", "%S+") do table.insert(fields, token) end
				return fields
			end
			local function validate_part(part, min, max, allow_names)
				if part == "*" then return true end
				local step = string.match(part, "^%*/(%d+)$")
				if step then return tonumber(step) and tonumber(step) >= 1 end
				local a,b = string.match(part, "^(%d+)%-(%d+)$")
				if a and b then a=tonumber(a); b=tonumber(b); return a and b and a>=min and b<=max and a<=b end
				local num = tonumber(part)
				if num and num>=min and num<=max then return true end
				if allow_names and string.match(part, "^[A-Za-z]+$") then return true end
				return false
			end
			local function validate_field(field, min, max, allow_names)
				for part in string.gmatch(field, "[^,]+") do
					if not validate_part(part, min, max, allow_names) then return false end
				end
				return true
			end
			local function is_valid_cron(expr)
				if not expr or expr == "" then return false, "表达式为空" end
				if string.match(expr, "^@%w+$") then return true end -- 支持 @yearly 等描述符
				local f = split_fields(expr)
				if #f ~= 5 then return false, "字段数不是5" end
				if not validate_field(f[1], 0, 59, false) then return false, "分钟字段非法" end
				if not validate_field(f[2], 0, 23, false) then return false, "小时字段非法" end
				if not validate_field(f[3], 1, 31, false) then return false, "日字段非法" end
				if not validate_field(f[4], 1, 12, true) then return false, "月字段非法" end
				if not validate_field(f[5], 0, 7, true) then return false, "周字段非法" end
				return true
			end
			local cronjobs, err = kubectl:GVK("batch", "v1", "CronJob"):AllNamespace(""):List()
			if err then
				print("获取 CronJob 失败: " .. tostring(err))
				return
			end
			local doc_suspend, _ = kubectl:GVK("batch", "v1", "CronJob"):Doc("spec.suspend")
			local doc_schedule, _ = kubectl:GVK("batch", "v1", "CronJob"):Doc("spec.schedule")
			local doc_deadline, _ = kubectl:GVK("batch", "v1", "CronJob"):Doc("spec.startingDeadlineSeconds")
			for _, cj in ipairs(cronjobs) do
				local ns = cj.metadata and cj.metadata.namespace or "default"
				local name = cj.metadata and cj.metadata.name or ""
				-- 检查挂起
				if cj.spec and cj.spec.suspend == true then
					check_event("失败", "CronJob " .. name .. " 已被挂起", {namespace=ns, name=name, doc=doc_suspend})
				end
				-- 检查调度表达式合法性(5 字段)
				if cj.spec and cj.spec.schedule ~= nil then
					local ok, reason = is_valid_cron(cj.spec.schedule)
					if not ok then
						check_event("失败", "CronJob " .. name .. " 的调度表达式非法: " .. tostring(reason), {namespace=ns, name=name, value=cj.spec.schedule, doc=doc_schedule})
					end
				end
				-- 检查 startingDeadlineSeconds
				if cj.spec and cj.spec.startingDeadlineSeconds ~= nil then
					if tonumber(cj.spec.startingDeadlineSeconds) < 0 then
						check_event("失败", "CronJob " .. name .. " 的 startingDeadlineSeconds 为负数", {namespace=ns, name=name, value=cj.spec.startingDeadlineSeconds, doc=doc_deadline})
					end
				end
			end
			print("CronJob 合规性检查完成")
		`,
	},
	{
		Name:           "Gateway 合规性检查",
		Description:    "检查 Gateway 关联的 GatewayClass 是否存在,以及 Gateway 状态是否被接受",
		Group:          "gateway.networking.k8s.io",
		Version:        "v1",
		Kind:           "Gateway",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Gateway_007",
		TimeoutSeconds: 45,
		Script: `
			local gateways, err = kubectl:GVK("gateway.networking.k8s.io", "v1", "Gateway"):AllNamespace(""):List()
			if err then
				print("获取 Gateway 失败: " .. tostring(err))
				return
			end
			for _, gtw in ipairs(gateways) do
				local ns = gtw.metadata and gtw.metadata.namespace or "default"
				local name = gtw.metadata and gtw.metadata.name or ""
				local className = gtw.spec and gtw.spec.gatewayClassName or nil
				local classExists = false
				if className then
					local gtwclass, err = kubectl:GVK("gateway.networking.k8s.io", "v1", "GatewayClass"):Name(className):Get()
					if not err and gtwclass then
						classExists = true
					end
				end
				if not classExists then
					check_event("失败", "Gateway 使用的 GatewayClass " .. tostring(className) .. " 不存在", {namespace=ns, name=name, gatewayClassName=className})
				end
				-- 检查第一个 Condition 状态
				if gtw.status and gtw.status.conditions and #gtw.status.conditions > 0 then
					local cond = gtw.status.conditions[1]
					if cond.status ~= "True" then
						check_event("失败", "Gateway '" .. ns .. "/" .. name .. "' 未被接受, Message: '" .. (cond.message or "") .. "'", {namespace=ns, name=name, message=cond.message})
					end
				end
			end
			print("Gateway 合规性检查完成")
		`,
	},
	{
		Name:           "GatewayClass 合规性检查",
		Description:    "检查 GatewayClass 的第一个 Condition 状态是否为 True,否则报告未被接受及 message。",
		Group:          "gateway.networking.k8s.io",
		Version:        "v1",
		Kind:           "GatewayClass",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_GatewayClass_008",
		TimeoutSeconds: 45,
		Script: `
			local gatewayclasses, err = kubectl:GVK("gateway.networking.k8s.io", "v1", "GatewayClass"):AllNamespace(""):List()
			if err then
				print("获取 GatewayClass 失败: " .. tostring(err))
				return
			end
			for _, gc in ipairs(gatewayclasses) do
				local name = gc.metadata and gc.metadata.name or ""
				if gc.status and gc.status.conditions and #gc.status.conditions > 0 then
					local cond = gc.status.conditions[1]
					if cond.status ~= "True" then
						check_event("失败", "GatewayClass '" .. name .. "' 未被接受, Message: '" .. (cond.message or "") .. "'", {name=name, message=cond.message})
					end
				end
			end
			print("GatewayClass 合规性检查完成")
		`,
	},
	{
		Name:           "HPA Condition 检查",
		Description:    "检查 HorizontalPodAutoscaler 的 Condition 状态,ScalingLimited 为 True 或其他 Condition 为 False 时报警。",
		Group:          "autoscaling",
		Version:        "v2",
		Kind:           "HorizontalPodAutoscaler",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_HPA_Condition_009",
		TimeoutSeconds: 45,
		Script: `
			local hpas, err = kubectl:GVK("autoscaling", "v2", "HorizontalPodAutoscaler"):AllNamespace(""):List()
			if err then print("获取 HPA 失败: " .. tostring(err)) return end
			for _, hpa in ipairs(hpas) do
				if hpa.status and hpa.status.conditions then
					for _, cond in ipairs(hpa.status.conditions) do
						if cond.type == "ScalingLimited" and cond.status == "True" then
							check_event("失败", cond.message or "ScalingLimited condition True", {namespace=hpa.metadata.namespace, name=hpa.metadata.name, type=cond.type})
						elseif cond.status == "False" then
							check_event("失败", cond.message or (cond.type .. " condition False"), {namespace=hpa.metadata.namespace, name=hpa.metadata.name, type=cond.type})
						end
					end
				end
			end
			print("HPA Condition 检查完成")
		`,
	},
	{
		Name:           "HPA ScaleTargetRef 存在性检查",
		Description:    "检查 HorizontalPodAutoscaler 的 ScaleTargetRef 指向的对象是否存在。",
		Group:          "autoscaling",
		Version:        "v2",
		Kind:           "HorizontalPodAutoscaler",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_HPA_ScaleTargetRef_010",
		TimeoutSeconds: 60,
		Script: `
			local hpas, err = kubectl:GVK("autoscaling", "v2", "HorizontalPodAutoscaler"):AllNamespace(""):List()
			if err then print("获取 HPA 失败: " .. tostring(err)) return end
			for _, hpa in ipairs(hpas) do
				if hpa.spec and hpa.spec.scaleTargetRef then
					local ref = hpa.spec.scaleTargetRef
					local exists = false
					if ref.kind == "Deployment" then
						exists = kubectl:GVK("apps", "v1", "Deployment"):Namespace(hpa.metadata.namespace):Name(ref.name):Exists()
					elseif ref.kind == "ReplicaSet" then
						exists = kubectl:GVK("apps", "v1", "ReplicaSet"):Namespace(hpa.metadata.namespace):Name(ref.name):Exists()
					elseif ref.kind == "StatefulSet" then
						exists = kubectl:GVK("apps", "v1", "StatefulSet"):Namespace(hpa.metadata.namespace):Name(ref.name):Exists()
					elseif ref.kind == "ReplicationController" then
						exists = kubectl:GVK("", "v1", "ReplicationController"):Namespace(hpa.metadata.namespace):Name(ref.name):Exists()
					else
						check_event("失败", "HorizontalPodAutoscaler 使用了不支持的 ScaleTargetRef Kind: " .. tostring(ref.kind), {namespace=hpa.metadata.namespace, name=hpa.metadata.name, kind=ref.kind})
					end
					if not exists then
						check_event("失败", "HorizontalPodAutoscaler 的 ScaleTargetRef " .. ref.kind .. "/" .. ref.name .. " 不存在", {namespace=hpa.metadata.namespace, name=hpa.metadata.name, kind=ref.kind, refname=ref.name})
					end
				end
			end
			print("HPA ScaleTargetRef 存在性检查完成")
		`,
	},
	{
		Name:           "HPA 资源配置检查",
		Description:    "检查 HPA 关联对象的 Pod 模板中所有容器是否配置了 requests 和 limits。",
		Group:          "autoscaling",
		Version:        "v2",
		Kind:           "HorizontalPodAutoscaler",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_HPA_Resource_011",
		TimeoutSeconds: 75,
		Script: `
			local hpas, err = kubectl:GVK("autoscaling", "v2", "HorizontalPodAutoscaler"):AllNamespace(""):List()
			if err then print("获取 HPA 失败: " .. tostring(err)) return end
			for _, hpa in ipairs(hpas) do
				if hpa.spec and hpa.spec.scaleTargetRef then
					local ref = hpa.spec.scaleTargetRef
					local gvk_map = {
						Deployment = {group="apps", version="v1", kind="Deployment"},
						ReplicaSet = {group="apps", version="v1", kind="ReplicaSet"},
						StatefulSet = {group="apps", version="v1", kind="StatefulSet"},
						ReplicationController = {group="", version="v1", kind="ReplicationController"},
					}
					local gvk = gvk_map[ref.kind]
					if gvk then
						local target, err = kubectl:GVK(gvk.group, gvk.version, gvk.kind):Namespace(hpa.metadata.namespace):Name(ref.name):Get()
						if not err and target and target.spec and target.spec.template and target.spec.template.spec and target.spec.template.spec.containers then
							local containers = target.spec.template.spec.containers
							local all_ok = true
							for _, c in ipairs(containers) do
								if not c.resources or not c.resources.requests or not c.resources.limits then
									all_ok = false
									check_event("失败", ref.kind .. " " .. hpa.metadata.namespace .. "/" .. ref.name .. " 的容器未配置 requests 或 limits", {namespace=hpa.metadata.namespace, name=hpa.metadata.name, kind=ref.kind, refname=ref.name, container=c.name})
								end
							end
						end
					end
				end
			end
			print("HPA 资源配置检查完成")
		`,
	}, {
		Name:           "HTTPRoute Backend Service 存在性与端口检查",
		Description:    "检查 HTTPRoute 所引用的后端 Service 是否存在,以及端口是否匹配 Service 的端口。",
		Group:          "gateway.networking.k8s.io",
		Version:        "v1",
		Kind:           "HTTPRoute",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_HTTPRoute_Backend_012",
		TimeoutSeconds: 60,
		Script: `
			local httproutes, err = kubectl:GVK("gateway.networking.k8s.io", "v1", "HTTPRoute"):AllNamespace(""):List()
			if err then print("获取 HTTPRoute 失败: " .. tostring(err)) return end
			for _, route in ipairs(httproutes) do
				if route.spec and route.spec.rules then
					for _, rule in ipairs(route.spec.rules) do
						if rule.backendRefs then
							for _, backend in ipairs(rule.backendRefs) do
								local svc, err = kubectl:GVK("", "v1", "Service"):Namespace(route.metadata.namespace):Name(backend.name):Get()
								if err or not svc then
									check_event("失败", "HTTPRoute 使用的 Service '" .. route.metadata.namespace .. "/" .. backend.name .. "' 不存在", {namespace=route.metadata.namespace, name=backend.name})
								else
									local portMatch = false
									if svc.spec and svc.spec.ports and backend.port then
										for _, svcPort in ipairs(svc.spec.ports) do
											if svcPort.port == backend.port then portMatch = true end
										end
									end
									if not portMatch then
										check_event("失败", "HTTPRoute 的后端 Service '" .. backend.name .. "' 使用端口 '" .. tostring(backend.port) .. "',但 Service 未配置该端口", {namespace=route.metadata.namespace, name=backend.name, port=backend.port})
									end
								end
							end
						end
					end
				end
			end
			print("HTTPRoute Backend Service 检查完成")
		`,
	}, {
		Name:           "HTTPRoute Backend Service 存在性与端口检查",
		Description:    "检查 HTTPRoute 所引用的后端 Service 是否存在,以及端口是否匹配 Service 的端口。",
		Group:          "gateway.networking.k8s.io",
		Version:        "v1",
		Kind:           "HTTPRoute",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_HTTPRoute_Backend_013",
		TimeoutSeconds: 60,
		Script: `
			local httproutes, err = kubectl:GVK("gateway.networking.k8s.io", "v1", "HTTPRoute"):AllNamespace(""):List()
			if err then print("获取 HTTPRoute 失败: " .. tostring(err)) return end
			for _, route in ipairs(httproutes) do
				if route.spec and route.spec.rules then
					for _, rule in ipairs(route.spec.rules) do
						if rule.backendRefs then
							for _, backend in ipairs(rule.backendRefs) do
								local svc, err = kubectl:GVK("", "v1", "Service"):Namespace(route.metadata.namespace):Name(backend.name):Get()
								if err or not svc then
									check_event("失败", "HTTPRoute 使用的 Service '" .. route.metadata.namespace .. "/" .. backend.name .. "' 不存在", {namespace=route.metadata.namespace, name=backend.name})
								else
									local portMatch = false
									if svc.spec and svc.spec.ports and backend.port then
										for _, svcPort in ipairs(svc.spec.ports) do
											if svcPort.port == backend.port then portMatch = true end
										end
									end
									if not portMatch then
										check_event("失败", "HTTPRoute 的后端 Service '" .. backend.name .. "' 使用端口 '" .. tostring(backend.port) .. "',但 Service 未配置该端口", {namespace=route.metadata.namespace, name=backend.name, port=backend.port})
									end
								end
							end
						end
					end
				end
			end
			print("HTTPRoute Backend Service 检查完成")
		`,
	}, {
		Name:           "HTTPRoute Gateway 存在性与命名空间策略检查",
		Description:    "检查 HTTPRoute 所引用的 Gateway 是否存在,以及 Gateway 的 AllowedRoutes 策略是否允许该 HTTPRoute。",
		Group:          "gateway.networking.k8s.io",
		Version:        "v1",
		Kind:           "HTTPRoute",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_HTTPRoute_Gateway_014",
		TimeoutSeconds: 75,
		Script: `
			local httproutes, err = kubectl:GVK("gateway.networking.k8s.io", "v1", "HTTPRoute"):AllNamespace(""):List()
			if err then print("获取 HTTPRoute 失败: " .. tostring(err)) return end
			for _, route in ipairs(httproutes) do
				if route.spec and route.spec.parentRefs then
					for _, gtwref in ipairs(route.spec.parentRefs) do
						local ns = route.metadata.namespace
						if gtwref.namespace then ns = gtwref.namespace end
						local gtw, err = kubectl:GVK("gateway.networking.k8s.io", "v1", "Gateway"):Namespace(ns):Name(gtwref.name):Get()
						if err or not gtw then
							check_event("失败", "HTTPRoute 使用的 Gateway '" .. ns .. "/" .. gtwref.name .. "' 不存在", {namespace=ns, name=gtwref.name})
						else
							if gtw.spec and gtw.spec.listeners then
								for _, listener in ipairs(gtw.spec.listeners) do
									if listener.allowedRoutes and listener.allowedRoutes.namespaces and listener.allowedRoutes.namespaces.from then
										local allow = listener.allowedRoutes.namespaces.from
										if allow == "Same" and route.metadata.namespace ~= gtw.metadata.namespace then
											check_event("失败", "HTTPRoute '" .. route.metadata.namespace .. "/" .. route.metadata.name .. "' 与 Gateway '" .. gtw.metadata.namespace .. "/" .. gtw.metadata.name .. "' 不在同一命名空间,且 Gateway 只允许同命名空间 HTTPRoute", {route_ns=route.metadata.namespace, route_name=route.metadata.name, gtw_ns=gtw.metadata.namespace, gtw_name=gtw.metadata.name})
										elseif allow == "Selector" and listener.allowedRoutes.namespaces.selector and listener.allowedRoutes.namespaces.selector.matchLabels then
											local match = false
											for k, v in pairs(listener.allowedRoutes.namespaces.selector.matchLabels) do
												if route.metadata.labels and route.metadata.labels[k] == v then match = true end
											end
											if not match then
												check_event("失败", "HTTPRoute '" .. route.metadata.namespace .. "/" .. route.metadata.name .. "' 的标签与 Gateway '" .. gtw.metadata.namespace .. "/" .. gtw.metadata.name .. "' 的 Selector 不匹配", {route_ns=route.metadata.namespace, route_name=route.metadata.name, gtw_ns=gtw.metadata.namespace, gtw_name=gtw.metadata.name})
											end
										end
									end
								end
							end
						end
					end
				end
			end
			print("HTTPRoute Gateway 检查完成")
		`,
	},
	{
		Name:           "Ingress 合规性检查",
		Description:    "检查 Ingress 是否指定 IngressClass,引用的 IngressClass/Service/Secret 是否存在。",
		Group:          "networking",
		Version:        "v1",
		Kind:           "Ingress",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Ingress_015",
		TimeoutSeconds: 75,
		Script: `
			local ingresses, err = kubectl:GVK("networking.k8s.io", "v1", "Ingress"):AllNamespace(""):List()
			if err then print("获取 Ingress 失败: " .. tostring(err)) return end
			for _, ing in ipairs(ingresses) do
				local ingressClassName = ing.spec and ing.spec.ingressClassName or nil
				if not ingressClassName and ing.metadata and ing.metadata.annotations then
					ingressClassName = ing.metadata.annotations["kubernetes.io/ingress.class"]
				end
				if not ingressClassName or ingressClassName == "" then
					check_event("失败", "Ingress " .. ing.metadata.namespace .. "/" .. ing.metadata.name .. " 未指定 IngressClass", {namespace=ing.metadata.namespace, name=ing.metadata.name})
				else
					local ic, err = kubectl:GVK("networking.k8s.io", "v1", "IngressClass"):Name(ingressClassName):Get()
					if err or not ic then
						check_event("失败", "Ingress 使用的 IngressClass '" .. ingressClassName .. "' 不存在", {namespace=ing.metadata.namespace, name=ing.metadata.name, ingressClass=ingressClassName})
					end
				end
				if ing.spec and ing.spec.rules then
					for _, rule in ipairs(ing.spec.rules) do
						if rule.http and rule.http.paths then
							for _, path in ipairs(rule.http.paths) do
								if path.backend and path.backend.service and path.backend.service.name then
									local svc, err = kubectl:GVK("", "v1", "Service"):Namespace(ing.metadata.namespace):Name(path.backend.service.name):Get()
									if err or not svc then
										check_event("失败", "Ingress 使用的 Service '" .. ing.metadata.namespace .. "/" .. path.backend.service.name .. "' 不存在", {namespace=ing.metadata.namespace, name=path.backend.service.name})
									end
								end
							end
						end
					end
				end
				if ing.spec and ing.spec.tls then
					for _, tls in ipairs(ing.spec.tls) do
						if tls.secretName then
							local sec, err = kubectl:GVK("", "v1", "Secret"):Namespace(ing.metadata.namespace):Name(tls.secretName):Get()
							if err or not sec then
								check_event("失败", "Ingress 使用的 TLS Secret '" .. ing.metadata.namespace .. "/" .. tls.secretName .. "' 不存在", {namespace=ing.metadata.namespace, name=tls.secretName})
							end
						end
					end
				end
			end
			print("Ingress 合规性检查完成")
		`,
	},
	{
		Name:           "Job 合规性检查",
		Description:    "检查 Job 是否被挂起(suspend)以及是否有失败(status.failed > 0)",
		Group:          "batch",
		Version:        "v1",
		Kind:           "Job",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Job_016",
		TimeoutSeconds: 45,
		Script: `
			local jobs, err = kubectl:GVK("batch", "v1", "Job"):AllNamespace(""):List()
			if err then print("获取 Job 失败: " .. tostring(err)) return end
			for _, job in ipairs(jobs) do
				if job.spec and job.spec.suspend == true then
					check_event("失败", "Job " .. job.metadata.name .. " 已被挂起", {namespace=job.metadata.namespace, name=job.metadata.name})
				end
				if job.status and job.status.failed and job.status.failed > 0 then
					check_event("失败", "Job " .. job.metadata.name .. " 有失败记录 (failed=" .. tostring(job.status.failed) .. ")", {namespace=job.metadata.namespace, name=job.metadata.name, failed=job.status.failed})
				end
			end
			print("Job 合规性检查完成")
		`,
	},
	{
		Name:           "MutatingWebhookConfiguration 合规性检查",
		Description:    "检查 MutatingWebhookConfiguration 的 webhook 指向的 Service 是否存在、是否有活跃 Pod、Pod 状态。",
		Group:          "admissionregistration.k8s.io",
		Version:        "v1",
		Kind:           "MutatingWebhookConfiguration",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_MutatingWebhook_017",
		TimeoutSeconds: 90,
		Script: `
			local mwcs, err = kubectl:GVK("admissionregistration.k8s.io", "v1", "MutatingWebhookConfiguration"):AllNamespace(""):List()
			if err then print("获取 MutatingWebhookConfiguration 失败: " .. tostring(err)) return end
			for _, mwc in ipairs(mwcs) do
				if mwc.webhooks then
					for _, webhook in ipairs(mwc.webhooks) do
						if webhook.clientConfig and webhook.clientConfig.service then
							local svc = webhook.clientConfig.service
							local service, err = kubectl:GVK("", "v1", "Service"):Namespace(svc.namespace):Name(svc.name):Get()
							if err or not service then
								check_event("失败", "MutatingWebhook " .. webhook.name .. " 指向的 Service '" .. svc.namespace .. "/" .. svc.name .. "' 不存在", {namespace=svc.namespace, name=svc.name, webhook=webhook.name})
							else
								if service.spec and service.spec.selector and next(service.spec.selector) ~= nil then
									local selector = ""
									for k, v in pairs(service.spec.selector) do
										if selector ~= "" then selector = selector .. "," end
										selector = selector .. k .. "=" .. v
									end
									local pods, err = kubectl:GVK("", "v1", "Pod"):Namespace(svc.namespace):WithLabelSelector(selector):List()
									if not err and pods and #pods.items == 0 then
										check_event("失败", "MutatingWebhook " .. webhook.name .. " 指向的 Service '" .. svc.namespace .. "/" .. svc.name .. "' 没有活跃 Pod", {namespace=svc.namespace, name=svc.name, webhook=webhook.name})
									end
									if pods and pods.items then
										for _, pod in ipairs(pods.items) do
											if pod.status and pod.status.phase ~= "Running" then
												check_event("失败", "MutatingWebhook " .. webhook.name .. " 指向的 Pod '" .. pod.metadata.name .. "' 状态为 " .. (pod.status.phase or "未知") , {namespace=svc.namespace, name=svc.name, webhook=webhook.name, pod=pod.metadata.name, phase=pod.status.phase})
											end
										end
									end
								end
							end
						end
					end
				end
			end
			print("MutatingWebhookConfiguration 合规性检查完成")
		`,
	},
	{
		Name:           "NetworkPolicy 合规性检查",
		Description:    "检查 NetworkPolicy 是否允许所有 Pod,或未作用于任何 Pod。",
		Group:          "networking",
		Version:        "v1",
		Kind:           "NetworkPolicy",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_NetworkPolicy_018",
		TimeoutSeconds: 60,
		Script: `
			local nps, err = kubectl:GVK("networking.k8s.io", "v1", "NetworkPolicy"):AllNamespace(""):List()
			if err then print("获取 NetworkPolicy 失败: " .. tostring(err)) return end
			for _, np in ipairs(nps) do
				if np.spec and np.spec.podSelector and (not np.spec.podSelector.matchLabels or next(np.spec.podSelector.matchLabels) == nil) then
					check_event("失败", "NetworkPolicy '" .. np.metadata.name .. "' 允许所有 Pod", {namespace=np.metadata.namespace, name=np.metadata.name})
				else
					local selector = ""
					if np.spec and np.spec.podSelector and np.spec.podSelector.matchLabels then
						for k, v in pairs(np.spec.podSelector.matchLabels) do
							if selector ~= "" then selector = selector .. "," end
							selector = selector .. k .. "=" .. v
						end
					end
					if selector ~= "" then
						local pods, err = kubectl:GVK("", "v1", "Pod"):Namespace(np.metadata.namespace):WithLabelSelector(selector):List()
						if not err and pods and #pods.items == 0 then
							check_event("失败", "NetworkPolicy '" .. np.metadata.name .. "' 未作用于任何 Pod", {namespace=np.metadata.namespace, name=np.metadata.name})
						end
					end
				end
			end
			print("NetworkPolicy 合规性检查完成")
		`,
	},
	{
		Name:           "Node 合规性检查",
		Description:    "检查 Node 的 Condition 状态,非 Ready/EtcdIsVoter 且状态异常时报警。",
		Group:          "",
		Version:        "v1",
		Kind:           "Node",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Node_019",
		TimeoutSeconds: 45,
		Script: `
			local nodes, err = kubectl:GVK("", "v1", "Node"):AllNamespace(""):List()
			if err then print("获取 Node 失败: " .. tostring(err)) return end
			for _, node in ipairs(nodes) do
				if node.status and node.status.conditions then
					for _, cond in ipairs(node.status.conditions) do
						if cond.type == "Ready" then
							if cond.status ~= "True" then
								check_event("失败", node.metadata.name .. " Ready 状态异常: " .. (cond.reason or "") .. " - " .. (cond.message or ""), {name=node.metadata.name, type=cond.type, reason=cond.reason, message=cond.message})
							end
						elseif cond.type == "EtcdIsVoter" then
							-- 跳过 k3s 特有的 EtcdIsVoter
						else
							if cond.status ~= "False" then
								check_event("失败", node.metadata.name .. " " .. cond.type .. " 状态异常: " .. (cond.reason or "") .. " - " .. (cond.message or ""), {name=node.metadata.name, type=cond.type, reason=cond.reason, message=cond.message})
							end
						end
					end
				end
			end
			print("Node 合规性检查完成")
		`,
	},
	{
		Name:           "Pod 合规性检查",
		Description:    "检查 Pod 的 Pending、调度失败、CrashLoopBackOff、终止异常、ReadinessProbe 失败等状态。",
		Group:          "",
		Version:        "v1",
		Kind:           "Pod",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Pod_020",
		TimeoutSeconds: 120,
		Script: `
			local pods, err = kubectl:GVK("", "v1", "Pod"):AllNamespace(""):List()
			if err then print("获取 Pod 失败: " .. tostring(err)) return end
			for _, pod in ipairs(pods) do
				if pod.status and pod.status.phase == "Pending" and pod.status.conditions then
					for _, cond in ipairs(pod.status.conditions) do
						if cond.type == "PodScheduled" and cond.reason == "Unschedulable" and cond.message and cond.message ~= "" then
							check_event("失败", cond.message, {namespace=pod.metadata.namespace, name=pod.metadata.name})
						end
					end
				end
				local function check_container_statuses(statuses, phase)
					if not statuses then return end
					for _, cs in ipairs(statuses) do
						if cs.state and cs.state.waiting then
							if cs.state.waiting.reason == "CrashLoopBackOff" and cs.lastState and cs.lastState.terminated then
								check_event("失败", "CrashLoopBackOff: 上次终止原因 " .. (cs.lastState.terminated.reason or "") .. " 容器=" .. cs.name .. " pod=" .. pod.metadata.name, {namespace=pod.metadata.namespace, name=pod.metadata.name, container=cs.name})
							elseif cs.state.waiting.reason and (cs.state.waiting.reason == "ImagePullBackOff" or cs.state.waiting.reason == "ErrImagePull" or cs.state.waiting.reason == "CreateContainerConfigError" or cs.state.waiting.reason == "CreateContainerError" or cs.state.waiting.reason == "RunContainerError" or cs.state.waiting.reason == "InvalidImageName") then
								check_event("失败", cs.state.waiting.message or (cs.state.waiting.reason .. " 容器=" .. cs.name .. " pod=" .. pod.metadata.name), {namespace=pod.metadata.namespace, name=pod.metadata.name, container=cs.name})
							end
						elseif cs.state and cs.state.terminated and cs.state.terminated.exitCode and cs.state.terminated.exitCode ~= 0 then
							check_event("失败", "终止异常: " .. (cs.state.terminated.reason or "Unknown") .. " exitCode=" .. tostring(cs.state.terminated.exitCode) .. " 容器=" .. cs.name .. " pod=" .. pod.metadata.name, {namespace=pod.metadata.namespace, name=pod.metadata.name, container=cs.name, exitCode=cs.state.terminated.exitCode})
						elseif cs.ready == false and phase == "Running" then
							check_event("失败", "容器未就绪: " .. cs.name .. " pod=" .. pod.metadata.name, {namespace=pod.metadata.namespace, name=pod.metadata.name, container=cs.name})
						end
					end
				end
				if pod.status then
					check_container_statuses(pod.status.initContainerStatuses, pod.status.phase)
					check_container_statuses(pod.status.containerStatuses, pod.status.phase)
				end
			end
			print("Pod 合规性检查完成")
		`,
	},
	{
		Name:           "PVC 合规性检查",
		Description:    "检查 PVC Pending 状态下的 ProvisioningFailed 事件。",
		Group:          "",
		Version:        "v1",
		Kind:           "PersistentVolumeClaim",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_PVC_021",
		TimeoutSeconds: 60,
		Script: `
			local pvcs, err = kubectl:GVK("", "v1", "PersistentVolumeClaim"):AllNamespace(""):List()
			if err then print("获取 PVC 失败: " .. tostring(err)) return end
			for _, pvc in ipairs(pvcs) do
				if pvc.status and pvc.status.phase == "Pending" then
					local events, err = kubectl:GVK("", "v1", "Event"):Namespace(pvc.metadata.namespace):WithFieldSelector("involvedObject.name=" .. pvc.metadata.name):List()
					if not err and events and events.items then
						for _, evt in ipairs(events.items) do
							if evt.reason == "ProvisioningFailed" and evt.message and evt.message ~= "" then
								check_event("失败", evt.message, {namespace=pvc.metadata.namespace, name=pvc.metadata.name})
							end
						end
					end
				end
			end
			print("PVC 合规性检查完成")
		`,
	},
	{
		Name:           "ReplicaSet 合规性检查",
		Description:    "检测副本数为0且有 FailedCreate 的 ReplicaFailure。",
		Group:          "apps",
		Version:        "v1",
		Kind:           "ReplicaSet",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_ReplicaSet_022",
		TimeoutSeconds: 45,
		Script: `
			local rss, err = kubectl:GVK("apps", "v1", "ReplicaSet"):AllNamespace(""):List()
			if err then print("获取 ReplicaSet 失败: " .. tostring(err)) return end
			for _, rs in ipairs(rss) do
				if rs.status and rs.status.replicas == 0 and rs.status.conditions then
					for _, cond in ipairs(rs.status.conditions) do
						if cond.type == "ReplicaFailure" and cond.reason == "FailedCreate" then
							check_event("失败", cond.message or "ReplicaSet 副本创建失败", {namespace=rs.metadata.namespace, name=rs.metadata.name})
						end
					end
				end
			end
			print("ReplicaSet 合规性检查完成")
		`,
	},
	{
		Name:           "Security ServiceAccount 默认账户使用检测",
		Description:    "检测 default ServiceAccount 是否被 Pod 使用。",
		Group:          "core",
		Version:        "v1",
		Kind:           "ServiceAccount",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Security_SA_023",
		TimeoutSeconds: 60,
		Script: `
			local sas, err = kubectl:GVK("", "v1", "ServiceAccount"):AllNamespace(""):List()
			if err then print("获取 ServiceAccount 失败: " .. tostring(err)) return end
			for _, sa in ipairs(sas) do
				if sa.metadata and sa.metadata.name == "default" then
					local pods, err = kubectl:GVK("", "v1", "Pod"):Namespace(sa.metadata.namespace):List()
					if not err and pods then
						local defaultSAUsers = {}
						for _, pod in ipairs(pods) do
							if pod.spec and pod.spec.serviceAccountName == "default" then
								table.insert(defaultSAUsers, pod.metadata.name)
							end
						end
						if #defaultSAUsers > 0 then
							check_event("失败", "Default service account 被以下 Pod 使用: " .. table.concat(defaultSAUsers, ", "), {namespace=sa.metadata.namespace, name=sa.metadata.name})
						end
					end
				end
			end
			print("Security ServiceAccount 检查完成")
		`,
	},
	{
		Name:           "Security RoleBinding 通配符检测",
		Description:    "检测 RoleBinding 关联的 Role 是否包含通配符权限。",
		Group:          "rbac.authorization.k8s.io",
		Version:        "v1",
		Kind:           "RoleBinding",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Security_RoleBinding_024",
		TimeoutSeconds: 75,
		Script: `
			local rbs, err = kubectl:GVK("rbac.authorization.k8s.io", "v1", "RoleBinding"):AllNamespace(""):List()
			if err then print("获取 RoleBinding 失败: " .. tostring(err)) return end
			for _, rb in ipairs(rbs) do
				if rb.roleRef and rb.roleRef.kind == "Role" and rb.roleRef.name then
					local role, err = kubectl:GVK("rbac.authorization.k8s.io", "v1", "Role"):Namespace(rb.metadata.namespace):Name(rb.roleRef.name):Get()
					if not err and role and role.rules then
						for _, rule in ipairs(role.rules) do
							local function containsWildcard(arr)
								if not arr then return false end
								for _, v in ipairs(arr) do if v == "*" then return true end end
								return false
							end
							if containsWildcard(rule.verbs) or containsWildcard(rule.resources) then
								check_event("失败", "RoleBinding '" .. rb.metadata.name .. "' 关联的 Role '" .. role.metadata.name .. "' 存在通配符权限", {namespace=rb.metadata.namespace, name=rb.metadata.name, role=role.metadata.name})
							end
						end
					end
				end
			end
			print("Security RoleBinding 检查完成")
		`,
	},
	{
		Name:           "Security Pod 安全上下文检测",
		Description:    "检测 Pod 是否存在特权容器或缺少安全上下文。",
		Group:          "core",
		Version:        "v1",
		Kind:           "Pod",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Security_Pod_025",
		TimeoutSeconds: 90,
		Script: `
			local pods, err = kubectl:GVK("", "v1", "Pod"):AllNamespace(""):List()
			if err then print("获取 Pod 失败: " .. tostring(err)) return end
			for _, pod in ipairs(pods) do
				local hasPrivileged = false
				if pod.spec and pod.spec.containers then
					for _, c in ipairs(pod.spec.containers) do
						if c.securityContext and c.securityContext.privileged == true then
							hasPrivileged = true
							check_event("失败", "容器 " .. c.name .. " 以特权模式运行,存在安全风险", {namespace=pod.metadata.namespace, name=pod.metadata.name, container=c.name})
							break
						end
					end
				end
				if not hasPrivileged and (not pod.spec or not pod.spec.securityContext) then
					check_event("失败", "Pod " .. pod.metadata.name .. " 未定义安全上下文,存在安全风险", {namespace=pod.metadata.namespace, name=pod.metadata.name})
				end
			end
			print("Security Pod 安全上下文检查完成")
		`,
	},
	{
		Name:           "StatefulSet 合规性检查",
		Description:    "检测 StatefulSet 关联的 Service、StorageClass 是否存在及 Pod 状态。",
		Group:          "apps",
		Version:        "v1",
		Kind:           "StatefulSet",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_StatefulSet_026",
		TimeoutSeconds: 120,
		Script: `
			local stss, err = kubectl:GVK("apps", "v1", "StatefulSet"):AllNamespace(""):List()
			if err then print("获取 StatefulSet 失败: " .. tostring(err)) return end
			for _, sts in ipairs(stss) do
				if sts.spec and sts.spec.serviceName then
					local svc, err = kubectl:GVK("", "v1", "Service"):Namespace(sts.metadata.namespace):Name(sts.spec.serviceName):Get()
					if err or not svc then
						check_event("失败", "StatefulSet 使用的 Service '" .. sts.metadata.namespace .. "/" .. sts.spec.serviceName .. "' 不存在", {namespace=sts.metadata.namespace, name=sts.metadata.name, service=sts.spec.serviceName})
					end
				end
				if sts.spec and sts.spec.volumeClaimTemplates then
					for _, vct in ipairs(sts.spec.volumeClaimTemplates) do
						if vct.spec and vct.spec.storageClassName then
							local sc, err = kubectl:GVK("storage.k8s.io", "v1", "StorageClass"):Name(vct.spec.storageClassName):Get()
							if err or not sc then
								check_event("失败", "StatefulSet 使用的 StorageClass '" .. vct.spec.storageClassName .. "' 不存在", {namespace=sts.metadata.namespace, name=sts.metadata.name, storageClass=vct.spec.storageClassName})
							end
						end
					end
				end
				if sts.spec and sts.spec.replicas and sts.status and sts.status.availableReplicas and sts.spec.replicas ~= sts.status.availableReplicas then
					for i = 0, sts.spec.replicas - 1 do
						local podName = sts.metadata.name .. "-" .. tostring(i)
						local pod, err = kubectl:GVK("", "v1", "Pod"):Namespace(sts.metadata.namespace):Name(podName):Get()
						if err or not pod then
							if i == 0 then
								local events, err = kubectl:GVK("", "v1", "Event"):Namespace(sts.metadata.namespace):WithFieldSelector("involvedObject.name=" .. sts.metadata.name):List()
								if not err and events and events.items then
									for _, evt in ipairs(events.items) do
										if evt.type ~= "Normal" and evt.message and evt.message ~= "" then
											check_event("失败", evt.message, {namespace=sts.metadata.namespace, name=sts.metadata.name})
										end
									end
								end
							end
							break
						end
						if pod.status and pod.status.phase ~= "Running" then
							check_event("失败", "StatefulSet 的 Pod '" .. pod.metadata.name .. "' 不在 Running 状态", {namespace=sts.metadata.namespace, name=sts.metadata.name, pod=pod.metadata.name, phase=pod.status.phase})
							break
						end
					end
				end
			end
			print("StatefulSet 合规性检查完成")
		`,
	},
	{
		Name:           "StorageClass 合规性检查",
		Description:    "检测 StorageClass 是否使用了已废弃的 provisioner,及是否存在多个默认 StorageClass。",
		Group:          "storage.k8s.io",
		Version:        "v1",
		Kind:           "StorageClass",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_StorageClass_027",
		TimeoutSeconds: 30,
		Script: `
			local scs, err = kubectl:GVK("storage.k8s.io", "v1", "StorageClass"):AllNamespace(""):List()
			if err then print("获取 StorageClass 失败: " .. tostring(err)) return end
			local defaultCount = 0
			for _, sc in ipairs(scs) do
				if sc.provisioner == "kubernetes.io/no-provisioner" then
					check_event("失败", "StorageClass '" .. sc.metadata.name .. "' 使用了已废弃的 provisioner 'kubernetes.io/no-provisioner'", {name=sc.metadata.name})
				end
				if sc.metadata.annotations and sc.metadata.annotations["storageclass.kubernetes.io/is-default-class"] == "true" then
					defaultCount = defaultCount + 1
				end
			end
			if defaultCount > 1 then
				check_event("失败", "存在多个默认 StorageClass (" .. tostring(defaultCount) .. "),可能导致混淆", {})
			end
			print("StorageClass 合规性检查完成")
		`,
	},
	{
		Name:           "PersistentVolume 合规性检查",
		Description:    "检测 PV 是否为 Released/Failed 状态,及容量小于 1Gi。",
		Group:          "core",
		Version:        "v1",
		Kind:           "PersistentVolume",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_PV_028",
		TimeoutSeconds: 45,
		Script: `
			local pvs, err = kubectl:GVK("", "v1", "PersistentVolume"):AllNamespace(""):List()
			if err then print("获取 PersistentVolume 失败: " .. tostring(err)) return end
			for _, pv in ipairs(pvs) do
				if pv.status and pv.status.phase == "Released" then
					check_event("失败", "PersistentVolume '" .. pv.metadata.name .. "' 处于 Released 状态,应及时清理", {name=pv.metadata.name})
				end
				if pv.status and pv.status.phase == "Failed" then
					check_event("失败", "PersistentVolume '" .. pv.metadata.name .. "' 处于 Failed 状态", {name=pv.metadata.name})
				end
				if pv.spec and pv.spec.capacity and pv.spec.capacity.storage then
					local function parseGi(val)
						local n = tonumber(val:match("%d+"))
						if val:find("Gi") then return n end
						if val:find("Mi") then return n and n/1024 or 0 end
						return 0
					end
					if parseGi(pv.spec.capacity.storage) < 1 then
						check_event("失败", "PersistentVolume '" .. pv.metadata.name .. "' 容量过小 (" .. pv.spec.capacity.storage .. ")", {name=pv.metadata.name, capacity=pv.spec.capacity.storage})
					end
				end
			end
			print("PersistentVolume 合规性检查完成")
		`,
	},
	{
		Name:        "PersistentVolumeClaim 合规性检查",
		Description: "检测 PVC Pending/Lost 状态、容量小于 1Gi、无 StorageClass。",
		Group:       "core",
		Version:     "v1",
		Kind:        "PersistentVolumeClaim",
		ScriptType:  constants.LuaScriptTypeBuiltin,
		ScriptCode:  "Builtin_PVC_029",
		Script: `
			local pvcs, err = kubectl:GVK("", "v1", "PersistentVolumeClaim"):AllNamespace(""):List()
			if err then print("获取 PVC 失败: " .. tostring(err)) return end
			for _, pvc in ipairs(pvcs) do
				if pvc.status and pvc.status.phase == "Pending" then
					check_event("失败", "PersistentVolumeClaim '" .. pvc.metadata.name .. "' 处于 Pending 状态", {namespace=pvc.metadata.namespace, name=pvc.metadata.name})
				elseif pvc.status and pvc.status.phase == "Lost" then
					check_event("失败", "PersistentVolumeClaim '" .. pvc.metadata.name .. "' 处于 Lost 状态", {namespace=pvc.metadata.namespace, name=pvc.metadata.name})
				else
					if pvc.spec and pvc.spec.resources and pvc.spec.resources.requests and pvc.spec.resources.requests.storage then
						local function parseGi(val)
							local n = tonumber(val:match("%d+"))
							if val:find("Gi") then return n end
							if val:find("Mi") then return n and n/1024 or 0 end
							return 0
						end
						if parseGi(pvc.spec.resources.requests.storage) < 1 then
							check_event("失败", "PersistentVolumeClaim '" .. pvc.metadata.name .. "' 容量过小 (" .. pvc.spec.resources.requests.storage .. ")", {namespace=pvc.metadata.namespace, name=pvc.metadata.name, capacity=pvc.spec.resources.requests.storage})
						end
					end
					if (not pvc.spec or not pvc.spec.storageClassName) and (not pvc.spec or not pvc.spec.volumeName or pvc.spec.volumeName == "") then
						check_event("失败", "PersistentVolumeClaim '" .. pvc.metadata.name .. "' 未指定 StorageClass", {namespace=pvc.metadata.namespace, name=pvc.metadata.name})
					end
				end
			end
			print("PersistentVolumeClaim 合规性检查完成")
		`,
	},
	{
		Name:        "ValidatingWebhookConfiguration 合规性检查",
		Description: "检查 ValidatingWebhookConfiguration 的 webhook 指向的 Service 是否存在、是否有活跃 Pod、Pod 状态。",
		Group:       "admissionregistration.k8s.io",
		Version:     "v1",
		Kind:        "ValidatingWebhookConfiguration",
		ScriptType:  constants.LuaScriptTypeBuiltin,
		ScriptCode:  "Builtin_ValidatingWebhook_030",
		Script: `
			local vwcs, err = kubectl:GVK("admissionregistration.k8s.io", "v1", "ValidatingWebhookConfiguration"):AllNamespace(""):List()
			if err then print("获取 ValidatingWebhookConfiguration 失败: " .. tostring(err)) return end
			for _, vwc in ipairs(vwcs) do
				if vwc.webhooks then
					for _, webhook in ipairs(vwc.webhooks) do
						if webhook.clientConfig and webhook.clientConfig.service then
							local svc = webhook.clientConfig.service
							local service, err = kubectl:GVK("", "v1", "Service"):Namespace(svc.namespace):Name(svc.name):Get()
							if err or not service then
								check_event("失败", "ValidatingWebhook " .. webhook.name .. " 指向的 Service '" .. svc.namespace .. "/" .. svc.name .. "' 不存在", {namespace=svc.namespace, name=svc.name, webhook=webhook.name})
							else
								if service.spec and service.spec.selector and next(service.spec.selector) ~= nil then
									local selector = ""
									for k, v in pairs(service.spec.selector) do
										if selector ~= "" then selector = selector .. "," end
										selector = selector .. k .. "=" .. v
									end
									local pods, err = kubectl:GVK("", "v1", "Pod"):Namespace(svc.namespace):WithLabelSelector(selector):List()
									if not err and pods and #pods.items == 0 then
										check_event("失败", "ValidatingWebhook " .. webhook.name .. " 指向的 Service '" .. svc.namespace .. "/" .. svc.name .. "' 没有活跃 Pod", {namespace=svc.namespace, name=svc.name, webhook=webhook.name})
									end
									if pods and pods.items then
										for _, pod in ipairs(pods.items) do
											if pod.status and pod.status.phase ~= "Running" then
												check_event("失败", "ValidatingWebhook " .. webhook.name .. " 指向的 Pod '" .. pod.metadata.name .. "' 状态为 " .. (pod.status.phase or "未知") , {namespace=svc.namespace, name=svc.name, webhook=webhook.name, pod=pod.metadata.name, phase=pod.status.phase})
											end
										end
									end
								end
							end
						end
					end
				end
			end
			print("ValidatingWebhookConfiguration 合规性检查完成")
		`,
	},
	{
		Name:        "Pod 日志错误检测",
		Description: "检查某一个 Pod 的最近日志是否包含指定关键字,若包含则认为检测失败。",
		Group:       "",
		Version:     "v1",
		Kind:        "Pod",
		ScriptType:  constants.LuaScriptTypeBuiltin,
		ScriptCode:  "Builtin_Pod_Log_Error_031",
		Script: `
			-- 示例:根据已知 Deployment 名称与命名空间,按其 selector 获取 Pod 列表并检查日志
			-- 请按需修改以下四个变量
			local deployName = "your-deploy-name"
			local namespace = "default"
			local keyword = "ERROR"  -- 默认关键字为 "ERROR",可按需改为要检测的关键字
			local tailLines = 200    -- 默认读取最近 200 行日志,按需调整

			-- 获取 Deployment 对象
			local dep, derr = kubectl:GVK("apps", "v1", "Deployment"):Namespace(namespace):Name(deployName):Get()
			if derr ~= nil or not dep then
				print("获取 Deployment 失败: " .. tostring(derr))
				return
			end

			-- 从 Deployment 的 selector.matchLabels 构建 LabelSelector
			local matchLabels = dep.spec and dep.spec.selector and dep.spec.selector.matchLabels or nil
			if not matchLabels then
				print("Deployment 未定义 selector.matchLabels,无法按标签筛选 Pod")
				return
			end
			local labelSelector = ""
			for k, v in pairs(matchLabels) do
				if labelSelector ~= "" then labelSelector = labelSelector .. "," end
				labelSelector = labelSelector .. k .. "=" .. v
			end

			-- 按 Deployment 的 selector 在同一命名空间获取 Pod 列表
			local pods, perr = kubectl:GVK("", "v1", "Pod"):Namespace(namespace):Cache(10):WithLabelSelector(labelSelector):List()
			if perr ~= nil then
				print("获取 Pod 列表失败: " .. tostring(perr))
				return
			end
			if not pods or #pods == 0 then
				print("未找到与 Deployment 匹配的 Pod: " .. namespace .. "/" .. deployName .. ", selector=" .. labelSelector)
				return
			end

			local foundError = false
			for _, pod in ipairs(pods) do
				local ns = pod.metadata.namespace
				local name = pod.metadata.name
				local containerName = nil
				if pod.spec and pod.spec.containers and #pod.spec.containers > 0 then
					containerName = pod.spec.containers[1].name
				end
				local opts = { tailLines = tailLines }
				if containerName ~= nil then
					opts.container = containerName
				end
				local logs, lerr = kubectl:GVK("", "v1", "Pod"):Namespace(ns):Name(name):GetLogs(opts)
				if lerr ~= nil then
					print("获取 Pod 日志失败: " .. tostring(lerr))
				else
					local logStr = (type(logs) == "string") and logs or tostring(logs)
					if logStr and string.find(logStr, keyword) ~= nil then
						foundError = true
						check_event("失败", "Pod 日志包含关键字 '" .. keyword .. "'", {namespace=ns, name=name, container=containerName, keyword=keyword})
					else
						print("Pod " .. ns .. "/" .. name .. " 最近日志未发现 '" .. keyword .. "'")
					end
				end
			end

			if not foundError then
				print("Deployment '" .. namespace .. "/" .. deployName .. "' 关联 Pod 的日志检查完成,未发现 '" .. keyword .. "'")
			end
			print("Pod 日志错误检测完成")
		`,
	},
	{
		Name:           "Pod 资源用量检查",
		Description:    "检查指定 Pod 的资源用量情况,包括 CPU 和内存的请求、限制、实时用量等信息",
		Group:          "",
		Version:        "v1",
		Kind:           "Pod",
		ScriptType:     constants.LuaScriptTypeBuiltin,
		ScriptCode:     "Builtin_Pod_ResourceUsage_032",
		TimeoutSeconds: 90,
		Script: `
			-- =============================
-- 🧩 Pod 资源用量检查脚本(JSON格式输出 + 比例修正)
-- =============================

-- 请修改以下变量为您要检查的 Pod 信息
local podName = "k8m-c6dccfb-qm7cp"  -- 要检查的 Pod 名称
local podNamespace = "k8m"           -- Pod 所在的命名空间

-- =============================
-- 可配置的告警阈值
-- =============================
-- 
-- 配置说明:
-- - cpuThreshold: CPU 使用率告警阈值,取值范围 0.0-1.0(例如:0.8 表示 80%)
-- - memoryThreshold: 内存使用率告警阈值,取值范围 0.0-1.0(例如:0.9 表示 90%)
-- 
-- 建议值:
-- - 生产环境:CPU 0.7-0.8,内存 0.8-0.9
-- - 测试环境:CPU 0.8-0.9,内存 0.9-0.95
-- - 开发环境:可适当放宽至 CPU 0.9,内存 0.95
local cpuThreshold = 0.8    -- CPU 使用率告警阈值(80%)
local memoryThreshold = 0.9 -- 内存使用率告警阈值(90%)

-- =============================
-- 工具函数
-- =============================

-- 将 Lua table 转为美化 JSON 字符串
local function to_json(tbl, indent)
    indent = indent or 0
    local padding = string.rep("  ", indent)
    if type(tbl) ~= "table" then
        if type(tbl) == "string" then
            return string.format("%q", tbl)
        else
            return tostring(tbl)
        end
    end
    local lines = {"{"}
    for k, v in pairs(tbl) do
        local key = string.format("%q", tostring(k))
        local val = to_json(v, indent + 1)
        local comma = (next(tbl, k) ~= nil) and "," or ""
        table.insert(lines, string.rep("  ", indent + 1) .. key .. ": " .. val .. comma)
    end
    table.insert(lines, padding .. "}")
    return table.concat(lines, "\n")
end

-- 字节换算为人类可读单位
local function human_bytes(n)
    if type(n) ~= "number" then return tostring(n) end
    local units = {"B", "KiB", "MiB", "GiB", "TiB"}
    local i = 1
    while n >= 1024 and i < #units do
        n = n / 1024
        i = i + 1
    end
    return string.format("%.2f %s", n, units[i])
end

-- 获取 allocatable.memory 的值
local function get_allocatable_memory(r)
    if not r then return nil end
    if r.memory and r.memory.allocatable then
        return tonumber(r.memory.allocatable)
    end
    if r.allocatable and r.allocatable.memory then
        return tonumber(r.allocatable.memory)
    end
    return nil
end

-- =============================
-- 获取 Pod 资源用量
-- =============================

local resourceUsage, err = kubectl:GVK("", "v1", "Pod"):Namespace(podNamespace):Name(podName):GetPodResourceUsage()
if err then
    print("获取 Pod 资源用量失败: " .. tostring(err))
    return
end

if not resourceUsage then
    print("Pod " .. podNamespace .. "/" .. podName .. " 资源用量信息为空")
    return
end

print("=== Pod 资源用量原始数据(JSON 格式) ===")
print(to_json(resourceUsage))

print("\n=== Pod 资源用量检查结果 ===")
print("Pod: " .. podNamespace .. "/" .. podName)

-- =============================
-- CPU 检查
-- =============================
if resourceUsage.cpu then
    print("\n--- CPU 资源 ---")
    if resourceUsage.cpu.requests then
        print("CPU 请求量: " .. tostring(resourceUsage.cpu.requests))
    end
    if resourceUsage.cpu.limits then
        print("CPU 限制量: " .. tostring(resourceUsage.cpu.limits))
    end
    if resourceUsage.cpu.realtime then
        print("CPU 实时用量: " .. tostring(resourceUsage.cpu.realtime))
    elseif resourceUsage.realtime and resourceUsage.realtime.cpu then
        print("CPU 实时用量: " .. tostring(resourceUsage.realtime.cpu))
    end
    if resourceUsage.cpu.allocatable then
        print("CPU 可分配量: " .. tostring(resourceUsage.cpu.allocatable))
    elseif resourceUsage.allocatable and resourceUsage.allocatable.cpu then
        print("CPU 可分配量: " .. tostring(resourceUsage.allocatable.cpu))
    end

    local cpuUsage = nil
    if resourceUsage.cpu.usageFractions then
        cpuUsage = tonumber(resourceUsage.cpu.usageFractions)
    elseif resourceUsage.usageFractions and resourceUsage.usageFractions.cpu and resourceUsage.usageFractions.cpu.realtimeFraction then
        cpuUsage = tonumber(resourceUsage.usageFractions.cpu.realtimeFraction)
    end

    if cpuUsage then
        if cpuUsage > 1 then
            print(string.format("CPU 使用率 (原始): %.2f%%", cpuUsage))
            cpuUsage = cpuUsage / 100
        end
        print(string.format("CPU 使用率: %.2f%%", cpuUsage * 100))
        if cpuUsage > cpuThreshold then
            check_event("警告", "Pod " .. podNamespace .. "/" .. podName .. " CPU 使用率过高: " .. string.format("%.2f%%", cpuUsage * 100), {namespace=podNamespace, name=podName, cpuUsage=cpuUsage})
        end
    end
end

-- =============================
-- 内存检查(修正版)
-- =============================
if resourceUsage.memory or resourceUsage.allocatable then
    print("\n--- 内存资源 ---")

    local memRealtime = nil
    if resourceUsage.memory and resourceUsage.memory.realtime then
        memRealtime = tonumber(resourceUsage.memory.realtime)
    elseif resourceUsage.realtime and resourceUsage.realtime.memory then
        memRealtime = tonumber(resourceUsage.realtime.memory)
    end

    local memAllocatable = get_allocatable_memory(resourceUsage)
    local memRequests = resourceUsage.memory and resourceUsage.memory.requests or nil
    local memLimits = resourceUsage.memory and resourceUsage.memory.limits or nil

    print("内存请求量: " .. tostring(memRequests or "(未设置)"))
    print("内存限制量: " .. tostring(memLimits or "(未设置)"))

    if memRealtime then
        print("内存实时用量: " .. human_bytes(memRealtime))
    else
        print("内存实时用量: (无数据)")
    end

    if memAllocatable then
        print("内存可分配量: " .. human_bytes(memAllocatable))
    else
        print("内存可分配量: (无数据)")
    end

    -- 重新计算 fraction
    local recomputedFraction = nil
    if memRealtime and memAllocatable and memAllocatable > 0 then
        recomputedFraction = memRealtime / memAllocatable
    end

    if recomputedFraction then
        print(string.format("内存使用率: %.2f%%", recomputedFraction * 100))
        if recomputedFraction > memoryThreshold then
            check_event("警告", "Pod " .. podNamespace .. "/" .. podName .. " 内存使用率过高: " .. string.format("%.2f%%", recomputedFraction * 100), {namespace=podNamespace, name=podName, memoryUsage=recomputedFraction})
        end
    else
        local rawUF = nil
        if resourceUsage.usageFractions and resourceUsage.usageFractions.memory and resourceUsage.usageFractions.memory.realtimeFraction then
            rawUF = tonumber(resourceUsage.usageFractions.memory.realtimeFraction)
        end
        if rawUF then
            if rawUF > 1 then
                print(string.format("内存使用率 (来源 usageFractions): %.2f%% (已推测为百分比)", rawUF))
                rawUF = rawUF / 100
            else
                print(string.format("内存使用率: %.2f%%", rawUF * 100))
            end
            if rawUF > memoryThreshold then
                check_event("警告", "Pod " .. podNamespace .. "/" .. podName .. " 内存使用率过高: " .. string.format("%.2f%%", rawUF * 100), {namespace=podNamespace, name=podName, memoryUsage=rawUF})
            end
        else
            print("内存使用率: (无法计算 —— 缺少数据)")
        end
    end
end

-- =============================
-- 检查 requests / limits 配置
-- =============================
local hasRequests = (resourceUsage.cpu and resourceUsage.cpu.requests) or (resourceUsage.memory and resourceUsage.memory.requests)
local hasLimits = (resourceUsage.cpu and resourceUsage.cpu.limits) or (resourceUsage.memory and resourceUsage.memory.limits)

if not hasRequests then
    check_event("失败", "Pod " .. podNamespace .. "/" .. podName .. " 未配置资源请求量 (requests)", {namespace=podNamespace, name=podName})
end

if not hasLimits then
    check_event("失败", "Pod " .. podNamespace .. "/" .. podName .. " 未配置资源限制量 (limits)", {namespace=podNamespace, name=podName})
end

print("\n✅ Pod 资源用量检查完成")

		`,
	},
}

BuiltinLuaScripts 内置检查脚本列表

Functions

func AddBuiltinLuaScripts added in v0.0.129

func AddBuiltinLuaScripts() error

func AddInnerAdminUser added in v0.0.97

func AddInnerAdminUser() error

AddInnerAdminUser 添加内置管理员账户

func AddInnerAdminUserGroup added in v0.0.97

func AddInnerAdminUserGroup() error

AddInnerAdminUserGroup 添加内置管理员账户组

func AddInnerMCPServer added in v0.0.66

func AddInnerMCPServer() error

AddInnerMCPServer 检查并初始化名为 "k8m" 的内部 MCP 服务器配置,不存在则创建,已存在则更新其 URL。

func AutoMigrate

func AutoMigrate() error

func DeleteHelmReleaseByNsAndReleaseName added in v0.0.137

func DeleteHelmReleaseByNsAndReleaseName(namespace, releaseName, cluster string) error

DeleteHelmReleaseByNsAndReleaseName 删除指定namespace和releaseName的HelmRelease记录

func FixClusterAuthorizationTypeName added in v0.0.87

func FixClusterAuthorizationTypeName() error

func FixClusterName added in v0.0.48

func FixClusterName() error

func FixRoleName added in v0.0.69

func FixRoleName() error

func GetBuiltinLuaScriptsVersion added in v0.0.129

func GetBuiltinLuaScriptsVersion(db *gorm.DB) (string, error)

GetBuiltinLuaScriptsVersion 获取数据库中记录的内置脚本版本

func GetBuiltinPromptContent added in v0.0.165

func GetBuiltinPromptContent(promptType constants.AIPromptType) string

GetBuiltinPromptContent 根据提示词类型获取内置提示词内容 参数:

  • promptType: 提示词类型

返回值:

  • string: 提示词内容,如果未找到则返回空字符串

func InitBuiltinAIPrompts added in v0.0.165

func InitBuiltinAIPrompts() error

InitBuiltinAIPrompts 初始化内置AI提示词

func InitConditionTable added in v0.0.86

func InitConditionTable() error

func InitConfigTable added in v0.0.74

func InitConfigTable() error

func MigrateAIModel added in v0.0.124

func MigrateAIModel() error

func SetBuiltinLuaScriptsVersion added in v0.0.129

func SetBuiltinLuaScriptsVersion(db *gorm.DB, version string) error

SetBuiltinLuaScriptsVersion 设置数据库中内置脚本的版本号

Types

type AIModelConfig added in v0.0.124

type AIModelConfig struct {
	ID          uint      `gorm:"primaryKey;autoIncrement" json:"id"`
	ApiKey      string    `json:"api_key"`
	ApiURL      string    `json:"api_url"`
	ApiModel    string    `json:"api_model"`
	Temperature float32   `json:"temperature"`
	TopP        float32   `json:"top_p"`
	Think       bool      `json:"think"` // 是否关闭思考模式
	Description string    `json:"description,omitempty"`
	CreatedAt   time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt   time.Time `json:"updated_at,omitempty"`
}

func (*AIModelConfig) Delete added in v0.0.124

func (c *AIModelConfig) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*AIModelConfig) GetOne added in v0.0.124

func (c *AIModelConfig) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*AIModelConfig, error)

func (*AIModelConfig) List added in v0.0.124

func (c *AIModelConfig) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*AIModelConfig, int64, error)

func (*AIModelConfig) Save added in v0.0.124

func (c *AIModelConfig) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type AIPrompt added in v0.0.165

type AIPrompt struct {
	ID          uint                   `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Name        string                 `json:"name" gorm:"size:100;not null"`             // 提示词名称
	Description string                 `json:"description" gorm:"size:500"`               // 提示词描述
	PromptType  constants.AIPromptType `json:"prompt_type" gorm:"size:50;not null;index"` // 提示词类型
	Content     string                 `json:"content" gorm:"type:text;not null"`         // 提示词内容
	IsBuiltin   bool                   `json:"is_builtin" gorm:"default:false;index"`     // 是否为内置提示词
	IsEnabled   bool                   `json:"is_enabled" gorm:"default:false;index"`     // 是否启用
	CreatedAt   time.Time              `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt   time.Time              `json:"updated_at,omitempty"`
}

AIPrompt AI提示词模型 用于存储和管理AI提示词的配置信息

func (*AIPrompt) Delete added in v0.0.165

func (m *AIPrompt) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete 删除AI提示词

func (*AIPrompt) GetOne added in v0.0.165

func (m *AIPrompt) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*AIPrompt, error)

GetOne 获取单个AI提示词

func (*AIPrompt) List added in v0.0.165

func (m *AIPrompt) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*AIPrompt, int64, error)

List 获取AI提示词列表

func (*AIPrompt) Save added in v0.0.165

func (m *AIPrompt) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Save 保存AI提示词

func (AIPrompt) TableName added in v0.0.165

func (AIPrompt) TableName() string

TableName 表名

type ApiKey added in v0.0.80

type ApiKey struct {
	ID          uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Username    string    `gorm:"index;not null" json:"username,omitempty"` // 所属用户
	Key         string    `gorm:"type:text" json:"key,omitempty"`           // API密钥值
	Description string    `json:"description,omitempty"`                    // 描述信息
	CreatedAt   time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt   time.Time `json:"updated_at,omitempty"`   // Automatically managed by GORM for update time
	CreatedBy   string    `json:"created_by,omitempty"`   // 创建者
	LastUsedAt  time.Time `json:"last_used_at,omitempty"` // 最后使用时间
}

ApiKey 用户API密钥

func (*ApiKey) Delete added in v0.0.80

func (c *ApiKey) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*ApiKey) GetOne added in v0.0.80

func (c *ApiKey) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*ApiKey, error)

func (*ApiKey) List added in v0.0.80

func (c *ApiKey) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*ApiKey, int64, error)

func (*ApiKey) Save added in v0.0.80

func (c *ApiKey) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type ClusterUserRole added in v0.0.69

type ClusterUserRole struct {
	ID                  uint                               `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Cluster             string                             `gorm:"index" json:"cluster,omitempty"`  // 集群名称
	Username            string                             `gorm:"index" json:"username,omitempty"` // 用户名
	Role                string                             `gorm:"index" json:"role,omitempty"`     // 角色类型:只读、读写、Exec
	Namespaces          string                             `json:"namespaces,omitempty"`            // Namespaces列表,逗号分割 ,该用户可以访问的Ns
	BlacklistNamespaces string                             `json:"blacklist_namespaces,omitempty"`  // 黑名单Namespaces列表,逗号分割,禁止访问的Ns
	AuthorizationType   constants.ClusterAuthorizationType `json:"authorization_type,omitempty"`    // 用户类型。User\Group两种,默认为User,空为User。Group指用户组
	CreatedAt           time.Time                          `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt           time.Time                          `json:"updated_at,omitempty"`
}

ClusterUserRole 集群用户权限表 AuthorizationType有两种类型(user、user_group),如果是用户,那么代表这个人有哪些权限 如果是Group,那么代表这个组有哪些权限,这个组可能会有多个用户,那么这多个用户都有相关的权限

func (*ClusterUserRole) Delete added in v0.0.69

func (c *ClusterUserRole) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*ClusterUserRole) GetOne added in v0.0.69

func (c *ClusterUserRole) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*ClusterUserRole, error)

func (*ClusterUserRole) List added in v0.0.69

func (c *ClusterUserRole) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*ClusterUserRole, int64, error)

func (*ClusterUserRole) Save added in v0.0.69

func (c *ClusterUserRole) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type ConditionReverse added in v0.0.86

type ConditionReverse struct {
	ID          uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Name        string    `gorm:"type:text" json:"name,omitempty"`        // 指标名称,使用包含方式查找。如Pressure、Unavailable等
	Enabled     bool      `json:"enabled,omitempty"`                      // 指标描述
	Description string    `gorm:"type:text" json:"description,omitempty"` // 指标描述
	CreatedAt   time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt   time.Time `json:"updated_at,omitempty"` // 更新时间
}

ConditionReverse 用于记录需要反转解释的K8s状态指标

func (*ConditionReverse) Delete added in v0.0.86

func (c *ConditionReverse) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete 删除记录

func (*ConditionReverse) GetOne added in v0.0.86

func (c *ConditionReverse) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*ConditionReverse, error)

GetOne 获取单条记录

func (*ConditionReverse) List added in v0.0.86

func (c *ConditionReverse) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*ConditionReverse, int64, error)

List 列出所有记录

func (*ConditionReverse) Save added in v0.0.86

func (c *ConditionReverse) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Save 保存记录

type Config added in v0.0.74

type Config struct {
	ID                   uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	ProductName          string    `json:"product_name,omitempty"` // 产品名称
	LoginType            string    `json:"login_type,omitempty"`
	JwtTokenSecret       string    `json:"jwt_token_secret,omitempty"`
	NodeShellImage       string    `json:"node_shell_image,omitempty"`
	KubectlShellImage    string    `json:"kubectl_shell_image,omitempty"`
	ImagePullTimeout     int       `gorm:"default:30" json:"image_pull_timeout,omitempty"` // 镜像拉取超时时间(秒)
	AnySelect            bool      `gorm:"default:true" json:"any_select"`
	PrintConfig          bool      `json:"print_config"`
	EnableAI             bool      `gorm:"default:true" json:"enable_ai"`                      // 是否启用AI功能,默认开启
	EnableSwagger        bool      `gorm:"default:true" json:"enable_swagger"`                 // 是否启用Swagger文档,默认开启
	UseBuiltInModel      bool      `gorm:"default:true" json:"use_built_in_model"`             // 是否使用内置模型,默认开启
	MaxIterations        int32     `json:"max_iterations"`                                     //  模型自动对话的最大轮数
	MaxHistory           int32     `json:"max_history"`                                        //  模型对话上下文历史记录数
	ResourceCacheTimeout int       `gorm:"default:60" json:"resource_cache_timeout,omitempty"` // 资源缓存时间(秒)
	ModelID              uint      `json:"model_id"`
	CreatedAt            time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt            time.Time `json:"updated_at,omitempty"` // Automatically managed by GORM for update time
}

func (*Config) Delete added in v0.0.124

func (c *Config) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*Config) GetOne added in v0.0.124

func (c *Config) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*Config, error)

func (*Config) List added in v0.0.124

func (c *Config) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*Config, int64, error)

func (*Config) Save added in v0.0.124

func (c *Config) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type CustomTemplate

type CustomTemplate struct {
	ID        uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"` // 模板 ID,主键,自增
	Name      string    `gorm:"index" json:"name,omitempty"`                  // 模板名称,非空,最大长度 255
	Content   string    `gorm:"type:text" json:"content,omitempty"`           // 模板内容,支持大文本存储
	Kind      string    `gorm:"index" json:"kind,omitempty"`                  // 模板类型,最大长度 100
	Cluster   string    `gorm:"index" json:"cluster,omitempty"`               // 模板类型,最大长度 100
	IsGlobal  bool      `gorm:"index" json:"is_global,omitempty"`             // 模板类型,最大长度 100
	CreatedBy string    `gorm:"index" json:"created_by,omitempty"`            // 创建者
	CreatedAt time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt time.Time `json:"updated_at,omitempty"` // Automatically managed by GORM for update time
}

CustomTemplate 表示用户自定义模板表的结构体

func (*CustomTemplate) Delete

func (c *CustomTemplate) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*CustomTemplate) GetOne

func (c *CustomTemplate) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*CustomTemplate, error)

func (*CustomTemplate) List

func (c *CustomTemplate) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*CustomTemplate, int64, error)

func (*CustomTemplate) Save

func (c *CustomTemplate) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type HelmChart added in v0.0.51

type HelmChart struct {
	ID             uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	RepositoryID   uint      `gorm:"index;not null" json:"repository_id,omitempty"` // 关联仓库ID
	RepositoryName string    `json:"repository_name,omitempty"`                     // 关联仓库ID
	Name           string    `gorm:"index;not null" json:"name,omitempty"`          // Chart名称
	LatestVersion  string    `json:"latest_version,omitempty"`                      // 最新版本(冗余字段,优化查询)
	Description    string    `json:"description,omitempty"`                         // Chart描述
	Home           string    `json:"home,omitempty"`                                // 项目主页URL
	Icon           string    `json:"icon,omitempty"`                                // Chart图标链接
	Keywords       string    `json:"keywords,omitempty"`                            // 关键词(PostgreSQL数组类型)
	KubeVersion    string    `json:"kubeVersion,omitempty"`                         // 最低k8s版本要求
	AppVersion     string    `json:"appVersion,omitempty"`                          // app应用版本
	Deprecated     bool      `json:"deprecated,omitempty"`                          // Whether or not this chart is deprecated
	CreatedAt      time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt      time.Time `json:"updated_at"`
	Sources        string    `json:"sources,omitempty"` // 源码主页
}

func (*HelmChart) BatchSave added in v0.0.137

func (c *HelmChart) BatchSave(params *dao.Params, events []*HelmChart, batchSize int, queryFuncs ...func(*gorm.DB) *gorm.DB) error

BatchSave 批量保存 InspectionCheckEvent 实例

func (*HelmChart) Delete added in v0.0.51

func (c *HelmChart) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*HelmChart) GetOne added in v0.0.51

func (c *HelmChart) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*HelmChart, error)

func (*HelmChart) List added in v0.0.51

func (c *HelmChart) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*HelmChart, int64, error)

func (*HelmChart) Save added in v0.0.51

func (c *HelmChart) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type HelmRelease added in v0.0.137

type HelmRelease struct {
	ID           uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	ReleaseName  string    `gorm:"index" json:"release_name,omitempty"`       // Release 名称
	RepoName     string    `json:"repo_name,omitempty"`                       // 仓库名称
	Namespace    string    `gorm:"not null;index" json:"namespace,omitempty"` // 命名空间
	ChartName    string    `gorm:"not null" json:"chart_name,omitempty"`      // Chart 名称
	ChartVersion string    `json:"chart_version,omitempty"`                   // Chart 版本
	Values       string    `json:"values,omitempty"`                          // values.yaml 内容
	Status       string    `json:"status,omitempty"`                          // 安装状态
	Cluster      string    `json:"cluster,omitempty"`
	Result       string    `json:"result,omitempty"` // 描述
	CreatedAt    time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt    time.Time `json:"updated_at,omitempty"`
}

func GetHelmReleaseByNsAndReleaseName added in v0.0.137

func GetHelmReleaseByNsAndReleaseName(namespace, releaseName, cluster string) (*HelmRelease, error)

GetHelmReleaseByNsAndReleaseName 通过namespace和releaseName获取repo名称

func (*HelmRelease) Delete added in v0.0.137

func (r *HelmRelease) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*HelmRelease) GetOne added in v0.0.137

func (r *HelmRelease) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*HelmRelease, error)

func (*HelmRelease) List added in v0.0.137

func (r *HelmRelease) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*HelmRelease, int64, error)

func (*HelmRelease) Save added in v0.0.137

func (r *HelmRelease) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type HelmRepository added in v0.0.51

type HelmRepository struct {
	ID                    uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Name                  string    `gorm:"not null" json:"name,omitempty"` // 仓库名称(唯一)
	URL                   string    `gorm:"not null" json:"url,omitempty"`  // 仓库地址(如 https://charts.example.com
	Type                  string    `gorm:"comment:仓库类型(OCI/HTTP)" json:"type,omitempty"`
	Description           string    `json:"description,omitempty"` // 仓库描述
	AuthType              string    `gorm:"comment:认证类型(Basic/AuthToken/OAuth)" json:"auth_type,omitempty"`
	Username              string    `json:"username,omitempty"` // 认证用户名(加密存储)
	Password              string    `gorm:"-;comment:密码(临时字段,存储时需加密)" json:"password,omitempty"`
	EncryptedSecret       string    `gorm:"comment:加密后的凭据" json:"encrypted_secret,omitempty"`
	IsActive              bool      `gorm:"default:true" json:"is_active,omitempty"` // 是否启用
	Generated             string    `json:"generated,omitempty"`                     // repo 索引文件创建时间
	CertFile              string    `json:"certFile,omitempty"`
	KeyFile               string    `json:"keyFile,omitempty"`
	CAFile                string    `json:"caFile,omitempty"`
	InsecureSkipTLSverify bool      `json:"insecure_skip_tls_verify,omitempty"`
	PassCredentialsAll    bool      `json:"pass_credentials_all,omitempty"`
	CreatedAt             time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt             time.Time `json:"updated_at,omitempty"` // Automatically managed by GORM for update time
}

func (*HelmRepository) Delete added in v0.0.51

func (c *HelmRepository) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*HelmRepository) GetIDByNameAndURL added in v0.0.51

func (c *HelmRepository) GetIDByNameAndURL(params *dao.Params) (uint, error)

func (*HelmRepository) GetOne added in v0.0.51

func (c *HelmRepository) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*HelmRepository, error)

func (*HelmRepository) List added in v0.0.51

func (c *HelmRepository) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*HelmRepository, int64, error)

func (*HelmRepository) Save added in v0.0.51

func (c *HelmRepository) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type InspectionCheckEvent added in v0.0.129

type InspectionCheckEvent struct {
	ID          uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	RecordID    uint      `json:"record_id"`                        // 关联的巡检执行记录ID
	EventStatus string    `json:"event_status"`                     // 事件状态(如“正常”、“失败”)
	EventMsg    string    `json:"event_msg"`                        // 事件消息
	Extra       string    `gorm:"type:text" json:"extra,omitempty"` // 额外上下文
	ScriptName  string    `json:"script_name"`                      // 检测脚本名称
	Kind        string    `json:"kind"`                             // 检查的资源类型
	CheckDesc   string    `json:"check_desc"`                       // 检查脚本内容描述
	Cluster     string    `json:"cluster"`                          // 检查集群
	Namespace   string    `json:"namespace"`                        // 资源命名空间
	Name        string    `json:"name"`                             // 资源名称
	CreatedAt   time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt   time.Time `json:"updated_at,omitempty"`  // Automatically managed by GORM for update time
	ScheduleID  *uint     `json:"schedule_id,omitempty"` // 关联的定时任务ID
}

InspectionCheckEvent 用于记录每次检测的详细信息,包括检测状态、消息、额外上下文、脚本名称、资源类型、描述、命名空间和资源名。

func (*InspectionCheckEvent) BatchSave added in v0.0.129

func (c *InspectionCheckEvent) BatchSave(params *dao.Params, events []*InspectionCheckEvent, batchSize int, queryFuncs ...func(*gorm.DB) *gorm.DB) error

BatchSave 批量保存 InspectionCheckEvent 实例

func (*InspectionCheckEvent) Delete added in v0.0.129

func (c *InspectionCheckEvent) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete 根据指定 ID 删除 InspectionCheckEvent 实例

func (*InspectionCheckEvent) GetOne added in v0.0.129

func (c *InspectionCheckEvent) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*InspectionCheckEvent, error)

GetOne 获取单个 InspectionCheckEvent 实例

func (*InspectionCheckEvent) List added in v0.0.129

func (c *InspectionCheckEvent) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*InspectionCheckEvent, int64, error)

List 返回符合条件的 InspectionCheckEvent 列表及总数

func (*InspectionCheckEvent) Save added in v0.0.129

func (c *InspectionCheckEvent) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Save 保存或更新 InspectionCheckEvent 实例

type InspectionLuaScript added in v0.0.129

type InspectionLuaScript struct {
	ID             uint                    `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Name           string                  `json:"name"`                                   // 脚本名称,主键
	Description    string                  `json:"description"`                            // 脚本描述
	Group          string                  `json:"group"`                                  // 分组
	Version        string                  `json:"version"`                                // 版本
	Kind           string                  `json:"kind"`                                   // 类型
	ScriptType     constants.LuaScriptType `json:"script_type"`                            // 脚本类型 内置/自定义
	Script         string                  `gorm:"type:text" json:"script"`                // 脚本内容
	ScriptCode     string                  `gorm:"uniqueIndex;size:64" json:"script_code"` // 脚本唯一标识码,每个脚本唯一
	TimeoutSeconds int                     `json:"timeout_seconds" gorm:"default:60"`      // 脚本执行超时时间(秒),默认60秒
	CreatedAt      time.Time               `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt      time.Time               `json:"updated_at,omitempty"` // Automatically managed by GORM for update time

}

InspectionLuaScript 表示一条 Lua 脚本的元数据及内容 包含脚本名称、描述、分组、版本、类型和脚本内容等信息 用于存储和管理自定义 Lua 脚本

func (*InspectionLuaScript) Delete added in v0.0.129

func (c *InspectionLuaScript) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete 根据指定 ID 删除 InspectionLuaScript 实例

func (*InspectionLuaScript) GetOne added in v0.0.129

func (c *InspectionLuaScript) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*InspectionLuaScript, error)

GetOne 获取单个 InspectionLuaScript 实例

func (*InspectionLuaScript) List added in v0.0.129

func (c *InspectionLuaScript) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*InspectionLuaScript, int64, error)

List 返回符合条件的 InspectionLuaScript 列表及总数

func (*InspectionLuaScript) Save added in v0.0.129

func (c *InspectionLuaScript) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Save 保存或更新 InspectionLuaScript 实例

type InspectionLuaScriptBuiltinVersion added in v0.0.129

type InspectionLuaScriptBuiltinVersion struct {
	Key       string    `gorm:"primaryKey;size:64" json:"key"` // 固定为 builtin_lua_scripts
	Version   string    `json:"version"`                       // 版本号
	UpdatedAt time.Time `json:"updated_at"`
}

InspectionLuaScriptBuiltinVersion 用于记录内置脚本的版本号 只会有一条记录,key 固定为 builtin_lua_scripts 用于判断是否需要更新内置脚本

type InspectionRecord added in v0.0.129

type InspectionRecord struct {
	ID           uint       `gorm:"primaryKey;autoIncrement" json:"id,omitempty"` // 主键
	ScheduleID   *uint      `json:"schedule_id,omitempty"`                        // 关联的定时任务ID,可为空(手动触发时为空)
	ScheduleName string     `json:"schedule_name,omitempty"`                      // 巡检任务名称快照
	Cluster      string     `json:"cluster"`                                      // 巡检目标集群
	TriggerType  string     `json:"trigger_type"`                                 // 触发类型(manual/cron)
	Status       string     `json:"status"`                                       // 执行状态(pending/running/success/failed)
	StartTime    time.Time  `json:"start_time"`
	EndTime      *time.Time `json:"end_time,omitempty"`
	ErrorCount   int        `json:"error_count"`
	AISummary    string     `gorm:"type:text" json:"ai_summary,omitempty"` // AI生成的巡检总结
	AISummaryErr string     `json:"ai_summary_err,omitempty"`              // AI生成错误
	ResultRaw    string     `gorm:"type:text" json:"result_raw,omitempty"` // AI总结前的原始巡检结果,JSON字符串格式
	CreatedAt    time.Time  `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt    time.Time  `json:"updated_at,omitempty"` // Automatically managed by GORM for update time

}

func (*InspectionRecord) Delete added in v0.0.129

func (c *InspectionRecord) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete 删除指定ID的 InspectionRecord

func (*InspectionRecord) GetAISummaryById added in v0.0.132

func (c *InspectionRecord) GetAISummaryById(recordID uint) (string, error)

GetAISummaryById 获取 InspectionRecord 的AISummary

func (*InspectionRecord) GetOne added in v0.0.129

func (c *InspectionRecord) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*InspectionRecord, error)

GetOne 获取单个 InspectionRecord

func (*InspectionRecord) GetRecordBothContentById added in v0.0.169

func (c *InspectionRecord) GetRecordBothContentById(recordID uint) (string, string, error)

GetRecordBothContentById 获取巡检记录的完整内容,同时返回AI总结和原始结果 参数:recordID 巡检记录ID 返回值:aiSummary AI总结内容,resultRaw 原始结果内容,error 错误

func (*InspectionRecord) GetRecordContentById added in v0.0.169

func (c *InspectionRecord) GetRecordContentById(recordID uint) (string, bool, error)

GetRecordContentById 获取巡检记录的内容,优先返回AI总结,如果没有则返回原始结果 返回值:content 内容,isAISummary 是否为AI总结(true)还是原始结果(false),error 错误

func (*InspectionRecord) List added in v0.0.129

func (c *InspectionRecord) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*InspectionRecord, int64, error)

List 返回符合条件的 InspectionRecord 列表及总数

func (*InspectionRecord) Save added in v0.0.129

func (c *InspectionRecord) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Save 保存或更新 InspectionRecord 实例

type InspectionSchedule added in v0.0.129

type InspectionSchedule struct {
	ID               uint         `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Name             string       `json:"name"`                                // 巡检任务名称
	Description      string       `json:"description"`                         // 巡检任务描述
	Clusters         string       `json:"clusters"`                            // 目标集群列表
	Webhooks         string       `json:"webhooks"`                            // webhook列表
	WebhookNames     string       `json:"webhook_names"`                       // webhook 名称列表
	Cron             string       `json:"cron"`                                // cron表达式,定时周期
	ScriptCodes      string       `gorm:"type:text" json:"script_codes"`       // 每个脚本唯一标识码
	Enabled          bool         `json:"enabled"`                             // 是否启用该任务
	AIEnabled        bool         `json:"ai_enabled"`                          // 是否启用AI总结功能
	AIPromptTemplate string       `gorm:"type:text" json:"ai_prompt_template"` // AI总结提示词模板
	CronRunID        cron.EntryID `json:"cron_run_id"`                         // cron 运行ID,可用于删除
	LastRunTime      *time.Time   `json:"last_run_time"`                       // 上次运行时间
	ErrorCount       int          `json:"error_count"`                         // 错误次数
	CreatedAt        time.Time    `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt        time.Time    `json:"updated_at,omitempty"` // Automatically managed by GORM for update time

}

InspectionSchedule 用于描述定时巡检任务的元数据,包括任务名称、描述、目标集群、cron表达式等 该结构体可用于存储和管理定时巡检任务的相关信息 字段涵盖任务名称、描述、目标集群、cron表达式、启用状态、AI总结功能配置、创建人和创建时间 支持配置AI总结功能的开关和自定义提示词模板 可结合数据库或配置管理进行持久化

func (*InspectionSchedule) Delete added in v0.0.129

func (c *InspectionSchedule) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete 根据指定 ID 删除 InspectionSchedule 实例

func (*InspectionSchedule) GetOne added in v0.0.129

func (c *InspectionSchedule) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*InspectionSchedule, error)

GetOne 获取单个 InspectionSchedule 实例

func (*InspectionSchedule) List added in v0.0.129

func (c *InspectionSchedule) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*InspectionSchedule, int64, error)

List 返回符合条件的 InspectionSchedule 列表及总数

func (*InspectionSchedule) Save added in v0.0.129

func (c *InspectionSchedule) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Save 保存或更新 InspectionSchedule 实例

type InspectionScriptResult added in v0.0.129

type InspectionScriptResult struct {
	ID         uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	RecordID   uint      `json:"record_id"`   // 关联的巡检执行记录ID
	ScriptName string    `json:"script_name"` // 脚本名称
	ScriptKind string    `json:"script_kind"` // 脚本资源类型
	ScriptDesc string    `json:"script_desc"` // 脚本描述
	StartTime  time.Time `json:"start_time"`
	EndTime    time.Time `json:"end_time"`
	StdOutput  string    `json:"std_output"`            // 脚本标准输出
	ErrorMsg   string    `json:"error_msg,omitempty"`   // 错误信息
	Cluster    string    `json:"cluster"`               // 目标集群
	ScheduleID *uint     `json:"schedule_id,omitempty"` // 巡检计划ID
	CreatedAt  time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt  time.Time `json:"updated_at,omitempty"` // Automatically managed by GORM for update time

}

func (*InspectionScriptResult) BatchSave added in v0.0.129

func (c *InspectionScriptResult) BatchSave(params *dao.Params, events []*InspectionScriptResult, batchSize int, queryFuncs ...func(*gorm.DB) *gorm.DB) error

BatchSave 批量保存 InspectionCheckEvent 实例

func (*InspectionScriptResult) Delete added in v0.0.129

func (c *InspectionScriptResult) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete 删除指定ID的 InspectionScriptResult

func (*InspectionScriptResult) GetOne added in v0.0.129

func (c *InspectionScriptResult) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*InspectionScriptResult, error)

GetOne 获取单个 InspectionScriptResult

func (*InspectionScriptResult) List added in v0.0.129

func (c *InspectionScriptResult) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*InspectionScriptResult, int64, error)

List 返回符合条件的 InspectionScriptResult 列表及总数

func (*InspectionScriptResult) Save added in v0.0.129

func (c *InspectionScriptResult) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Save 保存或更新 InspectionScriptResult 实例

type KubeConfig

type KubeConfig struct {
	ID          uint   `gorm:"primaryKey;autoIncrement" json:"id,omitempty"` // 模板 ID,主键,自增
	Content     string `gorm:"type:text" json:"content,omitempty"`           // 模板内容,支持大文本存储
	Server      string `json:"server,omitempty"`
	User        string `json:"user,omitempty"`
	Cluster     string `json:"cluster,omitempty"` // 类型,最大长度 100
	Namespace   string `json:"namespace,omitempty"`
	DisplayName string `json:"display_name,omitempty"`
	// aws 集群相关
	AccessKey       string `json:"-"`                    // AWS Access Key ID
	SecretAccessKey string `json:"-"`                    // AWS Secret Access Key
	ClusterName     string `json:"cluster_name"`         // AWS EKS 集群名称
	Region          string `json:"region"`               // AWS 区域
	IsAWSEKS        bool   `json:"is_aws_eks,omitempty"` // 标识是否为AWS EKS集群
	// token 纳管相关 server\token\cadata
	Token  string `gorm:"type:text" json:"token,omitempty"`   // token 内容,支持大文本存储
	CACert string `gorm:"type:text" json:"ca_data,omitempty"` // ca 证书内容,支持大文本存储

	// kom 集群注册配置项
	// ProxyURL 设置 HTTP 代理,例如 http://127.0.0.1:7890
	ProxyURL string `gorm:"type:varchar(255)" json:"proxy_url,omitempty"`
	// Timeout 设置请求超时时间,单位为秒,默认为 30 秒
	Timeout int `gorm:"default:30" json:"timeout,omitempty"`
	// QPS 设置每秒查询数限制,默认为 200
	QPS float32 `gorm:"default:200" json:"qps,omitempty"`
	// Burst 设置突发请求数限制,默认为 2000
	Burst int `gorm:"default:2000" json:"burst,omitempty"`

	CreatedAt time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt time.Time `json:"updated_at,omitempty"` // Automatically managed by GORM for update time
}

KubeConfig 用户导入kubeconfig

func (*KubeConfig) AfterFind added in v0.0.153

func (c *KubeConfig) AfterFind(tx *gorm.DB) error

AfterFind 在查询后解密敏感字段

func (*KubeConfig) BeforeSave added in v0.0.153

func (c *KubeConfig) BeforeSave(tx *gorm.DB) error

BeforeSave 在保存前加密敏感字段

func (*KubeConfig) Delete

func (c *KubeConfig) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*KubeConfig) GetOne

func (c *KubeConfig) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*KubeConfig, error)

func (*KubeConfig) List

func (c *KubeConfig) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*KubeConfig, int64, error)

func (*KubeConfig) Save

func (c *KubeConfig) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type LDAPConfig added in v0.0.148

type LDAPConfig struct {
	ID              uint      `gorm:"primaryKey" json:"id"`
	Name            string    `gorm:"size:50;not null" json:"name"`            // 配置名称
	Host            string    `gorm:"size:100;not null" json:"host"`           // 服务器地址
	Port            int       `gorm:"not null" json:"port"`                    // 端口
	BindDN          string    `gorm:"size:100;not null" json:"bind_dn"`        // 管理员DN
	BindPassword    string    `gorm:"not null" json:"bind_password,omitempty"` // 管理员密码(加密存储)
	BaseDN          string    `gorm:"size:100;not null" json:"base_dn"`        // 基础DN
	UserFilter      string    `gorm:"size:255" json:"user_filter"`             // 用户过滤器
	LOGIN2AUTHCLOSE bool      `gorm:"default:true" json:"login2_auth_close"`   // 登录后开启认证
	DefaultGroup    string    `gorm:"size:50" json:"default_group"`            // 默认用户组
	Enabled         bool      `gorm:"default:true" json:"enabled"`             // 启用状态
	CreatedAt       time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt       time.Time `json:"updated_at"`
}

func (*LDAPConfig) Delete added in v0.0.148

func (l *LDAPConfig) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete 删除记录

func (*LDAPConfig) GetOne added in v0.0.148

func (l *LDAPConfig) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*LDAPConfig, error)

GetOne 获取单条记录

func (*LDAPConfig) List added in v0.0.148

func (l *LDAPConfig) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*LDAPConfig, int64, error)

List 列出所有记录

func (*LDAPConfig) Save added in v0.0.148

func (l *LDAPConfig) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Save 保存记录

type MCPServerConfig added in v0.0.64

type MCPServerConfig struct {
	ID        uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	URL       string    `gorm:"not null" json:"url,omitempty"`
	Name      string    `gorm:"uniqueIndex;not null;type:varchar(255)" json:"name,omitempty"`
	Enabled   bool      `gorm:"default:false" json:"enabled,omitempty"`
	CreatedAt time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt time.Time `json:"updated_at,omitempty"`
}

MCPServerConfig MCP服务器配置

func (*MCPServerConfig) Delete added in v0.0.64

func (c *MCPServerConfig) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*MCPServerConfig) GetOne added in v0.0.64

func (c *MCPServerConfig) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*MCPServerConfig, error)

func (*MCPServerConfig) List added in v0.0.64

func (c *MCPServerConfig) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*MCPServerConfig, int64, error)

func (*MCPServerConfig) Save added in v0.0.64

func (c *MCPServerConfig) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type MCPTool added in v0.0.85

type MCPTool struct {
	ID          uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	ServerName  string    `json:"server_name,omitempty"`                                        // mcp server id,唯一
	Name        string    `gorm:"uniqueIndex;not null;type:varchar(255)" json:"name,omitempty"` // 工具名称,唯一
	Description string    `gorm:"type:text" json:"description,omitempty"`                       // 工具描述
	InputSchema string    `gorm:"type:text" json:"input_schema,omitempty"`                      // 输入模式,JSON格式
	Enabled     bool      `gorm:"default:true" json:"enabled,omitempty"`                        // 是否启用
	CreatedAt   time.Time `json:"created_at,omitempty" gorm:"<-:create"`                        // 创建时间
	UpdatedAt   time.Time `json:"updated_at,omitempty"`                                         // 更新时间
}

MCPTool MCP工具配置

func (*MCPTool) BatchSave added in v0.0.85

func (c *MCPTool) BatchSave(params *dao.Params, tools []*MCPTool, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*MCPTool) Delete added in v0.0.85

func (c *MCPTool) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*MCPTool) GetOne added in v0.0.85

func (c *MCPTool) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*MCPTool, error)

func (*MCPTool) List added in v0.0.85

func (c *MCPTool) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*MCPTool, int64, error)

func (*MCPTool) Save added in v0.0.85

func (c *MCPTool) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type MCPToolCallResult added in v0.0.107

type MCPToolCallResult struct {
	ToolName   string `json:"tool_name"`
	Parameters any    `json:"parameters"`
	Result     string `json:"result"`
	Error      string `json:"error,omitempty"`
}

MCPToolCallResult 存储工具调用的结果

type MCPToolLog added in v0.0.88

type MCPToolLog struct {
	ID          uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	ToolName    string    `gorm:"index" json:"tool_name,omitempty"`      // 工具名称
	ServerName  string    `gorm:"index" json:"server_name,omitempty"`    // 服务器名称
	Parameters  string    `gorm:"type:text" json:"parameters,omitempty"` // 执行参数
	Prompt      string    `gorm:"type:text" json:"prompt,omitempty"`
	Result      string    `gorm:"type:text" json:"result,omitempty"` // 执行结果
	Error       string    `gorm:"type:text" json:"error,omitempty"`  // 错误信息
	ExecuteTime int64     `json:"execute_time,omitempty"`            // 执行时间(毫秒)
	CreatedAt   time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	CreatedBy   string    `gorm:"index" json:"created_by,omitempty"`
}

MCPToolLog MCP工具执行日志

func (*MCPToolLog) Delete added in v0.0.88

func (c *MCPToolLog) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*MCPToolLog) GetOne added in v0.0.88

func (c *MCPToolLog) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*MCPToolLog, error)

func (*MCPToolLog) List added in v0.0.88

func (c *MCPToolLog) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*MCPToolLog, int64, error)

func (*MCPToolLog) Save added in v0.0.88

func (c *MCPToolLog) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type McpKey added in v0.0.89

type McpKey struct {
	ID          uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Username    string    `gorm:"index;not null" json:"username,omitempty"` // 所属用户
	McpKey      string    `gorm:"type:text" json:"mcp_key,omitempty"`       // MCP密钥值
	Description string    `json:"description,omitempty"`                    // 描述信息
	Enabled     bool      `gorm:"default:true" json:"enabled,omitempty"`    // 是否启用
	Jwt         string    `gorm:"type:text" json:"jwt"`                     //  JWT
	LastUsedAt  time.Time `json:"last_used_at,omitempty"`                   // 最后使用时间
	CreatedAt   time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt   time.Time `json:"updated_at,omitempty"` // Automatically managed by GORM for update time
	CreatedBy   string    `json:"created_by,omitempty"` // 创建者
}

McpKey MCP访问密钥

func (*McpKey) Delete added in v0.0.89

func (c *McpKey) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*McpKey) GetOne added in v0.0.89

func (c *McpKey) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*McpKey, error)

func (*McpKey) List added in v0.0.89

func (c *McpKey) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*McpKey, int64, error)

func (*McpKey) Save added in v0.0.89

func (c *McpKey) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error
type Menu struct {
	ID        uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	MenuData  string    `gorm:"type:text" json:"-"`
	CreatedAt time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt time.Time `json:"updated_at,omitempty"`
}

Menu represents a versioned menu structure. Each save operation creates a new record with an incremented version.

func (m *Menu) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete removes menu records by their IDs.

func (m *Menu) DeleteByID(id int) error

DeleteByID removes a single menu record by its ID.

func (m *Menu) GetLatest(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*Menu, error)

GetLatest retrieves the latest version of the menu.

func (m *Menu) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*Menu, error)

GetOne retrieves a single menu record by its ID.

func (m *Menu) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*Menu, int64, error)

List retrieves a list of menu versions based on parameters.

func (m *Menu) MarshalJSON() ([]byte, error)

MarshalJSON 自定义JSON序列化方法 将存储在数据库中的字符串转换为JSON对象

func (c *Menu) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error
func (m *Menu) UnmarshalJSON(data []byte) error

UnmarshalJSON 自定义JSON反序列化方法 将接收到的JSON数据转换为字符串存储

type MenuDataJSON struct {
	ID        uint      `json:"id,omitempty"`
	MenuData  any       `json:"menu_data,omitempty"`
	CreatedAt time.Time `json:"created_at,omitempty"`
	UpdatedAt time.Time `json:"updated_at,omitempty"`
}

MenuDataJSON 用于处理JSON序列化和反序列化

type OperationLog

type OperationLog struct {
	ID           uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"` // 模板 ID,主键,自增
	UserName     string    `json:"username,omitempty"`
	Role         string    `json:"role,omitempty"`
	Cluster      string    `gorm:"index" json:"cluster,omitempty"`
	Namespace    string    `json:"namespace,omitempty"`
	Name         string    `json:"name,omitempty"`
	Group        string    `json:"group,omitempty"`                       // 资源group
	Kind         string    `json:"kind,omitempty"`                        // 资源kind
	Action       string    `json:"action,omitempty"`                      // 操作类型
	Params       string    `gorm:"type:text" json:"params,omitempty"`     // 操作参数
	ActionResult string    `json:"action_result,omitempty"`               // 操作结果
	CreatedAt    time.Time `json:"created_at,omitempty" gorm:"<-:create"` // Automatically managed by GORM for creation time
	UpdatedAt    time.Time `json:"updated_at,omitempty"`                  // Automatically managed by GORM for update time

}

OperationLog 用户导入OperationLog

func (*OperationLog) Delete

func (c *OperationLog) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*OperationLog) GetOne

func (c *OperationLog) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*OperationLog, error)

func (*OperationLog) List

func (c *OperationLog) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*OperationLog, int64, error)

func (*OperationLog) Save

func (c *OperationLog) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type Release added in v0.0.137

type Release struct {
	Name        string `json:"name"`
	Namespace   string `json:"namespace"`
	Revision    string `json:"revision"`
	Updated     string `json:"updated"`
	Status      string `json:"status"`
	Chart       string `json:"chart"`
	AppVersion  string `json:"app_version"`
	Description string `json:"description"`
}

type ReleaseHistory added in v0.0.137

type ReleaseHistory struct {
	Revision   int    `json:"revision"`
	Updated    string `json:"updated"`
	Status     string `json:"status"`
	Chart      string `json:"chart"`
	AppVersion string `json:"app_version"`
}

type SSOConfig added in v0.0.92

type SSOConfig struct {
	ID                 uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Name               string    `json:"name,omitempty"`                                    // 配置名称
	Type               string    `gorm:"default:oidc" json:"type,omitempty"`                // 配置类型
	ClientID           string    `gorm:"type:text;" json:"client_id,omitempty"`             // OAuth2客户端ID
	ClientSecret       string    `gorm:"type:text;" json:"client_secret,omitempty"`         // OAuth2客户端密钥
	Issuer             string    `gorm:"type:text;" json:"issuer,omitempty"`                // 认证服务器地址
	Enabled            bool      `gorm:"default:false" json:"enabled,omitempty"`            // 是否启用SSO
	PreferUserNameKeys string    `gorm:"type:text;" json:"prefer_user_name_keys,omitempty"` // 用户自定义获取用户名的字段顺序,适用于如果用户名字段不在默认字段中情况
	Scopes             string    `gorm:"type:text;" json:"scopes,omitempty"`                // 授权范围
	CreatedAt          time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt          time.Time `json:"updated_at,omitempty"` // 更新时间
}

SSOConfig SSO配置表

func (*SSOConfig) Delete added in v0.0.92

func (s *SSOConfig) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete 删除记录

func (*SSOConfig) GetOne added in v0.0.92

func (s *SSOConfig) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*SSOConfig, error)

GetOne 获取单条记录

func (*SSOConfig) List added in v0.0.92

func (s *SSOConfig) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*SSOConfig, int64, error)

List 列出所有记录

func (*SSOConfig) Save added in v0.0.92

func (s *SSOConfig) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Save 保存记录

type ShellLog

type ShellLog struct {
	ID            uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"` // 模板 ID,主键,自增
	UserName      string    `json:"username,omitempty"`
	Cluster       string    `json:"cluster,omitempty"`
	Namespace     string    `json:"namespace,omitempty"`
	PodName       string    `json:"pod_name,omitempty"`
	ContainerName string    `json:"container_name,omitempty"`
	Command       string    `json:"command,omitempty"` // shell 执行命令
	Role          string    `json:"role,omitempty"`
	CreatedAt     time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt     time.Time `json:"updated_at,omitempty"` // Automatically managed by GORM for update time
}

ShellLog 用户导入ShellLog

func (*ShellLog) Delete

func (c *ShellLog) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*ShellLog) GetOne

func (c *ShellLog) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*ShellLog, error)

func (*ShellLog) List

func (c *ShellLog) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*ShellLog, int64, error)

func (*ShellLog) Save

func (c *ShellLog) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type User

type User struct {
	ID               uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Username         string    `gorm:"type:varchar(255);uniqueIndex;not null" json:"username,omitempty"`
	Salt             string    `gorm:"not null" json:"salt,omitempty"`
	Password         string    `gorm:"not null" json:"password,omitempty"`
	GroupNames       string    `json:"group_names,omitempty"`
	Source           string    `json:"source,omitempty"` // 来源,如:db, ldap_config.json, oauth
	CreatedAt        time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt        time.Time `json:"updated_at,omitempty"`                          // Automatically managed by GORM for update time
	TwoFAEnabled     bool      `gorm:"default:false" json:"two_fa_enabled,omitempty"` // 是否启用2FA
	TwoFAType        string    `gorm:"size:20" json:"two_fa_type,omitempty"`          // 2FA类型:如 'totp', 'sms', 'email'
	TwoFASecret      string    `gorm:"size:100" json:"two_fa_secret,omitempty"`       // 2FA密钥
	TwoFABackupCodes string    `gorm:"size:500" json:"two_fa_backup_codes,omitempty"` // 备用恢复码,逗号分隔
	TwoFAAppName     string    `gorm:"size:100" json:"two_fa_app_name,omitempty"`     // 2FA应用名称,用于提醒用户使用的是哪个软件
	Disabled         bool      `gorm:"default:false" json:"disabled,omitempty"`       // 是否启用
}

User 用户导入User

func (*User) Delete

func (c *User) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*User) GetOne

func (c *User) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*User, error)

func (*User) IsDisabled added in v0.0.132

func (c *User) IsDisabled(username string) (bool, error)

func (*User) List

func (c *User) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*User, int64, error)

func (*User) Save

func (c *User) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*User) UpdateColumn added in v0.0.139

func (c *User) UpdateColumn(columnName string, value any) error

type UserGroup added in v0.0.55

type UserGroup struct {
	ID          uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	GroupName   string    `gorm:"index" json:"group_name,omitempty"`
	Description string    `json:"description,omitempty"`
	Role        string    `gorm:"index" json:"role,omitempty"` // 管理员/只读
	MenuData    string    `gorm:"type:text" json:"menu_data"`
	CreatedAt   time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt   time.Time `json:"updated_at,omitempty"`
}

func (*UserGroup) Delete added in v0.0.55

func (c *UserGroup) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*UserGroup) GetOne added in v0.0.55

func (c *UserGroup) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*UserGroup, error)

func (*UserGroup) List added in v0.0.55

func (c *UserGroup) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*UserGroup, int64, error)

func (*UserGroup) Save added in v0.0.55

func (c *UserGroup) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

type WebhookLogRecord added in v0.0.173

type WebhookLogRecord struct {
	ID           uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	WebhookID    uint      `json:"webhook_id,omitempty" gorm:"index"`     // webhook接收器ID
	WebhookName  string    `json:"webhook_name,omitempty"`                // webhook名称
	ReceiverID   string    `json:"receiver_id,omitempty"`                 // 接收器ID
	Method       string    `json:"method,omitempty"`                      // HTTP方法
	URL          string    `json:"url,omitempty"`                         // 请求URL
	StatusCode   int       `json:"status_code,omitempty"`                 // 响应状态码
	Success      bool      `json:"success,omitempty" gorm:"index"`        // 是否成功
	Duration     int64     `json:"duration,omitempty"`                    // 请求耗时(纳秒)
	ErrorMessage string    `json:"error_message,omitempty"`               // 错误信息
	Summary      string    `json:"summary,omitempty"`                     // 日志摘要
	Detail       string    `gorm:"type:text" json:"detail,omitempty"`     // 完整日志详情(JSON格式)
	RequestTime  time.Time `json:"request_time,omitempty" gorm:"index"`   // 请求时间
	CreatedAt    time.Time `json:"created_at,omitempty" gorm:"<-:create"` // 创建时间
	UpdatedAt    time.Time `json:"updated_at,omitempty"`                  // 更新时间
}

WebhookLogRecord webhook发送日志记录

func (*WebhookLogRecord) Delete added in v0.0.173

func (w *WebhookLogRecord) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Delete 删除webhook日志

func (*WebhookLogRecord) GetOne added in v0.0.173

func (w *WebhookLogRecord) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*WebhookLogRecord, error)

GetOne 获取单个webhook日志

func (*WebhookLogRecord) GetStatistics added in v0.0.173

func (w *WebhookLogRecord) GetStatistics(webhookID uint, startTime, endTime time.Time) (map[string]interface{}, error)

GetStatistics 获取webhook发送统计信息

func (*WebhookLogRecord) List added in v0.0.173

func (w *WebhookLogRecord) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*WebhookLogRecord, int64, error)

List 查询webhook日志列表

func (*WebhookLogRecord) ListBySuccess added in v0.0.173

func (w *WebhookLogRecord) ListBySuccess(success bool, params *dao.Params) ([]*WebhookLogRecord, int64, error)

ListBySuccess 根据成功状态查询日志

func (*WebhookLogRecord) ListByTimeRange added in v0.0.173

func (w *WebhookLogRecord) ListByTimeRange(startTime, endTime time.Time, params *dao.Params) ([]*WebhookLogRecord, int64, error)

ListByTimeRange 根据时间范围查询日志

func (*WebhookLogRecord) ListByWebhookID added in v0.0.173

func (w *WebhookLogRecord) ListByWebhookID(webhookID uint, params *dao.Params) ([]*WebhookLogRecord, int64, error)

ListByWebhookID 根据webhook ID查询日志

func (*WebhookLogRecord) Save added in v0.0.173

func (w *WebhookLogRecord) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Save 保存webhook日志

type WebhookReceiver added in v0.0.130

type WebhookReceiver struct {
	ID           uint      `gorm:"primaryKey;autoIncrement" json:"id,omitempty"`
	Name         string    `json:"name,omitempty"`     // webhook名称
	Platform     string    `json:"platform,omitempty"` // feishu,dingtalk
	TargetURL    string    `json:"target_url,omitempty"`
	BodyTemplate string    `gorm:"type:text" json:"body_template,omitempty"` // 发送到webhook的body模板
	SignSecret   string    `json:"sign_secret,omitempty"`
	CreatedAt    time.Time `json:"created_at,omitempty" gorm:"<-:create"`
	UpdatedAt    time.Time `json:"updated_at,omitempty"` // Automatically managed by GORM for update time
}

func (*WebhookReceiver) Delete added in v0.0.130

func (c *WebhookReceiver) Delete(params *dao.Params, ids string, queryFuncs ...func(*gorm.DB) *gorm.DB) error

func (*WebhookReceiver) GetNamesByIds added in v0.0.132

func (c *WebhookReceiver) GetNamesByIds(ids string) ([]string, error)

func (*WebhookReceiver) GetOne added in v0.0.130

func (c *WebhookReceiver) GetOne(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) (*WebhookReceiver, error)

func (*WebhookReceiver) List added in v0.0.130

func (c *WebhookReceiver) List(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) ([]*WebhookReceiver, int64, error)

func (*WebhookReceiver) ListByRecordID added in v0.0.132

func (c *WebhookReceiver) ListByRecordID(recordID uint) ([]*WebhookReceiver, error)

func (*WebhookReceiver) Save added in v0.0.130

func (c *WebhookReceiver) Save(params *dao.Params, queryFuncs ...func(*gorm.DB) *gorm.DB) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL