package handlers import ( "encoding/json" "net/http" "time" "ezops/internal/models" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // AnsibleHandler Ansible 自动化处理器 // Logan.Li type AnsibleHandler struct { db *gorm.DB } func NewAnsibleHandler(db *gorm.DB) *AnsibleHandler { return &AnsibleHandler{db: db} } // ==================== Playbook ==================== func (h *AnsibleHandler) ListPlaybooks(c *gin.Context) { var query models.PageQuery c.ShouldBindQuery(&query) db := h.db.Model(&models.AnsiblePlaybook{}) if name := c.Query("name"); name != "" { db = db.Where("name LIKE ?", "%"+name+"%") } if cat := c.Query("category"); cat != "" { db = db.Where("category = ?", cat) } var total int64 db.Count(&total) var items []models.AnsiblePlaybook db.Order("updated_at DESC").Offset(query.GetOffset()).Limit(query.GetLimit()).Find(&items) c.JSON(http.StatusOK, models.Response{Code: 200, Data: models.ListResponse{List: items, Total: total}}) } func (h *AnsibleHandler) GetPlaybook(c *gin.Context) { var item models.AnsiblePlaybook if err := h.db.First(&item, c.Param("id")); err.Error != nil { c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "Playbook 不存在"}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Data: item}) } func (h *AnsibleHandler) CreatePlaybook(c *gin.Context) { var req struct { Name string `json:"name" binding:"required"` Description string `json:"description"` Content string `json:"content" binding:"required"` Tags string `json:"tags"` Category string `json:"category"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: err.Error()}) return } username := c.GetString("username") item := models.AnsiblePlaybook{ Name: req.Name, Description: req.Description, Content: req.Content, Tags: req.Tags, Category: req.Category, CreatedBy: username, } if err := h.db.Create(&item); err.Error != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "创建失败"}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Data: item}) } func (h *AnsibleHandler) UpdatePlaybook(c *gin.Context) { id := c.Param("id") var item models.AnsiblePlaybook if err := h.db.First(&item, id); err.Error != nil { c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "不存在"}) return } var req struct { Name *string `json:"name"` Description *string `json:"description"` Content *string `json:"content"` Tags *string `json:"tags"` Category *string `json:"category"` } c.ShouldBindJSON(&req) updates := map[string]interface{}{} if req.Name != nil { updates["name"] = *req.Name } if req.Description != nil { updates["description"] = *req.Description } if req.Content != nil { updates["content"] = *req.Content } if req.Tags != nil { updates["tags"] = *req.Tags } if req.Category != nil { updates["category"] = *req.Category } h.db.Model(&item).Updates(updates) h.db.First(&item, id) c.JSON(http.StatusOK, models.Response{Code: 200, Data: item}) } func (h *AnsibleHandler) DeletePlaybook(c *gin.Context) { id := c.Param("id") if err := h.db.Delete(&models.AnsiblePlaybook{}, id); err.Error != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "删除失败"}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Message: "已删除"}) } // ==================== Job ==================== func (h *AnsibleHandler) ListJobs(c *gin.Context) { var query models.PageQuery c.ShouldBindQuery(&query) db := h.db.Model(&models.AnsibleJob{}) if status := c.Query("status"); status != "" { db = db.Where("status = ?", status) } if pbID := c.Query("playbook_id"); pbID != "" { db = db.Where("playbook_id = ?", pbID) } var total int64 db.Count(&total) var items []models.AnsibleJob db.Order("created_at DESC").Offset(query.GetOffset()).Limit(query.GetLimit()).Find(&items) c.JSON(http.StatusOK, models.Response{Code: 200, Data: models.ListResponse{List: items, Total: total}}) } func (h *AnsibleHandler) GetJob(c *gin.Context) { var item models.AnsibleJob if err := h.db.First(&item, c.Param("id")); err.Error != nil { c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "不存在"}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Data: item}) } // ExecutePlaybook 执行 Playbook(模拟执行) // Logan.Li func (h *AnsibleHandler) ExecutePlaybook(c *gin.Context) { pbID := c.Param("id") var playbook models.AnsiblePlaybook if err := h.db.First(&playbook, pbID); err.Error != nil { c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "Playbook 不存在"}) return } var req struct { TargetHosts []string `json:"target_hosts"` Variables map[string]interface{} `json:"variables"` } c.ShouldBindJSON(&req) username := c.GetString("username") hostsJSON, _ := json.Marshal(req.TargetHosts) varsJSON, _ := json.Marshal(req.Variables) now := time.Now() job := models.AnsibleJob{ PlaybookID: playbook.ID, PlaybookName: playbook.Name, Status: "success", TargetHosts: string(hostsJSON), Variables: string(varsJSON), Output: "PLAY [" + playbook.Name + "] ***\n\nTASK [执行完成] ***\nok: " + func() string { if len(req.TargetHosts) > 0 { return req.TargetHosts[0] }; return "localhost" }() + "\n\nPLAY RECAP ***\nok=1 changed=0 unreachable=0 failed=0", Duration: 1500, TriggeredBy: username, StartedAt: &now, CompletedAt: &now, } if err := h.db.Create(&job); err.Error != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "创建执行记录失败"}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Data: job}) } // ==================== Inventory ==================== func (h *AnsibleHandler) ListInventories(c *gin.Context) { var items []models.AnsibleInventory h.db.Order("updated_at DESC").Find(&items) c.JSON(http.StatusOK, models.Response{Code: 200, Data: models.ListResponse{List: items, Total: int64(len(items))}}) } func (h *AnsibleHandler) CreateInventory(c *gin.Context) { var req struct { Name string `json:"name" binding:"required"` Description string `json:"description"` Hosts interface{} `json:"hosts"` // 数组 } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.Response{Code: 400, Message: err.Error()}) return } hostsJSON, _ := json.Marshal(req.Hosts) item := models.AnsibleInventory{ Name: req.Name, Description: req.Description, Hosts: string(hostsJSON), CreatedBy: c.GetString("username"), } h.db.Create(&item) c.JSON(http.StatusOK, models.Response{Code: 200, Data: item}) } func (h *AnsibleHandler) UpdateInventory(c *gin.Context) { id := c.Param("id") var item models.AnsibleInventory if err := h.db.First(&item, id); err.Error != nil { c.JSON(http.StatusNotFound, models.Response{Code: 404, Message: "不存在"}) return } var req struct { Name *string `json:"name"` Description *string `json:"description"` Hosts interface{} `json:"hosts"` } c.ShouldBindJSON(&req) updates := map[string]interface{}{} if req.Name != nil { updates["name"] = *req.Name } if req.Description != nil { updates["description"] = *req.Description } if req.Hosts != nil { hostsJSON, _ := json.Marshal(req.Hosts) updates["hosts"] = string(hostsJSON) } h.db.Model(&item).Updates(updates) h.db.First(&item, id) c.JSON(http.StatusOK, models.Response{Code: 200, Data: item}) } func (h *AnsibleHandler) DeleteInventory(c *gin.Context) { if err := h.db.Delete(&models.AnsibleInventory{}, c.Param("id")); err.Error != nil { c.JSON(http.StatusInternalServerError, models.Response{Code: 500, Message: "删除失败"}) return } c.JSON(http.StatusOK, models.Response{Code: 200, Message: "已删除"}) }