diff --git a/model/disk.go b/model/disk.go deleted file mode 100644 index 75d3bc5..0000000 --- a/model/disk.go +++ /dev/null @@ -1,98 +0,0 @@ -/* - * @Author: LinkLeong link@icewhale.com - * @Date: 2022-07-13 10:43:45 - * @LastEditors: LinkLeong - * @LastEditTime: 2022-08-03 14:45:35 - * @FilePath: /CasaOS/model/disk.go - * @Description: - * @Website: https://www.casaos.io - * Copyright (c) 2022 by icewhale, All Rights Reserved. - */ -package model - -type LSBLKModel struct { - Name string `json:"name"` - FsType string `json:"fstype"` - Size uint64 `json:"size"` - FSSize string `json:"fssize"` - Path string `json:"path"` - Model string `json:"model"` //设备标识符 - RM bool `json:"rm"` //是否为可移动设备 - RO bool `json:"ro"` //是否为只读设备 - State string `json:"state"` - PhySec int `json:"phy-sec"` //物理扇区大小 - Type string `json:"type"` - Vendor string `json:"vendor"` //供应商 - Rev string `json:"rev"` //修订版本 - FSAvail string `json:"fsavail"` //可用空间 - FSUse string `json:"fsuse%"` //已用百分比 - MountPoint string `json:"mountpoint"` - Format string `json:"format"` - Health string `json:"health"` - HotPlug bool `json:"hotplug"` - UUID string `json:"uuid"` - FSUsed string `json:"fsused"` - Temperature int `json:"temperature"` - Tran string `json:"tran"` - MinIO uint64 `json:"min-io"` - UsedPercent float64 `json:"used_percent"` - Serial string `json:"serial"` - Children []LSBLKModel `json:"children"` - SubSystems string `json:"subsystems"` - Label string `json:"label"` - //详情特有 - StartSector uint64 `json:"start_sector,omitempty"` - Rota bool `json:"rota"` //true(hhd) false(ssd) - DiskType string `json:"disk_type"` - EndSector uint64 `json:"end_sector,omitempty"` -} - -type Drive struct { - Name string `json:"name"` - Size uint64 `json:"size"` - Model string `json:"model"` - Health string `json:"health"` - Temperature int `json:"temperature"` - DiskType string `json:"disk_type"` - NeedFormat bool `json:"need_format"` - Serial string `json:"serial"` - Path string `json:"path"` - ChildrenNumber int `json:"children_number"` -} - -type DriveUSB struct { - Name string `json:"name"` - Size uint64 `json:"size"` - Model string `json:"model"` - Avail uint64 `json:"avail"` - Children []USBChildren `json:"children"` -} -type USBChildren struct { - Name string `json:"name"` - Size uint64 `json:"size"` - Avail uint64 `json:"avail"` - MountPoint string `json:"mount_point"` -} - -type Storage struct { - MountPoint string `json:"mount_point"` - Size string `json:"size"` - Avail string `json:"avail"` //可用空间 - Type string `json:"type"` - Path string `json:"path"` - DriveName string `json:"drive_name"` - Label string `json:"label"` -} -type Storages struct { - DiskName string `json:"disk_name"` - Size uint64 `json:"size"` - Path string `json:"path"` - Children []Storage `json:"children"` -} - -type Summary struct { - Size uint64 `json:"size"` - Avail uint64 `json:"avail"` //可用空间 - Health bool `json:"health"` - Used uint64 `json:"used"` -} diff --git a/model/notify/storage.go b/model/notify/storage.go deleted file mode 100644 index 0c62970..0000000 --- a/model/notify/storage.go +++ /dev/null @@ -1,19 +0,0 @@ -/* - * @Author: LinkLeong link@icewhale.com - * @Date: 2022-07-15 10:43:00 - * @LastEditors: LinkLeong - * @LastEditTime: 2022-07-15 10:56:17 - * @FilePath: /CasaOS/model/notify/storage.go - * @Description: - * @Website: https://www.casaos.io - * Copyright (c) 2022 by icewhale, All Rights Reserved. - */ -package notify - -type StorageMessage struct { - Type string `json:"type"` //sata,usb - Action string `json:"action"` //remove add - Path string `json:"path"` - Volume string `json:"volume"` - Size uint64 `json:"size"` -} diff --git a/model/smartctl_model.go b/model/smartctl_model.go deleted file mode 100644 index ec7f75c..0000000 --- a/model/smartctl_model.go +++ /dev/null @@ -1,69 +0,0 @@ -package model - -// -type SmartctlA struct { - Smartctl struct { - Version []int `json:"version"` - SvnRevision string `json:"svn_revision"` - PlatformInfo string `json:"platform_info"` - BuildInfo string `json:"build_info"` - Argv []string `json:"argv"` - ExitStatus int `json:"exit_status"` - } `json:"smartctl"` - Device struct { - Name string `json:"name"` - InfoName string `json:"info_name"` - Type string `json:"type"` - Protocol string `json:"protocol"` - } `json:"device"` - ModelName string `json:"model_name"` - SerialNumber string `json:"serial_number"` - FirmwareVersion string `json:"firmware_version"` - UserCapacity struct { - Blocks int `json:"blocks"` - Bytes int64 `json:"bytes"` - } `json:"user_capacity"` - SmartStatus struct { - Passed bool `json:"passed"` - } `json:"smart_status"` - AtaSmartData struct { - OfflineDataCollection struct { - Status struct { - Value int `json:"value"` - String string `json:"string"` - } `json:"status"` - CompletionSeconds int `json:"completion_seconds"` - } `json:"offline_data_collection"` - SelfTest struct { - Status struct { - Value int `json:"value"` - String string `json:"string"` - Passed bool `json:"passed"` - } `json:"status"` - PollingMinutes struct { - Short int `json:"short"` - Extended int `json:"extended"` - Conveyance int `json:"conveyance"` - } `json:"polling_minutes"` - } `json:"self_test"` - Capabilities struct { - Values []int `json:"values"` - ExecOfflineImmediateSupported bool `json:"exec_offline_immediate_supported"` - OfflineIsAbortedUponNewCmd bool `json:"offline_is_aborted_upon_new_cmd"` - OfflineSurfaceScanSupported bool `json:"offline_surface_scan_supported"` - SelfTestsSupported bool `json:"self_tests_supported"` - ConveyanceSelfTestSupported bool `json:"conveyance_self_test_supported"` - SelectiveSelfTestSupported bool `json:"selective_self_test_supported"` - AttributeAutosaveEnabled bool `json:"attribute_autosave_enabled"` - ErrorLoggingSupported bool `json:"error_logging_supported"` - GpLoggingSupported bool `json:"gp_logging_supported"` - } `json:"capabilities"` - } `json:"ata_smart_data"` - PowerOnTime struct { - Hours int `json:"hours"` - } `json:"power_on_time"` - PowerCycleCount int `json:"power_cycle_count"` - Temperature struct { - Current int `json:"current"` - } `json:"temperature"` -} diff --git a/pkg/utils/command/command_helper.go b/pkg/utils/command/command_helper.go index 9a2fded..5727b63 100644 --- a/pkg/utils/command/command_helper.go +++ b/pkg/utils/command/command_helper.go @@ -2,11 +2,9 @@ package command import ( "bufio" - "context" "fmt" "io/ioutil" "os/exec" - "time" ) func OnlyExec(cmdStr string) { @@ -35,8 +33,8 @@ func ExecResultStrArray(cmdStr string) []string { fmt.Println(err) return nil } - //str, err := ioutil.ReadAll(stdout) - var networklist = []string{} + // str, err := ioutil.ReadAll(stdout) + networklist := []string{} outputBuf := bufio.NewReader(stdout) for { output, _, err := outputBuf.ReadLine() @@ -72,41 +70,3 @@ func ExecResultStr(cmdStr string) string { } return string(str) } - -//执行 lsblk 命令 -func ExecLSBLK() []byte { - output, err := exec.Command("lsblk", "-O", "-J", "-b").Output() - if err != nil { - fmt.Println("lsblk", err) - return nil - } - return output -} - -//执行 lsblk 命令 -func ExecLSBLKByPath(path string) []byte { - output, err := exec.Command("lsblk", path, "-O", "-J", "-b").Output() - if err != nil { - fmt.Println("lsblk", err) - return nil - } - return output -} - -//exec smart -func ExecSmartCTLByPath(path string) []byte { - timeout := 3 - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second) - defer cancel() - output, err := exec.CommandContext(ctx, "smartctl", "-a", path, "-j").Output() - if err != nil { - fmt.Println("smartctl", err) - return nil - } - return output -} - -func ExecEnabledSMART(path string) { - - exec.Command("smartctl", "-s on", path).Output() -} diff --git a/route/v1/disk.go b/route/v1/disk.go deleted file mode 100644 index 7601eb4..0000000 --- a/route/v1/disk.go +++ /dev/null @@ -1,608 +0,0 @@ -package v1 - -import ( - "fmt" - "net/http" - "path/filepath" - "reflect" - "strconv" - "strings" - "time" - - "github.com/IceWhaleTech/CasaOS/model" - "github.com/IceWhaleTech/CasaOS/model/notify" - "github.com/IceWhaleTech/CasaOS/pkg/utils/common_err" - "github.com/IceWhaleTech/CasaOS/pkg/utils/encryption" - "github.com/IceWhaleTech/CasaOS/pkg/utils/file" - "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) { - path := c.Query("path") - if len(path) > 0 { - m := service.MyService.Disk().GetDiskInfo(path) - c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m}) - return - } - t := c.DefaultQuery("type", "") - list := service.MyService.Disk().LSBLK(false) - if t == "usb" { - 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 - for _, child := range v.Children { - if len(child.MountPoint) > 0 { - avail, _ := strconv.ParseUint(child.FSAvail, 10, 64) - temp.Avail += avail - } - } - data = append(data, temp) - } - } - c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) - return - } - - 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 - disk.ChildrenNumber = len(list[i].Children) - 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.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.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" || strings.Contains(list[i].SubSystems, "virtio") || (list[i].Tran == "ata" && list[i].Type == "disk") { - temp := service.MyService.Disk().SmartCTL(list[i].Path) - if reflect.DeepEqual(temp, model.SmartctlA{}) { - temp.SmartStatus.Passed = true - } - isAvail := true - for _, v := range list[i].Children { - if v.MountPoint != "" { - stor := model.Storage{} - stor.MountPoint = v.MountPoint - stor.Size = v.FSSize - stor.Avail = v.FSAvail - stor.Path = v.Path - stor.Type = v.FsType - stor.DriveName = list[i].Name - storage = append(storage, stor) - isAvail = false - } - } - - if isAvail { - //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(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) -} - -// @Summary disk list -// @Produce application/json -// @Accept application/json -// @Tags disk -// @Security ApiKeyAuth -// @Success 200 {string} string "ok" -// @Router /disk/list [get] -func GetDisksUSBList(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.Label - if temp.Name == "" { - temp.Name = v.Name - } - temp.Size = v.Size - children := []model.USBChildren{} - for _, child := range v.Children { - - if len(child.MountPoint) > 0 { - tempChildren := model.USBChildren{} - tempChildren.MountPoint = child.MountPoint - tempChildren.Size, _ = strconv.ParseUint(child.FSSize, 10, 64) - tempChildren.Avail, _ = strconv.ParseUint(child.FSAvail, 10, 64) - tempChildren.Name = child.Label - if len(tempChildren.Name) == 0 { - tempChildren.Name = filepath.Base(child.MountPoint) - } - avail, _ := strconv.ParseUint(child.FSAvail, 10, 64) - children = append(children, tempChildren) - temp.Avail += avail - } - } - - temp.Children = children - data = append(data, temp) - } - } - c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: data}) - -} - -func DeleteDisksUmount(c *gin.Context) { - id := c.GetHeader("user_id") - js := make(map[string]string) - c.ShouldBind(&js) - - path := js["path"] - pwd := js["password"] - - if len(path) == 0 { - c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) - return - } - user := service.MyService.User().GetUserAllInfoById(id) - if user.Id == 0 { - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)}) - return - } - if encryption.GetMD5ByStr(pwd) != user.Password { - c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)}) - return - } - - if _, ok := diskMap[path]; ok { - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)}) - return - } - - diskInfo := service.MyService.Disk().GetDiskInfo(path) - for _, v := range diskInfo.Children { - service.MyService.Disk().UmountPointAndRemoveDir(v.Path) - //delete data - service.MyService.Disk().DeleteMountPoint(v.Path, v.MountPoint) - - service.MyService.Shares().DeleteShareByPath(v.MountPoint) - } - - service.MyService.Disk().RemoveLSBLKCache() - - //send notify to client - msg := notify.StorageMessage{} - msg.Action = "REMOVED" - msg.Path = path - msg.Volume = "" - msg.Size = 0 - msg.Type = "" - service.MyService.Notify().SendStorageBySocket(msg) - c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: path}) -} - -func DeleteDiskUSB(c *gin.Context) { - js := make(map[string]string) - c.ShouldBind(&js) - mountPoint := js["mount_point"] - if file.CheckNotExist(mountPoint) { - c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.DIR_NOT_EXISTS, Message: common_err.GetMsg(common_err.DIR_NOT_EXISTS)}) - return - } - service.MyService.Disk().UmountUSB(mountPoint) - c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: mountPoint}) -} - -// @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: common_err.SUCCESS, Message: common_err.GetMsg(common_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: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) - } - m := service.MyService.Disk().GetDiskInfo(path) - c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS), Data: m}) -} - -// @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: common_err.SUCCESS, Message: common_err.GetMsg(common_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) { - js := make(map[string]string) - c.ShouldBind(&js) - path := js["path"] - - if len(path) == 0 { - c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) - } - var p = path[:len(path)-1] - var n = path[len(path)-1:] - service.MyService.Disk().DelPartition(p, n) - c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_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 PostDiskAddPartition(c *gin.Context) { - - js := make(map[string]interface{}) - c.ShouldBind(&js) - path := js["path"].(string) - name := js["name"].(string) - format := js["format"].(bool) - - if len(path) == 0 { - c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) - return - } - if _, ok := diskMap[path]; ok { - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)}) - return - } - - //diskInfo := service.MyService.Disk().GetDiskInfo(path) - - // if !file.CheckNotExist("/DATA/" + name) { - // // /mnt/name exist - // c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.NAME_NOT_AVAILABLE, Message: common_err.GetMsg(common_err.NAME_NOT_AVAILABLE)}) - // return - // } - diskMap[path] = "busying" - currentDisk := service.MyService.Disk().GetDiskInfo(path) - if format { - // format := service.MyService.Disk().FormatDisk(path+"1", "ext4") - // if len(format) == 0 { - // delete(diskMap, path) - // c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FORMAT_ERROR, Message: common_err.GetMsg(common_err.FORMAT_ERROR)}) - // return - // } - service.MyService.Disk().AddPartition(path) - } - - // formatBool := true - // for formatBool { - // currentDisk = service.MyService.Disk().GetDiskInfo(path) - // 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(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_NEEDS_FORMAT, Message: common_err.GetMsg(common_err.DISK_NEEDS_FORMAT)}) - // return - // } - fmt.Println(name) - if len(name) == 0 { - name = "Storage" - } - fmt.Println(name) - for i := 0; i < len(currentDisk.Children); i++ { - childrenName := currentDisk.Children[i].Label - if len(childrenName) == 0 { - //childrenName = name + "_" + currentDisk.Children[i].Name - childrenName = name + "_" + strconv.Itoa(i+1) - } - mountPath := "/DATA/" + childrenName - if !file.CheckNotExist(mountPath) { - ls := service.MyService.System().GetDirPath(mountPath) - if len(ls) > 0 { - // exist - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.NAME_NOT_AVAILABLE, Message: common_err.GetMsg(common_err.NAME_NOT_AVAILABLE)}) - return - } - } - m := model2.SerialDisk{} - m.MountPoint = mountPath - m.Path = currentDisk.Children[i].Path - m.UUID = currentDisk.Children[i].UUID - m.State = 0 - m.CreatedAt = time.Now().Unix() - service.MyService.Disk().SaveMountPoint(m) - //mount dir - service.MyService.Disk().MountDisk(currentDisk.Children[i].Path, mountPath) - } - - service.MyService.Disk().RemoveLSBLKCache() - - delete(diskMap, path) - - //send notify to client - msg := notify.StorageMessage{} - msg.Action = "ADDED" - msg.Path = currentDisk.Children[0].Path - msg.Volume = "/DATA/" - msg.Size = currentDisk.Children[0].Size - msg.Type = currentDisk.Children[0].Tran - service.MyService.Notify().SendStorageBySocket(msg) - - c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) -} - -// @Param pwd formData string true "user password" -// @Param volume formData string true "mount point" -// @Success 200 {string} string "ok" -// @Router /disk/format [post] -func PostDiskFormat(c *gin.Context) { - id := c.GetHeader("user_id") - js := make(map[string]string) - c.ShouldBind(&js) - path := js["path"] - t := "ext4" - pwd := js["password"] - volume := js["volume"] - user := service.MyService.User().GetUserAllInfoById(id) - if user.Id == 0 { - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)}) - return - } - if encryption.GetMD5ByStr(pwd) != user.Password { - c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)}) - return - } - - if len(path) == 0 || len(t) == 0 { - c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) - return - } - if _, ok := diskMap[path]; ok { - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)}) - return - } - diskMap[path] = "busying" - service.MyService.Disk().UmountPointAndRemoveDir(path) - format := service.MyService.Disk().FormatDisk(path, t) - if len(format) == 0 { - delete(diskMap, path) - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.FORMAT_ERROR, Message: common_err.GetMsg(common_err.FORMAT_ERROR)}) - return - } - service.MyService.Disk().MountDisk(path, volume) - service.MyService.Disk().RemoveLSBLKCache() - delete(diskMap, path) - c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_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) { - id := c.GetHeader("user_id") - js := make(map[string]string) - c.ShouldBind(&js) - - path := js["path"] - mountPoint := js["volume"] - pwd := js["password"] - - if len(path) == 0 || len(mountPoint) == 0 { - c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.INVALID_PARAMS, Message: common_err.GetMsg(common_err.INVALID_PARAMS)}) - return - } - user := service.MyService.User().GetUserAllInfoById(id) - if user.Id == 0 { - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)}) - return - } - if encryption.GetMD5ByStr(pwd) != user.Password { - c.JSON(common_err.CLIENT_ERROR, model.Result{Success: common_err.PWD_INVALID, Message: common_err.GetMsg(common_err.PWD_INVALID)}) - return - } - - if _, ok := diskMap[path]; ok { - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.DISK_BUSYING, Message: common_err.GetMsg(common_err.DISK_BUSYING)}) - return - } - - service.MyService.Disk().UmountPointAndRemoveDir(path) - //delete data - service.MyService.Disk().DeleteMountPoint(path, mountPoint) - service.MyService.Disk().RemoveLSBLKCache() - - //send notify to client - msg := notify.StorageMessage{} - msg.Action = "REMOVED" - msg.Path = path - msg.Volume = mountPoint - msg.Size = 0 - msg.Type = "" - service.MyService.Notify().SendStorageBySocket(msg) - c.JSON(common_err.SUCCESS, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_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: common_err.SUCCESS, Message: common_err.GetMsg(common_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(common_err.SERVICE_ERROR, model.Result{Success: common_err.SERVICE_ERROR, Message: common_err.GetMsg(common_err.SERVICE_ERROR), Data: "disk undefind"}) - return - } - } - - c.JSON(http.StatusOK, model.Result{Success: common_err.SUCCESS, Message: common_err.GetMsg(common_err.SUCCESS)}) -} diff --git a/service/disk.go b/service/disk.go deleted file mode 100644 index dfe8219..0000000 --- a/service/disk.go +++ /dev/null @@ -1,285 +0,0 @@ -package service - -import ( - json2 "encoding/json" - "fmt" - "reflect" - "strconv" - "strings" - "time" - - "github.com/IceWhaleTech/CasaOS/model" - "github.com/IceWhaleTech/CasaOS/pkg/config" - command2 "github.com/IceWhaleTech/CasaOS/pkg/utils/command" - "github.com/IceWhaleTech/CasaOS/pkg/utils/loger" - model2 "github.com/IceWhaleTech/CasaOS/service/model" - "github.com/shirou/gopsutil/v3/disk" - "github.com/tidwall/gjson" - "go.uber.org/zap" - "gorm.io/gorm" -) - -type DiskService interface { - GetPlugInDisk() []string - LSBLK(isUseCache bool) []model.LSBLKModel - SmartCTL(path string) model.SmartctlA - FormatDisk(path, format string) []string - UmountPointAndRemoveDir(path string) []string - GetDiskInfo(path string) model.LSBLKModel - DelPartition(path, num string) string - AddPartition(path string) string - GetDiskInfoByPath(path string) *disk.UsageStat - MountDisk(path, volume string) - GetSerialAll() []model2.SerialDisk - SaveMountPoint(m model2.SerialDisk) - DeleteMountPoint(path, mountPoint string) - DeleteMount(id string) - UpdateMountPoint(m model2.SerialDisk) - RemoveLSBLKCache() - UmountUSB(path string) -} -type diskService struct { - db *gorm.DB -} - -func (d *diskService) RemoveLSBLKCache() { - key := "system_lsblk" - Cache.Delete(key) -} -func (d *diskService) UmountUSB(path string) { - r := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;UDEVILUmount " + path) - fmt.Println(r) -} -func (d *diskService) SmartCTL(path string) model.SmartctlA { - - key := "system_smart_" + path - if result, ok := Cache.Get(key); ok { - - res, ok := result.(model.SmartctlA) - if ok { - return res - } - } - var m model.SmartctlA - str := command2.ExecSmartCTLByPath(path) - if str == nil { - loger.Error("failed to exec shell ", zap.Any("err", "smartctl exec error")) - Cache.Add(key, m, time.Minute*10) - return m - } - - err := json2.Unmarshal([]byte(str), &m) - if err != nil { - loger.Error("Failed to unmarshal json", zap.Any("err", err)) - } - if !reflect.DeepEqual(m, model.SmartctlA{}) { - Cache.Add(key, m, time.Hour*24) - } - return m -} - -//通过脚本获取外挂磁盘 -func (d *diskService) GetPlugInDisk() []string { - return command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetPlugInDisk") -} - -//格式化硬盘 -func (d *diskService) FormatDisk(path, format string) []string { - r := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;FormatDisk " + path + " " + format) - return r -} - -//移除挂载点,删除目录 -func (d *diskService) UmountPointAndRemoveDir(path string) []string { - r := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;UMountPorintAndRemoveDir " + path) - return r -} - -//删除分区 -func (d *diskService) DelPartition(path, num string) string { - r := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;DelPartition " + path + " " + num) - fmt.Println(r) - return "" -} - -//part -func (d *diskService) AddPartition(path string) string { - command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;AddPartition " + path) - return "" -} - -func (d *diskService) AddAllPartition(path string) { - -} - -//获取硬盘详情 -func (d *diskService) GetDiskInfoByPath(path string) *disk.UsageStat { - diskInfo, err := disk.Usage(path + "1") - - if err != nil { - fmt.Println(err) - } - diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64) - diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64) - return diskInfo -} - -//get disk details -func (d *diskService) LSBLK(isUseCache bool) []model.LSBLKModel { - key := "system_lsblk" - var n []model.LSBLKModel - - if result, ok := Cache.Get(key); ok && isUseCache { - - res, ok := result.([]model.LSBLKModel) - if ok { - return res - } - } - - str := command2.ExecLSBLK() - if str == nil { - loger.Error("Failed to exec shell", zap.Any("err", "lsblk exec error")) - return nil - } - var m []model.LSBLKModel - err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &m) - if err != nil { - loger.Error("Failed to unmarshal json", zap.Any("err", err)) - } - - var c []model.LSBLKModel - - var fsused uint64 - - var health = true - for _, i := range m { - if i.Type != "loop" && !i.RO { - fsused = 0 - for _, child := range i.Children { - if child.RM { - child.Health = strings.TrimSpace(command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDiskHealthState " + child.Path)) - if strings.ToLower(strings.TrimSpace(child.State)) != "ok" { - health = false - } - f, _ := strconv.ParseUint(child.FSUsed, 10, 64) - fsused += f - } else { - health = false - } - c = append(c, child) - } - //i.Format = strings.TrimSpace(command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDiskType " + i.Path)) - if health { - i.Health = "OK" - } - i.FSUsed = strconv.FormatUint(fsused, 10) - i.Children = c - if fsused > 0 { - i.UsedPercent, err = strconv.ParseFloat(fmt.Sprintf("%.4f", float64(fsused)/float64(i.Size)), 64) - if err != nil { - loger.Error("Failed to parse float", zap.Any("err", err)) - } - } - n = append(n, i) - health = true - c = []model.LSBLKModel{} - fsused = 0 - } - } - if len(n) > 0 { - Cache.Add(key, n, time.Second*100) - } - return n -} - -func (d *diskService) GetDiskInfo(path string) model.LSBLKModel { - str := command2.ExecLSBLKByPath(path) - if str == nil { - loger.Error("Failed to exec shell", zap.Any("err", "lsblk exec error")) - return model.LSBLKModel{} - } - - var ml []model.LSBLKModel - err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &ml) - if err != nil { - loger.Error("Failed to unmarshal json", zap.Any("err", err)) - return model.LSBLKModel{} - } - - m := model.LSBLKModel{} - if len(ml) > 0 { - m = ml[0] - } - return m - // 下面为计算是否可以继续分区的部分,暂时不需要 - chiArr := make(map[string]string) - chiList := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetPartitionSectors " + m.Path) - if len(chiList) == 0 { - loger.Error("chiList length error", zap.Any("err", "chiList length error")) - } - for i := 0; i < len(chiList); i++ { - tempArr := strings.Split(chiList[i], ",") - chiArr[tempArr[0]] = chiList[i] - } - var maxSector uint64 = 0 - for i := 0; i < len(m.Children); i++ { - tempArr := strings.Split(chiArr[m.Children[i].Path], ",") - m.Children[i].StartSector, _ = strconv.ParseUint(tempArr[1], 10, 64) - m.Children[i].EndSector, _ = strconv.ParseUint(tempArr[2], 10, 64) - if m.Children[i].EndSector > maxSector { - maxSector = m.Children[i].EndSector - } - - } - diskEndSector := command2.ExecResultStrArray("source " + config.AppInfo.ShellPath + "/helper.sh ;GetDiskSizeAndSectors " + m.Path) - - if len(diskEndSector) < 2 { - loger.Error("diskEndSector length error", zap.Any("err", "diskEndSector length error")) - } - diskEndSectorInt, _ := strconv.ParseUint(diskEndSector[len(diskEndSector)-1], 10, 64) - if (diskEndSectorInt-maxSector)*m.MinIO/1024/1024 > 100 { - //添加可以分区情况 - p := model.LSBLKModel{} - p.Path = "可以添加" - m.Children = append(m.Children, p) - } - return m -} - -func (d *diskService) MountDisk(path, volume string) { - //fmt.Println("source " + config.AppInfo.ShellPath + "/helper.sh ;do_mount " + path + " " + volume) - r := command2.ExecResultStr("source " + config.AppInfo.ShellPath + "/helper.sh ;do_mount " + path + " " + volume) - fmt.Println(r) -} - -func (d *diskService) SaveMountPoint(m model2.SerialDisk) { - d.db.Where("uuid = ?", m.UUID).Delete(&model2.SerialDisk{}) - d.db.Create(&m) -} - -func (d *diskService) UpdateMountPoint(m model2.SerialDisk) { - d.db.Model(&model2.SerialDisk{}).Where("uui = ?", m.UUID).Update("mount_point", m.MountPoint) -} - -func (d *diskService) DeleteMount(id string) { - - d.db.Delete(&model2.SerialDisk{}).Where("id = ?", id) -} - -func (d *diskService) DeleteMountPoint(path, mountPoint string) { - - d.db.Where("path = ? AND mount_point = ?", path, mountPoint).Delete(&model2.SerialDisk{}) - - command2.OnlyExec("source " + config.AppInfo.ShellPath + "/helper.sh ;do_umount " + path) -} - -func (d *diskService) GetSerialAll() []model2.SerialDisk { - var m []model2.SerialDisk - d.db.Find(&m) - return m -} - -func NewDiskService(db *gorm.DB) DiskService { - return &diskService{db: db} -} diff --git a/service/model/o_disk.go b/service/model/o_disk.go deleted file mode 100644 index 1121e87..0000000 --- a/service/model/o_disk.go +++ /dev/null @@ -1,25 +0,0 @@ -/* - * @Author: LinkLeong link@icewhale.org - * @Date: 2021-12-07 17:14:41 - * @LastEditors: LinkLeong - * @LastEditTime: 2022-08-17 18:46:43 - * @FilePath: /CasaOS/service/model/o_disk.go - * @Description: - * @Website: https://www.casaos.io - * Copyright (c) 2022 by icewhale, All Rights Reserved. - */ -package model - -//SerialAdvanced Technology Attachment (STAT) -type SerialDisk struct { - Id uint `gorm:"column:id;primary_key" json:"id"` - UUID string `json:"uuid"` - Path string `json:"path"` - State int `json:"state"` - MountPoint string `json:"mount_point"` - CreatedAt int64 `json:"created_at"` -} - -func (p *SerialDisk) TableName() string { - return "o_disk" -} diff --git a/service/service.go b/service/service.go index b699725..7d6de20 100644 --- a/service/service.go +++ b/service/service.go @@ -21,16 +21,17 @@ var Cache *cache.Cache var MyService Repository -var WebSocketConns []*websocket.Conn -var NewVersionApp map[string]string -var SocketRun bool +var ( + WebSocketConns []*websocket.Conn + NewVersionApp map[string]string + SocketRun bool +) type Repository interface { App() AppService User() UserService Docker() DockerService Casa() CasaService - Disk() DiskService Notify() NotifyServer Rely() RelyService System() SystemService @@ -51,7 +52,6 @@ func NewService(db *gorm.DB, RuntimePath string) Repository { user: NewUserService(db), docker: NewDockerService(), casa: NewCasaService(), - disk: NewDiskService(db), notify: NewNotifyService(db), rely: NewRelyService(db), system: NewSystemService(), @@ -66,7 +66,6 @@ type store struct { user UserService docker DockerService casa CasaService - disk DiskService notify NotifyServer rely RelyService system SystemService @@ -78,9 +77,11 @@ type store struct { func (c *store) Gateway() gateway.ManagementService { return c.gateway } + func (s *store) Connections() ConnectionsService { return s.connections } + func (s *store) Shares() SharesService { return s.shares } @@ -92,8 +93,8 @@ func (c *store) Rely() RelyService { func (c *store) System() SystemService { return c.system } -func (c *store) Notify() NotifyServer { +func (c *store) Notify() NotifyServer { return c.notify } @@ -112,7 +113,3 @@ func (c *store) Docker() DockerService { func (c *store) Casa() CasaService { return c.casa } - -func (c *store) Disk() DiskService { - return c.disk -}