497 lines
15 KiB
Go
497 lines
15 KiB
Go
package v1
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/IceWhaleTech/CasaOS/model"
|
|
"github.com/IceWhaleTech/CasaOS/pkg/config"
|
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
|
|
"github.com/IceWhaleTech/CasaOS/pkg/utils/oasis_err"
|
|
"github.com/IceWhaleTech/CasaOS/service"
|
|
model2 "github.com/IceWhaleTech/CasaOS/service/model"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/shirou/gopsutil/v3/disk"
|
|
)
|
|
|
|
var diskMap = make(map[string]string)
|
|
|
|
// @Summary disk list
|
|
// @Produce application/json
|
|
// @Accept application/json
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/list [get]
|
|
func GetDiskList(c *gin.Context) {
|
|
list := service.MyService.Disk().LSBLK(false)
|
|
dbList := service.MyService.Disk().GetSerialAll()
|
|
part := make(map[string]int64, len(dbList))
|
|
for _, v := range dbList {
|
|
part[v.MountPoint] = v.CreatedAt
|
|
}
|
|
findSystem := 0
|
|
|
|
disks := []model.Drive{}
|
|
storage := []model.Storage{}
|
|
avail := []model.Drive{}
|
|
for i := 0; i < len(list); i++ {
|
|
disk := model.Drive{}
|
|
if list[i].Rota {
|
|
disk.DiskType = "HDD"
|
|
} else {
|
|
disk.DiskType = "SSD"
|
|
}
|
|
disk.Serial = list[i].Serial
|
|
disk.Name = list[i].Name
|
|
disk.Size = list[i].Size
|
|
disk.Path = list[i].Path
|
|
disk.Model = list[i].Model
|
|
|
|
if len(list[i].Children) > 0 && findSystem == 0 {
|
|
for j := 0; j < len(list[i].Children); j++ {
|
|
if len(list[i].Children[j].Children) > 0 {
|
|
for _, v := range list[i].Children[j].Children {
|
|
if v.MountPoint == "/" {
|
|
stor := model.Storage{}
|
|
stor.Name = "System"
|
|
stor.MountPoint = v.MountPoint
|
|
stor.Size = v.FSSize
|
|
stor.Avail = v.FSAvail
|
|
stor.Path = v.Path
|
|
stor.Type = v.FsType
|
|
stor.DriveName = "System"
|
|
disk.Model = "System"
|
|
if strings.Contains(v.SubSystems, "mmc") {
|
|
disk.DiskType = "MMC"
|
|
} else if strings.Contains(v.SubSystems, "usb") {
|
|
disk.DiskType = "USB"
|
|
}
|
|
disk.Health = "true"
|
|
|
|
disks = append(disks, disk)
|
|
storage = append(storage, stor)
|
|
findSystem = 1
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
if list[i].Children[j].MountPoint == "/" {
|
|
stor := model.Storage{}
|
|
stor.Name = "System"
|
|
stor.MountPoint = list[i].Children[j].MountPoint
|
|
stor.Size = list[i].Children[j].FSSize
|
|
stor.Avail = list[i].Children[j].FSAvail
|
|
stor.Path = list[i].Children[j].Path
|
|
stor.Type = list[i].Children[j].FsType
|
|
stor.DriveName = "System"
|
|
disk.Model = "System"
|
|
if strings.Contains(list[i].Children[j].SubSystems, "mmc") {
|
|
disk.DiskType = "MMC"
|
|
} else if strings.Contains(list[i].Children[j].SubSystems, "usb") {
|
|
disk.DiskType = "USB"
|
|
}
|
|
disk.Health = "true"
|
|
|
|
disks = append(disks, disk)
|
|
storage = append(storage, stor)
|
|
findSystem = 1
|
|
break
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
if findSystem == 1 {
|
|
findSystem += 1
|
|
continue
|
|
}
|
|
|
|
if list[i].Tran == "sata" || list[i].Tran == "nvme" || list[i].Tran == "spi" || list[i].Tran == "sas" {
|
|
temp := service.MyService.Disk().SmartCTL(list[i].Path)
|
|
if reflect.DeepEqual(temp, model.SmartctlA{}) {
|
|
temp.SmartStatus.Passed = true
|
|
}
|
|
if len(list[i].Children) == 1 && len(list[i].Children[0].MountPoint) > 0 {
|
|
stor := model.Storage{}
|
|
stor.MountPoint = list[i].Children[0].MountPoint
|
|
stor.Size = list[i].Children[0].FSSize
|
|
stor.Avail = list[i].Children[0].FSAvail
|
|
stor.Path = list[i].Children[0].Path
|
|
stor.Type = list[i].Children[0].FsType
|
|
stor.DriveName = list[i].Name
|
|
pathArr := strings.Split(list[i].Children[0].MountPoint, "/")
|
|
if len(pathArr) == 3 {
|
|
stor.Name = pathArr[2]
|
|
}
|
|
if t, ok := part[list[i].Children[0].MountPoint]; ok {
|
|
stor.CreatedAt = t
|
|
}
|
|
storage = append(storage, stor)
|
|
} else {
|
|
//todo 长度有问题
|
|
if len(list[i].Children) == 1 && list[i].Children[0].FsType == "ext4" {
|
|
disk.NeedFormat = false
|
|
avail = append(avail, disk)
|
|
} else {
|
|
disk.NeedFormat = true
|
|
avail = append(avail, disk)
|
|
}
|
|
}
|
|
|
|
disk.Temperature = temp.Temperature.Current
|
|
disk.Health = strconv.FormatBool(temp.SmartStatus.Passed)
|
|
|
|
disks = append(disks, disk)
|
|
}
|
|
}
|
|
data := make(map[string]interface{}, 3)
|
|
data["drive"] = disks
|
|
data["storage"] = storage
|
|
data["avail"] = avail
|
|
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
|
|
}
|
|
|
|
// @Summary get disk list
|
|
// @Produce application/json
|
|
// @Accept application/json
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/lists [get]
|
|
func GetPlugInDisks(c *gin.Context) {
|
|
|
|
list := service.MyService.Disk().LSBLK(true)
|
|
var result []*disk.UsageStat
|
|
for _, item := range list {
|
|
result = append(result, service.MyService.Disk().GetDiskInfoByPath(item.Path))
|
|
}
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: result})
|
|
}
|
|
|
|
// @Summary disk detail
|
|
// @Produce application/json
|
|
// @Accept application/json
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Param path query string true "for example /dev/sda"
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/info [get]
|
|
func GetDiskInfo(c *gin.Context) {
|
|
path := c.Query("path")
|
|
if len(path) == 0 {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
|
}
|
|
m := service.MyService.Disk().GetDiskInfo(path)
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: m})
|
|
}
|
|
|
|
// @Summary format storage
|
|
// @Produce application/json
|
|
// @Accept multipart/form-data
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Param path formData string true "e.g. /dev/sda1"
|
|
// @Param pwd formData string true "user password"
|
|
// @Param volume formData string true "mount point"
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/format [post]
|
|
func FormatDisk(c *gin.Context) {
|
|
path := c.PostForm("path")
|
|
t := "ext4"
|
|
pwd := c.PostForm("pwd")
|
|
volume := c.PostForm("volume")
|
|
|
|
if pwd != config.UserInfo.PWD {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.PWD_INVALID, Message: oasis_err.GetMsg(oasis_err.PWD_INVALID)})
|
|
return
|
|
}
|
|
|
|
if len(path) == 0 || len(t) == 0 {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
|
return
|
|
}
|
|
if _, ok := diskMap[path]; ok {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
|
|
return
|
|
}
|
|
diskMap[path] = "busying"
|
|
service.MyService.Disk().UmountPointAndRemoveDir(path)
|
|
format := service.MyService.Disk().FormatDisk(path, t)
|
|
if len(format) == 0 {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.FORMAT_ERROR, Message: oasis_err.GetMsg(oasis_err.FORMAT_ERROR)})
|
|
delete(diskMap, path)
|
|
return
|
|
}
|
|
service.MyService.Disk().MountDisk(path, volume)
|
|
service.MyService.Disk().RemoveLSBLKCache()
|
|
delete(diskMap, path)
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
|
}
|
|
|
|
// @Summary 获取支持的格式
|
|
// @Produce application/json
|
|
// @Accept application/json
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/type [get]
|
|
func FormatDiskType(c *gin.Context) {
|
|
var strArr = [4]string{"fat32", "ntfs", "ext4", "exfat"}
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: strArr})
|
|
|
|
}
|
|
|
|
// @Summary 删除分区
|
|
// @Produce application/json
|
|
// @Accept multipart/form-data
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Param path formData string true "磁盘路径 例如/dev/sda1"
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/delpart [delete]
|
|
func RemovePartition(c *gin.Context) {
|
|
path := c.PostForm("path")
|
|
|
|
if len(path) == 0 {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
|
}
|
|
var p = path[:len(path)-1]
|
|
var n = path[len(path)-1:]
|
|
service.MyService.Disk().DelPartition(p, n)
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
|
}
|
|
|
|
// @Summary add storage
|
|
// @Produce application/json
|
|
// @Accept multipart/form-data
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Param path formData string true "disk path e.g. /dev/sda"
|
|
// @Param serial formData string true "serial"
|
|
// @Param name formData string true "name"
|
|
// @Param format formData bool true "need format(true)"
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/storage [post]
|
|
func AddPartition(c *gin.Context) {
|
|
name := c.PostForm("name")
|
|
path := c.PostForm("path")
|
|
format, _ := strconv.ParseBool(c.PostForm("format"))
|
|
if len(name) == 0 || len(path) == 0 {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
|
return
|
|
}
|
|
if _, ok := diskMap[path]; ok {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
|
|
return
|
|
}
|
|
if !file.CheckNotExist("/DATA/" + name) {
|
|
// /mnt/name exist
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.NAME_NOT_AVAILABLE, Message: oasis_err.GetMsg(oasis_err.NAME_NOT_AVAILABLE)})
|
|
return
|
|
}
|
|
diskMap[path] = "busying"
|
|
currentDisk := service.MyService.Disk().GetDiskInfo(path)
|
|
if !format {
|
|
if len(currentDisk.Children) != 1 || !(len(currentDisk.Children) > 0 && currentDisk.Children[0].FsType == "ext4") {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_NEEDS_FORMAT, Message: oasis_err.GetMsg(oasis_err.DISK_NEEDS_FORMAT)})
|
|
delete(diskMap, path)
|
|
return
|
|
}
|
|
} else {
|
|
service.MyService.Disk().AddPartition(path)
|
|
}
|
|
|
|
formatBool := true
|
|
for formatBool {
|
|
currentDisk = service.MyService.Disk().GetDiskInfo(path)
|
|
fmt.Println(currentDisk.Children)
|
|
if len(currentDisk.Children) > 0 {
|
|
formatBool = false
|
|
break
|
|
}
|
|
time.Sleep(time.Second)
|
|
}
|
|
currentDisk = service.MyService.Disk().GetDiskInfo(path)
|
|
if len(currentDisk.Children) != 1 {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_NEEDS_FORMAT, Message: oasis_err.GetMsg(oasis_err.DISK_NEEDS_FORMAT)})
|
|
return
|
|
}
|
|
|
|
mountPath := "/DATA/" + name
|
|
m := model2.SerialDisk{}
|
|
m.MountPoint = mountPath
|
|
m.Path = currentDisk.Children[0].Path
|
|
m.UUID = currentDisk.Children[0].UUID
|
|
m.State = 0
|
|
m.CreatedAt = time.Now().Unix()
|
|
service.MyService.Disk().SaveMountPoint(m)
|
|
|
|
//mount dir
|
|
service.MyService.Disk().MountDisk(currentDisk.Children[0].Path, mountPath)
|
|
|
|
service.MyService.Disk().RemoveLSBLKCache()
|
|
|
|
delete(diskMap, path)
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
|
}
|
|
|
|
// @Summary add mount point
|
|
// @Produce application/json
|
|
// @Accept multipart/form-data
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Param path formData string true "for example: /dev/sda1"
|
|
// @Param serial formData string true "disk id"
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/mount [post]
|
|
func PostMountDisk(c *gin.Context) {
|
|
// for example: path=/dev/sda1
|
|
path := c.PostForm("path")
|
|
serial := c.PostForm("serial")
|
|
|
|
mountPath := "/DATA/volume"
|
|
var list = service.MyService.Disk().GetSerialAll()
|
|
var pathMapList = make(map[string]string, len(list))
|
|
for _, v := range list {
|
|
pathMapList[v.MountPoint] = "1"
|
|
}
|
|
|
|
for i := 0; i < len(list)+1; i++ {
|
|
if _, ok := pathMapList[mountPath+strconv.Itoa(i)]; !ok {
|
|
mountPath = mountPath + strconv.Itoa(i)
|
|
break
|
|
}
|
|
}
|
|
|
|
//mount dir
|
|
service.MyService.Disk().MountDisk(path, mountPath)
|
|
|
|
m := model2.SerialDisk{}
|
|
m.MountPoint = mountPath
|
|
m.Path = path
|
|
m.UUID = serial
|
|
m.State = 0
|
|
//service.MyService.Disk().SaveMountPoint(m)
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
|
}
|
|
|
|
// @Summary remove mount point
|
|
// @Produce application/json
|
|
// @Accept multipart/form-data
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Param path formData string true "e.g. /dev/sda1"
|
|
// @Param mount_point formData string true "e.g. /mnt/volume1"
|
|
// @Param pwd formData string true "user password"
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/umount [post]
|
|
func PostDiskUmount(c *gin.Context) {
|
|
|
|
path := c.PostForm("path")
|
|
mountPoint := c.PostForm("volume")
|
|
pwd := c.PostForm("pwd")
|
|
|
|
if len(path) == 0 || len(mountPoint) == 0 {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
|
|
return
|
|
}
|
|
if pwd != config.UserInfo.PWD {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.PWD_INVALID, Message: oasis_err.GetMsg(oasis_err.PWD_INVALID)})
|
|
return
|
|
}
|
|
|
|
if _, ok := diskMap[path]; ok {
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.DISK_BUSYING, Message: oasis_err.GetMsg(oasis_err.DISK_BUSYING)})
|
|
return
|
|
}
|
|
|
|
service.MyService.Disk().UmountPointAndRemoveDir(path)
|
|
//delete data
|
|
service.MyService.Disk().DeleteMountPoint(path, mountPoint)
|
|
service.MyService.Disk().RemoveLSBLKCache()
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
|
}
|
|
|
|
// @Summary confirm delete disk
|
|
// @Produce application/json
|
|
// @Accept application/json
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Param id path string true "id"
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/remove/{id} [delete]
|
|
func DeleteDisk(c *gin.Context) {
|
|
id := c.Param("id")
|
|
service.MyService.Disk().DeleteMount(id)
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
|
}
|
|
|
|
// @Summary check mount point
|
|
// @Produce application/json
|
|
// @Accept application/json
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/init [get]
|
|
func GetDiskCheck(c *gin.Context) {
|
|
|
|
dbList := service.MyService.Disk().GetSerialAll()
|
|
list := service.MyService.Disk().LSBLK(true)
|
|
|
|
mapList := make(map[string]string)
|
|
|
|
for _, v := range list {
|
|
mapList[v.Serial] = "1"
|
|
}
|
|
|
|
for _, v := range dbList {
|
|
if _, ok := mapList[v.UUID]; !ok {
|
|
//disk undefind
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.ERROR, Message: oasis_err.GetMsg(oasis_err.ERROR), Data: "disk undefind"})
|
|
return
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
|
|
}
|
|
|
|
// @Summary check mount point
|
|
// @Produce application/json
|
|
// @Accept application/json
|
|
// @Tags disk
|
|
// @Security ApiKeyAuth
|
|
// @Success 200 {string} string "ok"
|
|
// @Router /disk/usb [get]
|
|
func GetUSBList(c *gin.Context) {
|
|
list := service.MyService.Disk().LSBLK(false)
|
|
data := []model.DriveUSB{}
|
|
for _, v := range list {
|
|
if v.Tran == "usb" {
|
|
temp := model.DriveUSB{}
|
|
temp.Model = v.Model
|
|
temp.Name = v.Name
|
|
temp.Size = v.Size
|
|
mountTemp := true
|
|
if len(v.Children) == 0 {
|
|
mountTemp = false
|
|
}
|
|
for _, child := range v.Children {
|
|
if len(child.MountPoint) > 0 {
|
|
avail, _ := strconv.ParseUint(child.FSAvail, 10, 64)
|
|
temp.Avail += avail
|
|
} else {
|
|
mountTemp = false
|
|
}
|
|
}
|
|
temp.Mount = mountTemp
|
|
data = append(data, temp)
|
|
}
|
|
}
|
|
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: data})
|
|
}
|