package handlers import ( "net/http" "time" "github.com/ansible-deploy/internal/models" "github.com/ansible-deploy/internal/services" "github.com/gin-gonic/gin" ) // AnsibleHandler API处理器 type AnsibleHandler struct { service *services.AnsibleService } // NewAnsibleHandler 创建处理器 func NewAnsibleHandler(svc *services.AnsibleService) *AnsibleHandler { return &AnsibleHandler{service: svc} } // ===== 主机管理 ===== func (h *AnsibleHandler) ListHosts(c *gin.Context) { hosts := h.service.ListHosts() c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": hosts}) } func (h *AnsibleHandler) AddHost(c *gin.Context) { var host models.Host if err := c.ShouldBindJSON(&host); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误: " + err.Error()}) return } if err := h.service.AddHost(host); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "主机添加成功"}) } func (h *AnsibleHandler) DeleteHost(c *gin.Context) { id := c.Param("id") if err := h.service.DeleteHost(id); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "主机删除成功"}) } func (h *AnsibleHandler) UpdateHost(c *gin.Context) { id := c.Param("id") var host models.Host if err := c.ShouldBindJSON(&host); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误"}) return } if err := h.service.UpdateHost(id, host); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "主机更新成功"}) } func (h *AnsibleHandler) TestConnection(c *gin.Context) { id := c.Param("id") result, err := h.service.TestConnection(id) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": result}) } // ===== 主机组管理 ===== func (h *AnsibleHandler) ListGroups(c *gin.Context) { groups := h.service.ListGroups() c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": groups}) } func (h *AnsibleHandler) CreateGroup(c *gin.Context) { var group models.HostGroup if err := c.ShouldBindJSON(&group); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误"}) return } if err := h.service.CreateGroup(group); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "组创建成功"}) } func (h *AnsibleHandler) DeleteGroup(c *gin.Context) { name := c.Param("name") if err := h.service.DeleteGroup(name); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "组删除成功"}) } func (h *AnsibleHandler) UpdateGroup(c *gin.Context) { name := c.Param("name") var group models.HostGroup if err := c.ShouldBindJSON(&group); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误"}) return } if err := h.service.UpdateGroup(name, group); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "组更新成功"}) } // ===== Playbook管理 ===== func (h *AnsibleHandler) ListPlaybooks(c *gin.Context) { playbooks := h.service.ListPlaybooks() c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": playbooks}) } func (h *AnsibleHandler) GetPlaybook(c *gin.Context) { name := c.Param("name") playbook, err := h.service.GetPlaybook(name) if err != nil { c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": playbook}) } func (h *AnsibleHandler) ExecutePlaybook(c *gin.Context) { var req models.PlaybookExecutionRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误: " + err.Error()}) return } task, err := h.service.ExecutePlaybook(req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "任务已启动", "taskId": task.ID}) } func (h *AnsibleHandler) CreatePlaybook(c *gin.Context) { var req struct { Name string `json:"name" binding:"required"` Content string `json:"content"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误: " + err.Error()}) return } if req.Content == "" { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "Playbook内容不能为空"}) return } if err := h.service.CreatePlaybook(req.Name, req.Content); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "Playbook创建成功"}) } func (h *AnsibleHandler) DeletePlaybook(c *gin.Context) { name := c.Param("name") if err := h.service.DeletePlaybook(name); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "Playbook删除成功"}) } func (h *AnsibleHandler) GetPlaybookContent(c *gin.Context) { name := c.Param("name") content, err := h.service.GetPlaybookContent(name) if err != nil { c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": content}) } func (h *AnsibleHandler) UpdatePlaybook(c *gin.Context) { name := c.Param("name") var req struct { Content string `json:"content" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误"}) return } if err := h.service.UpdatePlaybook(name, req.Content); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "Playbook更新成功"}) } // ===== Playbook模板 ===== func (h *AnsibleHandler) ListTemplates(c *gin.Context) { templates := services.GetPlaybookTemplates() category := c.Query("category") if category != "" { var filtered []services.PlaybookTemplate for _, t := range templates { if t.Category == category { filtered = append(filtered, t) } } templates = filtered } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": templates}) } func (h *AnsibleHandler) ListTemplateCategories(c *gin.Context) { cats := services.GetTemplateCategories() c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": cats}) } func (h *AnsibleHandler) GetTemplate(c *gin.Context) { id := c.Param("id") for _, t := range services.GetPlaybookTemplates() { if t.ID == id { c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": t}) return } } c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": "模板不存在"}) } func (h *AnsibleHandler) CreateFromTemplate(c *gin.Context) { var req struct { TemplateID string `json:"template_id" binding:"required"` PlaybookName string `json:"playbook_name" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误: " + err.Error()}) return } for _, t := range services.GetPlaybookTemplates() { if t.ID == req.TemplateID { if err := h.service.CreatePlaybook(req.PlaybookName, t.Content); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "Playbook创建成功"}) return } } c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": "模板不存在"}) } // ===== 命令执行 ===== func (h *AnsibleHandler) ExecuteCommand(c *gin.Context) { var req models.CommandRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误: " + err.Error()}) return } results, err := h.service.ExecuteCommand(req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": results}) } func (h *AnsibleHandler) BatchExecute(c *gin.Context) { var req models.CommandRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误"}) return } result := h.service.BatchExecute(req) c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "任务已启动", "data": result}) } // ===== 文件分发 ===== func (h *AnsibleHandler) DistributeFile(c *gin.Context) { var req models.FileDistributeRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误: " + err.Error()}) return } if req.Content == "" && req.SourceFile == "" { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "请提供文件内容或源文件路径"}) return } task, err := h.service.DistributeFile(req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "文件分发任务已启动", "taskId": task.ID}) } // ===== SSH密钥管理 ===== func (h *AnsibleHandler) ListSSHKeys(c *gin.Context) { keys := h.service.ListSSHKeys() c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": keys}) } func (h *AnsibleHandler) AddSSHKey(c *gin.Context) { var req models.SSHKeyCreateRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "参数错误: " + err.Error()}) return } if err := h.service.AddSSHKey(req.Name, req.PrivateKey); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "SSH密钥添加成功"}) } func (h *AnsibleHandler) DeleteSSHKey(c *gin.Context) { name := c.Param("name") if err := h.service.DeleteSSHKey(name); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "SSH密钥已删除"}) } // ===== 任务管理 ===== func (h *AnsibleHandler) ListTasks(c *gin.Context) { tasks := h.service.ListTasks() c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": tasks}) } func (h *AnsibleHandler) GetTask(c *gin.Context) { id := c.Param("id") task := h.service.GetTask(id) if task == nil { c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": "任务不存在"}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": task}) } func (h *AnsibleHandler) StreamTaskOutput(c *gin.Context) { id := c.Param("id") task := h.service.GetTask(id) if task == nil { c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": "任务不存在"}) return } c.Header("Content-Type", "text/event-stream") c.Header("Cache-Control", "no-cache") c.Header("Connection", "keep-alive") lastLen := 0 for { if c.Request.Context().Err() != nil { return } task := h.service.GetTask(id) if task == nil { return } output := task.Output if len(output) > lastLen { increment := output[lastLen:] lastLen = len(output) c.SSEvent("log", increment) c.Writer.Flush() } if task.Status != "running" { c.SSEvent("status", task.Status) c.SSEvent("error", task.Error) c.Writer.Flush() return } select { case <-time.After(500 * time.Millisecond): case <-c.Request.Context().Done(): return } } } func (h *AnsibleHandler) CancelTask(c *gin.Context) { id := c.Param("id") if err := h.service.CancelTask(id); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "任务已取消"}) } // ===== 系统信息 ===== func (h *AnsibleHandler) GetSystemInfo(c *gin.Context) { info := h.service.GetSystemInfo() c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "success", "data": info}) }