package service import ( "errors" "fmt" "github.com/google/uuid" "github.com/spf13/cast" "github.com/tealeg/xlsx" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/entity" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/request" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/response" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/client" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/tools" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/resp" "os/exec" "strings" "time" ) type HostManageSvc struct { User *entity.SystemUser } const AnsibleGroup string = "HostGroup" const AnsibleIp string = "HostIp" // AddHostManage 新增主机 func (h *HostManageSvc) AddHostManage(req request.AddHostManageReq) (err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } // 开启事务 session := db.NewSession() defer session.Close() session.Begin() // 校验 主机分组名称 是否重复 has, err := session.Table("host_manage").Where("is_delete = 0 AND host_name = ?", req.HostName).Exist() if has { err = resp.DbDataCheckError.WithError(errors.New("主机名称重复")) session.Rollback() return } if err != nil { err = resp.DbSelectError.WithError(err) session.Rollback() return } //新增主机分组 hostManage := entity.HostManage{ HostName: req.HostName, CreateUser: "", CreateTime: time.Now(), UpdateUser: "", UpdateTime: time.Now(), } _, err = session.Table("host_manage").Insert(&hostManage) if err != nil { err = resp.DbInsertError.WithError(err) session.Rollback() return } //查询临时表中的ip列表 hostManageLists := make([]request.HostManageList, 0) finder1 := session.Table("host_manage_list_cache").Where("conn_status = 0 AND id = ?", req.Uuid) //查询 err = finder1.OrderBy("ip_group").Find(&hostManageLists) if err != nil { err = resp.DbSelectError.WithError(err) session.Rollback() return } //删除临时表数据 _, err = session.Table("host_manage_list_cache").Where("id = ?", req.Uuid).Delete() if err != nil { err = resp.DbDeleteError.WithError(err) session.Rollback() return } //读取hosts中的主机组 hosts, err := tools.HostsToJson() if err != nil { err = resp.MarshalError.WithError(err) session.Rollback() return } hosts["["+AnsibleGroup+fmt.Sprintf("%d", hostManage.Id)+"]"] = nil //新增主机分组列表 for _, v := range hostManageLists { port := "22" if v.Port != "" { port = v.Port } hostManageList := entity.HostManageList{ Ip: v.Ip, Port: port, VoucherType: v.VoucherType, UserName: v.UserName, Password: v.Password, HostGroupId: hostManage.Id, HostFileUrl: req.HostFileUrl, IpGroup: v.IpGroup, } _, err = session.Table("host_manage_list").Insert(&hostManageList) if err != nil { err = resp.DbInsertError.WithError(err) session.Rollback() return } hostsIp := "" if v.VoucherType == 0 { hostsIp = fmt.Sprintf("%s ansible_ssh_host=%s ansible_ssh_port=%s ansible_ssh_user=\"%s\" ansible_ssh_pass=\"%s\" ansible_host_key_checking=false", AnsibleIp+fmt.Sprintf("%d", hostManageList.Id), v.Ip, v.Port, v.UserName, v.Password) } else { hostsIp = fmt.Sprintf("%s ansible_ssh_host=%s ansible_ssh_port=%s ansible_ssh_user=\"%s\" ansible_ssh_private_key_file=/root/.ssh/id_rsa ansible_host_key_checking=false", AnsibleIp+fmt.Sprintf("%d", hostManageList.Id), v.Ip, v.Port, v.UserName) } hosts["["+AnsibleGroup+fmt.Sprintf("%d", hostManage.Id)+"]"] = append(hosts["["+AnsibleGroup+fmt.Sprintf("%d", hostManage.Id)+"]"], hostsIp) } //写入hosts err = tools.MapToSaveHosts(hosts) if err != nil { err = resp.MarshalError.WithError(err) session.Rollback() return } session.Commit() return } // EditHostManage 编辑 func (h *HostManageSvc) EditHostManage(req request.EditHostManageReq) (err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } // 开启事务 session := db.NewSession() defer session.Close() session.Begin() //修改主机分组信息 hostManage := entity.HostManage{ UpdateUser: "", UpdateTime: time.Now(), } _, err = session.Table("host_manage").Where("is_delete = 0 AND id = ?", req.Id). Cols("update_user,update_time").Update(&hostManage) if err != nil { err = resp.DbUpdateError.WithError(err) session.Rollback() return } //正常ip列表 hostManageLists := make([]request.HostManageList, 0) finder1 := session.Table("host_manage_list_cache").Where("conn_status = 0 AND id = ?", req.Uuid) //查询 err = finder1.OrderBy("ip_group").Find(&hostManageLists) if err != nil { err = resp.DbSelectError.WithError(err) session.Rollback() return } //删除临时数据 _, err = session.Table("host_manage_list_cache").Where("id = ?", req.Uuid).Delete() if err != nil { err = resp.DbDeleteError.WithError(err) session.Rollback() return } //删除主机列表数据 _, err = session.Table("host_manage_list").Where("host_group_id = ?", req.Id).Cols("is_delete").Update(&entity.TaskManage{ IsDelete: 1, }) if err != nil { err = resp.DbDeleteError.WithError(err) session.Rollback() return } //读取hosts中的主机组 hosts, err := tools.HostsToJson() if err != nil { err = resp.MarshalError.WithError(err) return } hosts["["+AnsibleGroup+fmt.Sprintf("%d", req.Id)+"]"] = nil //新增主机分组列表 for _, v := range hostManageLists { port := "22" if v.Port != "" { port = v.Port } hostManageList := entity.HostManageList{ Ip: v.Ip, Port: port, VoucherType: v.VoucherType, UserName: v.UserName, Password: v.Password, HostGroupId: hostManage.Id, HostFileUrl: req.HostFileUrl, IpGroup: v.IpGroup, } _, err = session.Table("host_manage_list").Insert(&hostManageList) if err != nil { err = resp.DbInsertError.WithError(err) session.Rollback() return } hostsIp := "" if v.VoucherType == 0 { hostsIp = fmt.Sprintf("%s ansible_ssh_host=%s ansible_ssh_port=%s ansible_ssh_user=\"%s\" ansible_ssh_pass=\"%s\" ansible_host_key_checking=false", AnsibleIp+fmt.Sprintf("%d", hostManageList.Id), v.Ip, v.Port, v.UserName, v.Password) } else { hostsIp = fmt.Sprintf("%s ansible_ssh_host=%s ansible_ssh_port=%s ansible_ssh_user=\"%s\" ansible_ssh_private_key_file=/root/.ssh/id_rsa ansible_host_key_checking=false", AnsibleIp+fmt.Sprintf("%d", hostManageList.Id), v.Ip, v.Port, v.UserName) } hosts["["+AnsibleGroup+fmt.Sprintf("%d", req.Id)+"]"] = append(hosts["["+AnsibleGroup+fmt.Sprintf("%d", req.Id)+"]"], hostsIp) } //写入hosts err = tools.MapToSaveHosts(hosts) if err != nil { err = resp.MarshalError.WithError(err) return } session.Commit() return } // DelHostManage 删除任务 func (h *HostManageSvc) DelHostManage(req request.DelHostManageReq) (err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } // 开启事务 session := db.NewSession() defer session.Close() session.Begin() //检测是否可删除 var taskCnt int _, err = session.Table("task_manage").In("host_group_id", req.Id). Where("is_delete = 0").Select("count(*) AS task_cnt").Get(&taskCnt) if taskCnt > 0 { err = resp.DbDeleteError.WithError(errors.New("此主机分组下有关联任务,不可删除")) session.Rollback() return } if err != nil { err = resp.DbSelectError.WithError(err) session.Rollback() return } //删除主机分组 _, err = session.Table("host_manage").In("id", req.Id).Cols("is_delete").Update(&entity.HostManageList{ IsDelete: 1, }) if err != nil { err = resp.DbDeleteError.WithError(err) session.Rollback() return } //删除主机分组列表 _, err = session.Table("host_manage_list").In("host_group_id", req.Id).Cols("is_delete").Update(&entity.HostManageList{ IsDelete: 1, }) if err != nil { err = resp.DbDeleteError.WithError(err) session.Rollback() return } session.Commit() return } // DetailsHostManage 详情 func (h *HostManageSvc) DetailsHostManage(id int) (hostManageRes response.HostManageRes, err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } var hostManage response.HostManage hostList := make([]response.HostList, 0) taskList := make([]response.TaskList, 0) //查询主机分组 _, err = db.Table("host_manage").Where("is_delete = 0 AND id = ?", id).Get(&hostManage) if err != nil { err = resp.DbSelectError.WithError(err) return } //查询主机列表 err = db.Table("host_manage_list").Where("is_delete = 0 AND host_group_id = ?", id). Select("string_agg(ip,',') as ip,port,voucher_type,user_name,password,host_file_url,count(1) as cnt"). GroupBy("ip_group,port,voucher_type,user_name,PASSWORD,host_file_url").Find(&hostList) if err != nil { err = resp.DbSelectError.WithError(err) return } //查询任务列表 err = db.Table("task_manage").Where("is_delete = 0 AND host_group_id = ?", id).Find(&taskList) if err != nil { err = resp.DbSelectError.WithError(err) return } for _, v := range hostList { if v.HostFileUrl != "" { hostManageRes.HostFileUrl = v.HostFileUrl } hostManageRes.IpCnt = hostManageRes.IpCnt + v.Cnt } hostManageRes.Id = hostManage.Id hostManageRes.HostName = hostManage.HostName hostManageRes.TaskCnt = len(taskList) //hostManageRes.IpCnt = len(hostList) hostManageRes.CreateUser = hostManage.CreateUser hostManageRes.CreateTime = hostManage.CreateTime hostManageRes.UpdateUser = hostManage.UpdateUser hostManageRes.UpdateTime = hostManage.UpdateTime if hostManageRes.HostFileUrl == "" { hostManageRes.HostList = hostList } hostManageRes.TaskList = taskList return } // PageListHostManage 列表-分页 func (h *HostManageSvc) PageListHostManage(req request.ListHostManageReq) (total int64, hostManageListRes []response.HostManagesRes, err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } finder := db.Table("host_manage").Alias("hm").Where("hm.is_delete = 0") if req.Search != "" { finder.Where("hm.host_name LIKE ?", "%"+req.Search+"%") } if req.CreateDateFrom != "" { finder.Where("hm.create_time >= ?", req.CreateDateFrom) } if req.CreateDateTo != "" { finder.Where("hm.create_time <= ?", req.CreateDateTo) } finder.OrderBy("hm.id") //查询任务 total, err = finder.Select("hm.id,hm.host_name,hm.create_user,hm.create_time,(SELECT COUNT(*) FROM "+ "task_manage tm WHERE tm.is_delete = 0 AND tm.host_group_id = hm.ID) AS task_cnt,(SELECT COUNT(*) FROM "+ "host_manage_list hml WHERE hml.is_delete = 0 AND hml.conn_status = 1 AND hml.host_group_id = hm.ID) AS "+ "ip_cnt_err,(SELECT COUNT(*) FROM host_manage_list hml WHERE hml.is_delete = 0 AND hml.host_group_id = hm.ID) AS ip_cnt"). Limit(req.PageSize, (req.Page-1)*req.PageSize).FindAndCount(&hostManageListRes) if err != nil { err = resp.DbSelectError.WithError(err) return } return } // ListStateHostManage 列表状态检测 func (h *HostManageSvc) ListStateHostManage(req request.StateHostManageReq) (err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } // 开启事务 session := db.NewSession() defer session.Close() session.Begin() //查询主机IP列表 hostManageList := make([]response.HostManageListRes, 0) finder := session.Table("host_manage_list").Where("is_delete = 0 AND host_group_id = ?", req.Id) err = finder.Find(&hostManageList) if err != nil { err = resp.DbSelectError.WithError(err) return } //读取hosts中的主机组 hosts, err := tools.HostsToJson() if err != nil { err = resp.MarshalError.WithError(err) session.Rollback() return } if _, ok := hosts["["+AnsibleGroup+fmt.Sprintf("%d", req.Id)+"]"]; !ok { // 不存在 hosts["["+AnsibleGroup+fmt.Sprintf("%d", req.Id)+"]"] = nil } //新增主机分组列表 for _, v := range hostManageList { hostsIp := "" if v.VoucherType == 0 { hostsIp = fmt.Sprintf("%s ansible_ssh_host=%s ansible_ssh_port=%s ansible_ssh_user=\"%s\" ansible_ssh_pass=\"%s\" ansible_host_key_checking=false", AnsibleIp+fmt.Sprintf("%d", v.Id), v.Ip, v.Port, v.UserName, v.Password) } else { hostsIp = fmt.Sprintf("%s ansible_ssh_host=%s ansible_ssh_port=%s ansible_ssh_user=\"%s\" ansible_ssh_private_key_file=/root/.ssh/id_rsa ansible_host_key_checking=false", AnsibleIp+fmt.Sprintf("%d", v.Id), v.Ip, v.Port, v.UserName) } flag := 0 for _, v1 := range hosts["["+AnsibleGroup+fmt.Sprintf("%d", req.Id)+"]"] { if v1 == hostsIp { flag = 1 } } if flag == 0 { hosts["["+AnsibleGroup+fmt.Sprintf("%d", req.Id)+"]"] = append(hosts["["+AnsibleGroup+fmt.Sprintf("%d", req.Id)+"]"], hostsIp) } } //写入hosts err = tools.MapToSaveHosts(hosts) if err != nil { err = resp.MarshalError.WithError(err) session.Rollback() return } for _, v := range hostManageList { //修改状态 _, err = session.Table("host_manage_list").Where("is_delete = 0 AND id = ?", v.Id). Cols("conn_status").Update(&entity.HostManageList{ ConnStatus: StatusDetection(v.Ip), }) if err != nil { err = resp.DbUpdateError.WithError(err) session.Rollback() return } } session.Commit() return } // SaveStateHostManage 保存时状态检测 func (h *HostManageSvc) SaveStateHostManage(hostManageList []request.HostManageList) (id string, err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } //处理ip列表 ipGroup := 1 hostManageListCaches := make([]entity.HostManageListCache, 0) for _, v := range hostManageList { port := "22" if v.Port != "" { port = v.Port } ipList := strings.Split(v.Ip, ",") for _, v1 := range ipList { HostManageListCache := entity.HostManageListCache{ Ip: v1, Port: port, VoucherType: v.VoucherType, UserName: v.UserName, Password: v.Password, IpGroup: ipGroup, } hostManageListCaches = append(hostManageListCaches, HostManageListCache) } ipGroup += 1 } //读取hosts中的主机组 hosts, err := tools.HostsToJson() if err != nil { err = resp.MarshalError.WithError(err) return } if _, ok := hosts["["+AnsibleGroup+"]"]; !ok { // 不存在 hosts["["+AnsibleGroup+"]"] = nil } for _, v := range hostManageListCaches { hostsIp := "" if v.VoucherType == 0 { hostsIp = fmt.Sprintf("%s ansible_ssh_host=%s ansible_ssh_port=%s ansible_ssh_user=\"%s\" ansible_ssh_pass=\"%s\" ansible_host_key_checking=false", AnsibleIp+v.Ip, v.Ip, v.Port, v.UserName, v.Password) } else { hostsIp = fmt.Sprintf("%s ansible_ssh_host=%s ansible_ssh_port=%s ansible_ssh_user=\"%s\" ansible_ssh_private_key_file=/root/.ssh/id_rsa ansible_host_key_checking=false", AnsibleIp+v.Ip, v.Ip, v.Port, v.UserName) } flag := 0 for _, v1 := range hosts["["+AnsibleGroup+"]"] { if v1 == hostsIp { flag = 1 } } if flag == 0 { hosts["["+AnsibleGroup+"]"] = append(hosts["["+AnsibleGroup+"]"], hostsIp) } } //写入hosts err = tools.MapToSaveHosts(hosts) if err != nil { err = resp.MarshalError.WithError(err) return } //状态检测 id = uuid.New().String() for k, v := range hostManageListCaches { //调用状态检测函数 hostManageListCaches[k].ConnStatus = StatusDetection(v.Ip) hostManageListCaches[k].Id = id } //存入数据库 _, err = db.Table("host_manage_list_cache").Insert(&hostManageListCaches) if err != nil { err = resp.DbInsertError.WithError(err) return } return } // HostIpExceptionList 列表点击状态检测后展示-异常列表 func (h *HostManageSvc) HostIpExceptionList(req request.HostIpExceptionListReq) (total int64, hostManageListRes []response.HostManageListRes, err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } finder := db.Table("host_manage_list").Where("conn_status = 1 AND is_delete = 0 AND host_group_id = ?", req.Id) //查询 total, err = finder.Select("id,ip,port,voucher_type,user_name,password").OrderBy("id"). Limit(req.PageSize, (req.Page-1)*req.PageSize).FindAndCount(&hostManageListRes) if err != nil { err = resp.DbSelectError.WithError(err) return } return } // SaveIpExceptionList 保存时状态检测后展示-异常列表 func (h *HostManageSvc) SaveIpExceptionList(req request.HostIpExceptionListReq) (total int64, hostManageListCacheRes []response.HostManageListCache, err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } //异常ip列表-分页 finder := db.Table("host_manage_list_cache").Where("conn_status = 1 AND id = ?", req.Uuid) //查询 total, err = finder.OrderBy("ip_group").Limit(req.PageSize, (req.Page-1)*req.PageSize).FindAndCount(&hostManageListCacheRes) if err != nil { err = resp.DbSelectError.WithError(err) return } ////正常ip列表 //finder1 := db.Table("host_manage_list_cache").Where("conn_status = 0 AND id = ?", req.Uuid) ////查询 //err = finder1.OrderBy("ip_group").Find(&hostManageListCacheRes.AormalHost) //if err != nil { // err = resp.DbSelectError.WithError(err) // return //} // ////删除临时数据 //_, err = db.Table("host_manage_list_cache").Where("id = ?", req.Uuid).Delete() //if err != nil { // err = resp.DbDeleteError.WithError(err) // return //} return } // StatusDetection 状态检测 func StatusDetection(ip string) (ipConn int) { var cmd *exec.Cmd cmd = exec.Command("ansible", fmt.Sprintf("%s", AnsibleIp+ip), "-m", "ping") output, err := cmd.Output() if err != nil { fmt.Println("ping:", string(output)) return 1 } fmt.Println("ping:", string(output)) return 0 } // ExportIpStr 结果导出 type ExportIpStr struct { Ip string `json:"ip" index:"0"` // ip Port string `json:"port" index:"1"` // 端口 VoucherType string `json:"voucher_type" index:"2"` // 凭证类型 UserName string `json:"user_name" index:"3"` // 用户名 Password string `json:"password" index:"4"` // 密码 ConnStatus string `json:"conn_status" index:"5" ` // 连接状态 } // ExportIp 结果导出 func (h *HostManageSvc) ExportIp(id, uuid string, detectionType int) (fileName string, err error) { var ( push = make([]ExportIpStr, 0) hostManageList = make([]entity.HostManageList, 0) ) db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } if detectionType == 1 { //列表检测导出 finder := db.Table("host_manage_list").Where("is_delete = 0 AND conn_status = 1 AND host_group_id = ?", cast.ToInt(id)) err = finder.Select("ip,port,voucher_type,user_name,password").Find(&hostManageList) if err != nil { err = resp.DbSelectError.WithError(err) return } } else { //新增/编辑检测导出 finder := db.Table("host_manage_list_cache").Where("conn_status = 1 AND id = ?", uuid) err = finder.Select("ip,port,voucher_type,user_name,password").Find(&hostManageList) if err != nil { err = resp.DbSelectError.WithError(err) return } } for _, v := range hostManageList { voucherType := "" switch v.VoucherType { case 0: voucherType = "密码验证" case 1: voucherType = "密钥验证" } connStatus := "" switch v.ConnStatus { case 0: connStatus = "正常" case 1: connStatus = "异常" } staff := ExportIpStr{ Ip: v.Ip, Port: v.Port, VoucherType: voucherType, UserName: v.UserName, Password: v.Password, ConnStatus: connStatus, } push = append(push, staff) } saveFileName, err := generatePushExportXlsx(push) if err != nil { err = resp.FileExecError.WithError(err) return } return saveFileName, nil } func generatePushExportXlsx(push []ExportIpStr) (string, error) { file := xlsx.NewFile() sheet, _ := file.AddSheet("Sheet1") titles := []string{"IP", "端口", "凭证类型", "用户名", "密码", "状态"} row := sheet.AddRow() var cell *xlsx.Cell for _, title := range titles { cell = row.AddCell() cell.Value = title } for _, v := range push { row = sheet.AddRow() row.WriteStruct(&v, -1) } saveFileName := "IP列表导出数据.xlsx" err := file.Save("/app/xlsx/" + saveFileName) return saveFileName, err } // ListHostManage 列表 func (h *HostManageSvc) ListHostManage() (hostManagesListRes []response.HostManagesListRes, err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.WithError(err) return } finder := db.Table("host_manage").Where("is_delete = 0") finder.OrderBy("id") //查询任务 err = finder.Select("id,host_name").Find(&hostManagesListRes) if err != nil { err = resp.DbSelectError.WithError(err) return } return } // CronStatusDetection 定时任务-状态检测 func CronStatusDetection() { db, err := client.GetDbClient() if err != nil { fmt.Println("CronStatusDetection err:", err.Error()) return } //查询主机IP列表 hostManageList := make([]response.HostManageListRes, 0) finder := db.Table("host_manage_list").Where("is_delete = 0") err = finder.Find(&hostManageList) if err != nil { fmt.Println("CronStatusDetection err:", err.Error()) return } //往hosts文件中写入主机组ip //f, err := os.OpenFile("/etc/ansible/hosts", os.O_APPEND|os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777) //if err != nil { // fmt.Println("CronStatusDetection err:", err.Error()) // return //} //defer f.Close() //_, err = f.Write([]byte(fmt.Sprintf("%s%d\n", AnsibleGroup, req.Id))) //if err != nil { // fmt.Println("CronStatusDetection err:", err.Error()) // return //} //for _, v := range hostManageList { // _, err = f.Write([]byte(fmt.Sprintf("%s ansible_ssh_host=%s ansible_ssh_port=%s ansible_ssh_user=\"%s\" ansible_ssh_pass=\"%s\"\n", v.Ip, v.Ip, v.Port, v.UserName, v.Password))) // if err != nil { // fmt.Println("CronStatusDetection err:", err.Error()) // return // } //} for _, v := range hostManageList { //修改状态 _, err = db.Table("host_manage_list").Where("is_delete = 0 AND id = ?", v.Id). Cols("conn_status").Update(&entity.HostManageList{ ConnStatus: StatusDetection(v.Ip), }) if err != nil { fmt.Println("CronStatusDetection err:", err.Error()) return } } fmt.Println("CronPersonalCardDate success!") }