Compare commits

...

40 Commits

Author SHA1 Message Date
link
5c00655d14 Merge pull request #81 from IceWhaleTech/dev
Dev
2022-01-26 10:46:50 +08:00
link
eb36c262db Merge branch 'main' into dev 2022-01-26 10:46:43 +08:00
link
29d1861545 Merge branch 'main' into dev 2022-01-26 10:45:11 +08:00
link
3c9b410693 update dependency 2022-01-26 10:44:55 +08:00
link
4c3b41433b Update assist.sh 2022-01-24 22:06:31 +08:00
link
1fd13668c0 Merge pull request #78 from IceWhaleTech/dev
Dev
2022-01-24 17:22:48 +08:00
link
d1ab7261a6 Update usb-mount.sh 2022-01-24 17:21:43 +08:00
link
0fc65bcb3a update mount path 2022-01-24 17:08:28 +08:00
link
f1ce8bfd99 Merge pull request #77 from IceWhaleTech/dev
update disk
2022-01-24 11:19:47 +08:00
link
3f472f1864 update disk 2022-01-24 11:19:04 +08:00
link
229d94cae7 Merge pull request #74 from IceWhaleTech/dev
Fixed Storage Panel
2022-01-21 17:50:44 +08:00
link
c28e1bbf93 Fixed Storage Panel 2022-01-21 17:50:12 +08:00
link
a840029000 Merge pull request #73 from IceWhaleTech/dev
update UI
2022-01-20 18:45:54 +08:00
link
aad2646cf2 Merge branch 'dev' of ssh://github.com/IceWhaleTech/CasaOS into dev 2022-01-20 18:45:17 +08:00
link
ca1f8ad73e Update UI 2022-01-20 18:44:55 +08:00
link
dea02763a2 Update UI 2022-01-20 18:44:40 +08:00
link
ea67385a64 Merge pull request #72 from IceWhaleTech/dev
Storage Manager
2022-01-20 18:41:56 +08:00
link
fa2daa2767 Merge branch 'main' into dev 2022-01-20 18:41:49 +08:00
link
fcb906aa85 Storage Manager
Fix the app store classification problem
Fix the application market classification problem
2022-01-20 18:38:59 +08:00
老竭力
489a617126 Update casa.yml 2022-01-04 16:22:38 +08:00
老竭力
601e7ce10b Update casa.yml 2022-01-04 14:51:09 +08:00
老竭力
4a6fc9a945 Update system.go 2022-01-04 14:47:46 +08:00
老竭力
b377af1d24 Update casa.yml 2021-12-30 19:17:11 +08:00
老竭力
3fc00f8da7 Update casa.yml 2021-12-30 19:13:40 +08:00
老竭力
6e39fe5f8c Update casa.yml 2021-12-30 19:04:37 +08:00
老竭力
20c240a123 Update casa.yml 2021-12-30 19:00:11 +08:00
老竭力
3ea9fc0de0 Update casa.yml 2021-12-30 18:52:37 +08:00
老竭力
b80b08ef07 Update casa.yml 2021-12-30 18:50:45 +08:00
老竭力
505af8d101 Update casa.yml 2021-12-30 18:46:17 +08:00
老竭力
ae35a6d291 Update casa.yml 2021-12-30 18:44:07 +08:00
John Guan
2b95c07a47 Update casa.yml 2021-12-30 18:16:19 +08:00
John Guan
27a011e715 Update casa.yml 2021-12-30 18:01:01 +08:00
link
476831a12f Merge pull request #65 from IceWhaleTech/dev
update action system
2021-12-30 16:59:05 +08:00
link
9675eff69e update action system 2021-12-30 16:58:24 +08:00
link
85a044246e Merge pull request #64 from IceWhaleTech/dev
update action system
2021-12-30 16:53:32 +08:00
link
5c41fbcf3d update action system 2021-12-30 16:52:58 +08:00
link
6baab7a525 Merge pull request #63 from IceWhaleTech/dev
update action system
2021-12-30 16:42:39 +08:00
link
ab3b5a9077 update action system 2021-12-30 16:41:16 +08:00
link
5811c271b2 Merge pull request #62 from IceWhaleTech/dev
update web
2021-12-30 16:20:50 +08:00
link
cf5387346d update web 2021-12-30 16:20:30 +08:00
29 changed files with 2099 additions and 479 deletions

View File

@@ -63,7 +63,7 @@ jobs:
# git clone $REPO_URL -b $REPO_BRANCH --recursive casa
# ln -sf /workdir/casa $GITHUB_WORKSPACE/casa
# ls
- name: Set enviroment for github-release
run: |
@@ -76,7 +76,7 @@ jobs:
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Build frontend with nodejs and yarn
run: |
cd UI
@@ -90,7 +90,7 @@ jobs:
- name: Build with xgo
uses: crazy-max/ghaction-xgo@v1
with:
xgo_version: latest
xgo_version: v0.7.5
go_version: ${{ matrix.go_version }}
dest: build
prefix: casa

2
UI

Submodule UI updated: f3088b6354...8146d1f4cb

View File

@@ -21,12 +21,46 @@ type LSBLKModel struct {
Health string `json:"health"`
HotPlug bool `json:"hotplug"`
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"`
//详情特有
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"`
}
type Storage struct {
Name string `json:"name"`
MountPoint string `json:"mountpoint"`
Size string `json:"size"`
Avail string `json:"avail"` //可用空间
Type string `json:"type"`
CreatedAt int64 `json:"create_at"`
Path string `json:"path"`
DriveName string `json:"drive_name"`
}
type Summary struct {
Size uint64 `json:"size"`
Avail uint64 `json:"avail"` //可用空间
Health bool `json:"health"`
Used uint64 `json:"used"`
}

69
model/smartctl_model.go Normal file
View File

@@ -0,0 +1,69 @@
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"`
}

View File

@@ -1,7 +1,10 @@
package model
import "time"
type Path struct {
Name string `json:"name"`
Path string `json:"path"`
IsDir bool `json:"is_dir"`
Name string `json:"name"`
Path string `json:"path"`
IsDir bool `json:"is_dir"`
Date time.Time `json:"date"`
}

View File

@@ -2,9 +2,11 @@ package command
import (
"bufio"
"context"
"fmt"
"io/ioutil"
"os/exec"
"time"
)
func OnlyExec(cmdStr string) {
@@ -85,7 +87,27 @@ func ExecLSBLK() []byte {
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)
fmt.Println("output", string(output))
return nil
}
return output
}
func ExecEnabledSMART(path string) {
exec.Command("smartctl", "-s on", path).Output()
}

View File

@@ -21,6 +21,13 @@ const (
//zerotier
GET_TOKEN_ERROR = 30001
//disk
NAME_NOT_AVAILABLE = 40001
DISK_NEEDS_FORMAT = 40002
DISK_BUSYING = 40003
REMOVE_MOUNT_POINT_ERROR = 40004
FORMAT_ERROR = 40005
//app
UNINSTALL_APP_ERROR = 50001
PULL_IMAGE_ERROR = 50002
@@ -37,34 +44,41 @@ const (
var MsgFlags = map[int]string{
SUCCESS: "ok",
ERROR: "fail",
INVALID_PARAMS: "Invalid params",
ERROR_AUTH_TOKEN: "error auth token",
INVALID_PARAMS: "Parameters Error",
ERROR_AUTH_TOKEN: "Error auth token",
//user
PWD_INVALID: "Password invalid",
PWD_INVALID: "Invalid password",
PWD_IS_EMPTY: "Password is empty",
PWD_INVALID_OLD: "Old Password invalid",
ACCOUNT_LOCK: "Account Lock",
PWD_INVALID_OLD: "Invalid old password",
ACCOUNT_LOCK: "Account is locked",
//system
DIR_ALREADY_EXISTS: "Directory already exists",
DIR_ALREADY_EXISTS: "Folder already exists",
FILE_ALREADY_EXISTS: "File already exists",
FILE_OR_DIR_EXISTS: "File or directory already exists",
FILE_OR_DIR_EXISTS: "File or folder already exists",
PORT_IS_OCCUPIED: "Port is occupied",
//zerotier
GET_TOKEN_ERROR: "Get token error,Please log in to zerotier's official website to confirm whether the account is available",
//app
UNINSTALL_APP_ERROR: "uninstall app error",
PULL_IMAGE_ERROR: "pull image error",
DEVICE_NOT_EXIST: "device not exist",
UNINSTALL_APP_ERROR: "Error uninstalling app",
PULL_IMAGE_ERROR: "Error pulling image",
DEVICE_NOT_EXIST: "Device does not exist",
//disk
NAME_NOT_AVAILABLE: "Name not available",
DISK_NEEDS_FORMAT: "Drive needs to be formatted",
REMOVE_MOUNT_POINT_ERROR: "Failed to remove mount point",
DISK_BUSYING: "Drive is busy",
FORMAT_ERROR: "Formatting failed, please check if the directory is occupied",
//
FILE_DOES_NOT_EXIST: "file does not exist",
FILE_DOES_NOT_EXIST: "File does not exist",
FILE_READ_ERROR: "file read error",
SHORTCUTS_URL_ERROR: "url error",
FILE_READ_ERROR: "File read error",
SHORTCUTS_URL_ERROR: "URL error",
}
//获取错误信息

View File

@@ -3,6 +3,7 @@ package route
import (
"encoding/json"
"encoding/xml"
"fmt"
"strconv"
"time"
@@ -34,10 +35,9 @@ func installSyncthing(appId string) {
m := model.CustomizationPostData{}
var dockerImage string
var dockerImageVersion string
appInfo = service.MyService.OAPI().GetServerAppInfo(appId)
appInfo = service.MyService.OAPI().GetServerAppInfo(appId, "system")
dockerImage = appInfo.Image
dockerImageVersion = appInfo.ImageVersion
if len(appInfo.ImageVersion) == 0 {
dockerImageVersion = "latest"
@@ -84,9 +84,9 @@ func installSyncthing(appId string) {
err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog)
if err != nil {
//pull image error
fmt.Println("pull image error", err, dockerImage, dockerImageVersion)
return
}
for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) {
time.Sleep(time.Second)
}
@@ -101,8 +101,8 @@ func installSyncthing(appId string) {
m.Volumes = appInfo.Volumes
containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
if err != nil {
fmt.Println("container create error", err)
// create container error
return
}
@@ -170,7 +170,7 @@ func checkSystemApp() {
path := ""
for _, i := range paths {
if i.ContainerPath == "/config" {
path = docker.GetDir(v.CustomId, i.Path) + "config.xml"
path = docker.GetDir(v.CustomId, i.Path) + "/config.xml"
for i := 0; i < 10; i++ {
if file.CheckNotExist(path) {
time.Sleep(1 * time.Second)
@@ -197,21 +197,37 @@ func CheckSerialDiskMount() {
list := service.MyService.Disk().LSBLK()
mountPoint := make(map[string]string, len(dbList))
//remount
for _, v := range dbList {
mountPoint[v.Path] = v.MountPoint
}
for _, v := range list {
command.ExecEnabledSMART(v.Path)
if v.Children != nil {
for _, h := range v.Children {
mountPoint[h.MountPoint] = "1"
if len(h.MountPoint) == 0 && len(v.Children) == 1 && h.FsType == "ext4" {
if m, ok := mountPoint[h.Path]; ok {
//mount point check
volume := m
if !file.CheckNotExist(m) {
for i := 0; file.CheckNotExist(volume); i++ {
volume = m + strconv.Itoa(i+1)
}
}
service.MyService.Disk().MountDisk(h.Path, volume)
if volume != m {
ms := model2.SerialDisk{}
ms.Serial = v.Serial
service.MyService.Disk().UpdateMountPoint(ms)
}
}
}
}
}
}
//remount
for _, item := range dbList {
if _, ok := mountPoint[item.MountPoint]; !ok {
service.MyService.Disk().MountDisk(item.Path, item.MountPoint)
}
}
service.MyService.Disk().RemoveLSBLKCache()
command.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AutoRemoveUnuseDir")
}
func Update2_3() {

View File

@@ -33,7 +33,7 @@ func InitRouter() *gin.Engine {
r.GET("/v1/guide/check", v1.GetGuideCheck)
r.GET("/debug", v1.GetSystemConfigDebug)
r.GET("/v1/debug", v1.GetSystemConfigDebug)
//set user
r.POST("/v1/user/setusernamepwd", v1.Set_Name_Pwd)
//get user info
@@ -205,7 +205,7 @@ func InitRouter() *gin.Engine {
v1FileGroup.PUT("/rename", v1.RenamePath)
v1FileGroup.GET("/read", v1.GetFilerContent)
v1FileGroup.POST("/upload", v1.PostFileUpload)
v1FileGroup.GET("/dirpath", v1.DirPath)
v1FileGroup.GET("/catalog", v1.DirPath)
//创建目录
v1FileGroup.POST("/mkdir", v1.MkdirAll)
v1FileGroup.POST("/create", v1.PostCreateFile)
@@ -218,17 +218,23 @@ func InitRouter() *gin.Engine {
v1DiskGroup.Use()
{
v1DiskGroup.GET("/check", v1.GetDiskCheck)
//获取磁盘列表
v1DiskGroup.GET("/list", v1.GetPlugInDisk)
v1DiskGroup.GET("/list", v1.GetDiskList)
//获取磁盘详情
v1DiskGroup.GET("/info", v1.GetDiskInfo)
//格式化磁盘
//format storage
v1DiskGroup.POST("/format", v1.FormatDisk)
//添加分区
v1DiskGroup.POST("/part", v1.AddPartition)
// add storage
v1DiskGroup.POST("/storage", v1.AddPartition)
//mount SATA disk
v1DiskGroup.POST("/mount", v1.PostMountDisk)
//umount sata disk
v1DiskGroup.POST("/umount", v1.PostDiskUmount)
//获取可以格式化的内容
v1DiskGroup.GET("/type", v1.FormatDiskType)
@@ -236,12 +242,6 @@ func InitRouter() *gin.Engine {
//删除分区
v1DiskGroup.DELETE("/delpart", v1.RemovePartition)
//mount SATA disk
v1DiskGroup.POST("/mount", v1.PostMountDisk)
//umount SATA disk
v1DiskGroup.POST("/umount", v1.PostDiskUmount)
v1DiskGroup.DELETE("/remove/:id", v1.DeleteDisk)
}
v1ShareGroup := v1Group.Group("/share")
v1ShareGroup.Use()

View File

@@ -36,24 +36,24 @@ func AppList(c *gin.Context) {
categoryId := c.DefaultQuery("category_id", "0")
key := c.DefaultQuery("key", "")
recommend, list, community := service.MyService.OAPI().GetServerList(index, size, t, categoryId, key)
for i := 0; i < len(recommend); i++ {
ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion)
if ct != nil {
list[i].State = ct.State
}
}
for i := 0; i < len(list); i++ {
ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
if ct != nil {
list[i].State = ct.State
}
}
for i := 0; i < len(community); i++ {
ct, _ := service.MyService.Docker().DockerListByImage(community[i].Image, community[i].ImageVersion)
if ct != nil {
list[i].State = ct.State
}
}
// for i := 0; i < len(recommend); i++ {
// ct, _ := service.MyService.Docker().DockerListByImage(recommend[i].Image, recommend[i].ImageVersion)
// if ct != nil {
// recommend[i].State = ct.State
// }
// }
// for i := 0; i < len(list); i++ {
// ct, _ := service.MyService.Docker().DockerListByImage(list[i].Image, list[i].ImageVersion)
// if ct != nil {
// list[i].State = ct.State
// }
// }
// for i := 0; i < len(community); i++ {
// ct, _ := service.MyService.Docker().DockerListByImage(community[i].Image, community[i].ImageVersion)
// if ct != nil {
// community[i].State = ct.State
// }
// }
data := make(map[string]interface{}, 3)
data["recommend"] = recommend
data["list"] = list
@@ -137,7 +137,7 @@ func AppUsageList(c *gin.Context) {
func AppInfo(c *gin.Context) {
id := c.Param("id")
info := service.MyService.OAPI().GetServerAppInfo(id)
info := service.MyService.OAPI().GetServerAppInfo(id, "")
if info.NetworkModel != "host" {
for i := 0; i < len(info.Ports); i++ {
if p, _ := strconv.Atoi(info.Ports[i].ContainerPort); port2.IsPortAvailable(p, info.Ports[i].Protocol) {

View File

@@ -2,9 +2,14 @@ package v1
import (
"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"
@@ -12,18 +17,115 @@ import (
"github.com/shirou/gopsutil/v3/disk"
)
// @Summary 获取磁盘列表
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 GetPlugInDisk(c *gin.Context) {
func GetDiskList(c *gin.Context) {
list := service.MyService.Disk().LSBLK()
dbList := service.MyService.Disk().GetSerialAll()
part := make(map[string]int64, len(dbList))
for _, v := range dbList {
part[v.MountPoint] = v.CreatedAt
}
findSystem := 0
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: list})
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 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" {
temp := service.MyService.Disk().SmartCTL(list[i].Path)
if reflect.DeepEqual(temp, model.SmartctlA{}) {
continue
}
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
@@ -60,25 +162,46 @@ func GetDiskInfo(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: m})
}
// @Summary format disk
// @Summary format storage
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "for example /dev/sda1"
// @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")
t := c.PostForm("type")
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
}
service.MyService.Disk().FormatDisk(path, t)
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)})
}
@@ -115,23 +238,65 @@ func RemovePartition(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
// @Summary serial number
// @Summary add storage
// @Produce application/json
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "磁盘路径 例如/dev/sda"
// @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/addpart [post]
// @Router /disk/storage [post]
func AddPartition(c *gin.Context) {
name := c.PostForm("name")
path := c.PostForm("path")
serial := c.PostForm("serial")
if len(path) == 0 || len(serial) == 0 {
format, _ := strconv.ParseBool(c.PostForm("format"))
if len(name) == 0 || len(path) == 0 || len(serial) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err.INVALID_PARAMS, Message: oasis_err.GetMsg(oasis_err.INVALID_PARAMS)})
return
}
service.MyService.Disk().AddPartition(path)
if _, ok := diskMap[serial]; 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[serial] = "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, serial)
return
}
} else {
service.MyService.Disk().AddPartition(path)
}
mountPath := "/DATA/" + name
service.MyService.Disk().MountDisk(path, mountPath)
m := model2.SerialDisk{}
m.MountPoint = mountPath
m.Path = path + "1"
m.Serial = serial
m.State = 0
m.CreatedAt = time.Now().Unix()
service.MyService.Disk().SaveMountPoint(m)
//mount dir
service.MyService.Disk().MountDisk(path+"1", mountPath)
service.MyService.Disk().RemoveLSBLKCache()
delete(diskMap, serial)
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
@@ -149,7 +314,7 @@ func PostMountDisk(c *gin.Context) {
path := c.PostForm("path")
serial := c.PostForm("serial")
mountPath := "/mnt/volume"
mountPath := "/DATA/volume"
var list = service.MyService.Disk().GetSerialAll()
var pathMapList = make(map[string]string, len(list))
for _, v := range list {
@@ -165,13 +330,13 @@ func PostMountDisk(c *gin.Context) {
//mount dir
service.MyService.Disk().MountDisk(path, mountPath)
//save to data
m := model2.SerialDisk{}
m.MountPoint = mountPath
m.Path = path
m.Serial = serial
m.State = 0
service.MyService.Disk().SaveMountPoint(m)
//service.MyService.Disk().SaveMountPoint(m)
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS)})
}
@@ -180,19 +345,35 @@ func PostMountDisk(c *gin.Context) {
// @Accept multipart/form-data
// @Tags disk
// @Security ApiKeyAuth
// @Param path formData string true "for example: /dev/sda1"
// @Param mount_point formData string true "for example: /mnt/volume1"
// @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("mount_point")
service.MyService.Disk().UmountPointAndRemoveDir(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)})
}

View File

@@ -174,7 +174,7 @@ func InstallApp(c *gin.Context) {
dockerImageVersion = "latest"
}
if m.Origin != "custom" {
appInfo = service.MyService.OAPI().GetServerAppInfo(appId)
appInfo = service.MyService.OAPI().GetServerAppInfo(appId, "")
} else {

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"os"
"reflect"
"strconv"
"strings"
"time"
@@ -107,9 +108,33 @@ func GetSystemConfigDebug(c *gin.Context) {
array := service.MyService.System().GetSystemConfigDebug()
disk := service.MyService.ZiMa().GetDiskInfo()
array = append(array, fmt.Sprintf("disk,total:%v,used:%v,UsedPercent:%v", disk.Total>>20, disk.Used>>20, disk.UsedPercent))
sys := service.MyService.ZiMa().GetSysInfo()
//todo 准备sync需要显示的数据(镜像,容器)
var systemAppStatus string
images := service.MyService.Docker().IsExistImage("linuxserver/syncthing")
systemAppStatus += "Sync img: " + strconv.FormatBool(images) + "\n\t"
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: array})
list := service.MyService.App().GetSystemAppList()
for _, v := range *list {
systemAppStatus += v.Image + ",\n\t"
}
systemAppStatus += "Sync Key length: " + strconv.Itoa(len(config.SystemConfigInfo.SyncKey))
var bugContent string = fmt.Sprintf(`
- OS: %s
- CasaOS Version: %s
- Disk Total: %v
- Disk Used: %v
- Sync State: %s
- System Info: %s
- Browser: $Browser$
- Version: $Version$
`, sys.OS, types.CURRENTVERSION, disk.Total>>20, disk.Used>>20, systemAppStatus, array)
// array = append(array, fmt.Sprintf("disk,total:%v,used:%v,UsedPercent:%v", disk.Total>>20, disk.Used>>20, disk.UsedPercent))
c.JSON(http.StatusOK, model.Result{Success: oasis_err.SUCCESS, Message: oasis_err.GetMsg(oasis_err.SUCCESS), Data: bugContent})
}
func Sys(c *gin.Context) {
service.DockerPull()
@@ -237,7 +262,56 @@ func Info(c *gin.Context) {
var data = make(map[string]interface{}, 5)
list := service.MyService.Disk().LSBLK()
data["disk"] = list
summary := model.Summary{}
healthy := true
findSystem := 0
for i := 0; i < len(list); i++ {
if len(list[i].Children) > 0 && findSystem == 0 {
for j := 0; j < len(list[i].Children); j++ {
if list[i].Children[j].MountPoint == "/" {
s, _ := strconv.ParseUint(list[i].Children[j].FSSize, 10, 64)
a, _ := strconv.ParseUint(list[i].Children[j].FSAvail, 10, 64)
u, _ := strconv.ParseUint(list[i].Children[j].FSUsed, 10, 64)
summary.Size += s
summary.Avail += a
summary.Used += u
findSystem = 1
break
}
}
}
if findSystem == 1 {
findSystem += 1
continue
}
if list[i].Tran == "sata" {
temp := service.MyService.Disk().SmartCTL(list[i].Path)
if reflect.DeepEqual(temp, model.SmartctlA{}) {
continue
}
//list[i].Temperature = temp.Temperature.Current
if !temp.SmartStatus.Passed {
healthy = false
}
if len(list[i].Children) > 0 {
for _, v := range list[i].Children {
s, _ := strconv.ParseUint(v.FSSize, 10, 64)
a, _ := strconv.ParseUint(v.FSAvail, 10, 64)
u, _ := strconv.ParseUint(v.FSUsed, 10, 64)
summary.Size += s
summary.Avail += a
summary.Used += u
}
}
}
}
summary.Health = healthy
data["disk"] = summary
cpu := service.MyService.ZiMa().GetCpuPercent()
num := service.MyService.ZiMa().GetCpuCoreNum()
cpuData := make(map[string]interface{})

View File

@@ -16,7 +16,7 @@ type CasaService interface {
GetServerList(index, size, tp, categoryId, key string) (recommend, list, community []model.ServerAppList)
GetServerCategoryList() []model.ServerCategoryList
GetTaskList(size int) []model2.TaskDBModel
GetServerAppInfo(id string) model.ServerAppList
GetServerAppInfo(id, t string) model.ServerAppList
ShareAppFile(body []byte) string
}
@@ -88,13 +88,12 @@ func (o *casaService) GetServerCategoryList() []model.ServerCategoryList {
return list
}
func (o *casaService) GetServerAppInfo(id string) model.ServerAppList {
func (o *casaService) GetServerAppInfo(id, t string) model.ServerAppList {
head := make(map[string]string)
head["Authorization"] = GetToken()
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/info/"+id, head)
infoS := httper2.Get(config.ServerInfo.ServerApi+"/v2/app/info/"+id+"?t="+t, head)
info := model.ServerAppList{}
json2.Unmarshal([]byte(gjson.Get(infoS, "data").String()), &info)

View File

@@ -3,6 +3,7 @@ package service
import (
json2 "encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
"time"
@@ -20,8 +21,9 @@ import (
type DiskService interface {
GetPlugInDisk() []string
LSBLK() []model.LSBLKModel
FormatDisk(path, format string) string
UmountPointAndRemoveDir(path string) string
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
@@ -31,30 +33,60 @@ type DiskService interface {
SaveMountPoint(m model2.SerialDisk)
DeleteMountPoint(path, mountPoint string)
DeleteMount(id string)
UpdateMountPoint(m model2.SerialDisk)
RemoveLSBLKCache()
}
type diskService struct {
log loger2.OLog
db *gorm.DB
}
func (d *diskService) RemoveLSBLKCache() {
key := "system_lsblk"
Cache.Delete(key)
}
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 {
d.log.Error("smartctl exec error,smartctl")
return m
}
err := json2.Unmarshal([]byte(str), &m)
if err != nil {
d.log.Error("json ummarshal error", err)
}
if !reflect.DeepEqual(m, model.SmartctlA{}) {
Cache.Add(key, m, time.Second*10)
}
return m
}
//通过脚本获取外挂磁盘
func (d *diskService) GetPlugInDisk() []string {
return command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetPlugInDisk")
}
//格式化硬盘
func (d *diskService) FormatDisk(path, format string) string {
func (d *diskService) FormatDisk(path, format string) []string {
r := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;FormatDisk " + path + " " + format)
fmt.Println(r)
return ""
return r
}
//移除挂载点,删除目录
func (d *diskService) UmountPointAndRemoveDir(path string) string {
func (d *diskService) UmountPointAndRemoveDir(path string) []string {
r := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;UMountPorintAndRemoveDir " + path)
fmt.Println(r)
return ""
return r
}
//删除分区
@@ -66,8 +98,7 @@ func (d *diskService) DelPartition(path, num string) string {
//part
func (d *diskService) AddPartition(path string) string {
r := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AddPartition " + path)
fmt.Println(r)
command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;AddPartition " + path)
return ""
}
@@ -78,11 +109,10 @@ 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)
}
fmt.Println(path)
fmt.Println(diskInfo)
diskInfo.UsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.UsedPercent), 64)
diskInfo.InodesUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.1f", diskInfo.InodesUsedPercent), 64)
return diskInfo
@@ -91,7 +121,6 @@ func (d *diskService) GetDiskInfoByPath(path string) *disk.UsageStat {
//get disk details
func (d *diskService) LSBLK() []model.LSBLKModel {
key := "system_lsblk"
var n []model.LSBLKModel
if result, ok := Cache.Get(key); ok {
@@ -151,7 +180,7 @@ func (d *diskService) LSBLK() []model.LSBLKModel {
}
}
if len(n) > 0 {
Cache.Add(key, n, time.Second*10)
Cache.Add(key, n, time.Second*100)
}
return n
}
@@ -162,6 +191,7 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
d.log.Error("lsblk exec error,str")
return model.LSBLKModel{}
}
var ml []model.LSBLKModel
err := json2.Unmarshal([]byte(gjson.Get(string(str), "blockdevices").String()), &ml)
if err != nil {
@@ -169,9 +199,13 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
d.log.Error("json ummarshal error", err)
return model.LSBLKModel{}
}
//todo 需要判断长度
m := ml[0]
//声明数组
m := model.LSBLKModel{}
if len(ml) > 0 {
m = ml[0]
}
return m
// 下面为计算是否可以继续分区的部分,暂时不需要
chiArr := make(map[string]string)
chiList := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetPartitionSectors " + m.Path)
if len(chiList) == 0 {
@@ -182,7 +216,6 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
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], ",")
@@ -191,13 +224,13 @@ func (d *diskService) GetDiskInfo(path string) model.LSBLKModel {
if m.Children[i].EndSector > maxSector {
maxSector = m.Children[i].EndSector
}
}
diskEndSector := command2.ExecResultStrArray("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;GetDiskSizeAndSectors " + m.Path)
if len(diskEndSector) < 2 {
d.log.Error("diskEndSector length error")
}
diskEndSectorInt, _ := strconv.ParseUint(diskEndSector[len(diskEndSector)-1], 10, 64)
if (diskEndSectorInt-maxSector)*m.MinIO/1024/1024 > 100 {
//添加可以分区情况
@@ -214,9 +247,14 @@ func (d *diskService) MountDisk(path, volume string) {
}
func (d *diskService) SaveMountPoint(m model2.SerialDisk) {
d.db.Where("serial = ?", m.Serial).Delete(&model2.SerialDisk{})
d.db.Create(&m)
}
func (d *diskService) UpdateMountPoint(m model2.SerialDisk) {
d.db.Model(&model2.SerialDisk{}).Where("serial = ?", m.Serial).Update("mount_point", m.MountPoint)
}
func (d *diskService) DeleteMount(id string) {
d.db.Delete(&model2.SerialDisk{}).Where("id = ?", id)
@@ -224,7 +262,7 @@ func (d *diskService) DeleteMount(id string) {
func (d *diskService) DeleteMountPoint(path, mountPoint string) {
d.db.Delete(&model2.SerialDisk{}).Where("path= ? && mount_point = ?", path, mountPoint)
d.db.Where("path = ? AND mount_point = ?", path, mountPoint).Delete(&model2.SerialDisk{})
command2.OnlyExec("source " + config.AppInfo.ProjectPath + "/shell/helper.sh ;do_umount " + path)
}

View File

@@ -7,6 +7,7 @@ type SerialDisk struct {
Path string `json:"path"`
State int `json:"state"`
MountPoint string `json:"mount_point"`
CreatedAt int64 `json:"created_at"`
}
func (p *SerialDisk) TableName() string {

View File

@@ -7,6 +7,7 @@ import (
"runtime"
"strconv"
"strings"
"time"
"github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config"
@@ -86,10 +87,10 @@ func (c *zima) GetDirPath(path string) []model.Path {
if strings.Count(path, "/") > 0 {
for _, l := range ls {
dirs = append(dirs, model.Path{Name: l.Name(), Path: path + "/" + l.Name(), IsDir: l.IsDir()})
dirs = append(dirs, model.Path{Name: l.Name(), Path: path + "/" + l.Name(), IsDir: l.IsDir(), Date: l.ModTime()})
}
} else {
dirs = append(dirs, model.Path{Name: "DATA", Path: "/DATA/", IsDir: true})
dirs = append(dirs, model.Path{Name: "DATA", Path: "/DATA/", IsDir: true, Date: time.Now()})
}
return dirs
}

View File

@@ -9,4 +9,35 @@ version_0_2_3() {
}
# add in v0.2.5
readonly CASA_DEPANDS="curl smartmontools parted fdisk partprobe"
version_0_2_5() {
install_depends "$CASA_DEPANDS"
}
#Install Depends
install_depends() {
((EUID)) && sudo_cmd="sudo"
if [[ ! -x "$(command -v '$1')" ]]; then
show 2 "Install the necessary dependencies: $1"
packagesNeeded=$1
if [ -x "$(command -v apk)" ]; then
$sudo_cmd apk add --no-cache $packagesNeeded
elif [ -x "$(command -v apt-get)" ]; then
$sudo_cmd apt-get -y -q install $packagesNeeded
elif [ -x "$(command -v dnf)" ]; then
$sudo_cmd dnf install $packagesNeeded
elif [ -x "$(command -v zypper)" ]; then
$sudo_cmd zypper install $packagesNeeded
else
show 1 "Package manager not found. You must manually install: $packagesNeeded"
fi
fi
}
version_0_2_3
version_0_2_5

View File

@@ -73,10 +73,8 @@ UMountPorintAndRemoveDir() {
if [[ -z ${MOUNT_POINT} ]]; then
${log} "Warning: ${DEVICE} is not mounted"
else
umount -l ${DEVICE}
${log} "Unmounted ${DEVICE} from ${MOUNT_POINT}"
umount -lf ${DEVICE}
/bin/rmdir "${MOUNT_POINT}"
sed -i.bak "\@${MOUNT_POINT}@d" /var/log/usb-mount.track
fi
}
@@ -89,11 +87,11 @@ FormatDisk() {
elif [ "$2" == "ntfs" ]; then
mkfs.ntfs $1
elif [ "$2" == "ext4" ]; then
mkfs.ext4 -F $1
mkfs.ext4 -m 1 -F $1
elif [ "$2" == "exfat" ]; then
mkfs.exfat $1
else
mkfs.ext4 -F $1
mkfs.ext4 -m 1 -F $1
fi
}
@@ -118,12 +116,10 @@ AddPartition() {
parted -s $1 mkpart primary ext4 0 100%
mkfs.ext4 $11
mkfs.ext4 -m 1 $11
partprobe $1
# mount $11 $2
}
#磁盘类型
@@ -148,14 +144,14 @@ GetDiskHealthState() {
#result bytes
#result sectors
GetDiskSizeAndSectors() {
fdisk $1 -l | grep "/dev/sda:" | awk -F, 'BEGIN {OFS="\n"}{print $2,$3}' | awk '{print $1}'
fdisk $1 -l | grep "$1:" | awk -F, 'BEGIN {OFS="\n"}{print $2,$3}' | awk '{print $1}'
}
#获取磁盘分区数据扇区
#param 磁盘路径 /dev/sda
#result start,end,sectors
GetPartitionSectors() {
fdisk $1 -l | grep "/dev/sda[1-9]" | awk 'BEGIN{OFS=","}{print $1,$2,$3,$4}'
fdisk $1 -l | grep "$1[1-9]" | awk 'BEGIN{OFS=","}{print $1,$2,$3,$4}'
}
#检查没有使用的挂载点删除文件夹

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
# copy to /casaOS/util/shell path
# chmod 755
@@ -30,23 +30,32 @@ do_mount() {
# Figure out a mount point to use
# LABEL=${ID_FS_LABEL}
LABEL=${DEVBASE}
if grep -q " /mnt/casa_${LABEL} " /etc/mtab; then
# Already in use, make a unique one
LABEL+="-${DEVBASE}"
fi
DEV_LABEL="${LABEL}"
# LABEL=${DEVBASE}
# if grep -q " /DATA/USB_${LABEL} " /etc/mtab; then
# # Already in use, make a unique one
# LABEL+="-${DEVBASE}"
# fi
# DEV_LABEL="${LABEL}"
# Use the device name in case the drive doesn't have label
if [ -z ${DEV_LABEL} ]; then
DEV_LABEL="${DEVBASE}"
fi
# # Use the device name in case the drive doesn't have label
# if [ -z ${DEV_LABEL} ]; then
# DEV_LABEL="${DEVBASE}"
# fi
MOUNT_POINT="/mnt/casa_${DEV_LABEL}"
MOUNT_POINT="/DATA/USB_Storage1"
arr=("/DATA/USB_Storage1" "/DATA/USB_Storage2" "/DATA/USB_Storage3" "/DATA/USB_Storage4" "/DATA/USB_Storage5" "/DATA/USB_Storage6" "/DATA/USB_Storage7" "/DATA/USB_Storage8" "/DATA/USB_Storage9" "/DATA/USB_Storage10" "/DATA/USB_Storage11" "/DATA/USB_Storage12")
for folder in ${arr[@]}; do
#如果文件夹不存在,创建文件夹
if [ ! -d "$folder" ]; then
mkdir -p ${folder}
MOUNT_POINT=$folder
break
fi
done
${log} "Mount point: ${MOUNT_POINT}"
mkdir -p ${MOUNT_POINT}
# # Global mount options
# OPTS="rw,relatime"
@@ -84,7 +93,7 @@ do_mount() {
mount -t iso9660 ${DEVICE} ${MOUNT_POINT}
;;
*)
/bin/rmdir "${MOUNT_POINT}"
/bin/rmdir "${MOUNT_POINT}"
exit 0
;;
esac

View File

@@ -1,4 +1,5 @@
package types
const CURRENTVERSION = "0.2.4"
const BODY = "<li>New App Store</li><li>Fix minor bugs</li>"
const CURRENTVERSION = "0.2.6"
const BODY = "<li>Fix a disk that cannot be formatted under certain circumstances</li>"

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -15,7 +15,7 @@
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="/ui/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/@mdi/font@6.2.95/css/materialdesignicons.min.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/@mdi/font@6.5.95/css/materialdesignicons.min.css">
<title>
CasaOS
</title>

View File

@@ -214,7 +214,7 @@ eval("module.exports = __webpack_require__.p + \"img/Account.1bc4a418.png\";\n\n
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/esm/objectSpread2.js\");\n/* harmony import */ var vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vee-validate/dist/rules */ \"./node_modules/vee-validate/dist/rules.js\");\n/* harmony import */ var vee_validate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vee-validate */ \"./node_modules/vee-validate/dist/vee-validate.esm.js\");\n\n\n\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"required\", Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"required\"]), {}, {\n message: \"This field is required\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"email\", Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"email\"]), {}, {\n message: \"This field must be a valid email\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"confirmed\", Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"confirmed\"]), {}, {\n message: \"This field confirmation does not match\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"length\", Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"length\"]), {}, {\n message: \"This field must have 2 options\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"min\", Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_jerry_Desktop_CasaOS_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"min\"]), {}, {\n message: \"This field must have more than {length} characters\"\n}));\n\n//# sourceURL=webpack:///./src/plugins/vee-validate.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/esm/objectSpread2.js\");\n/* harmony import */ var vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vee-validate/dist/rules */ \"./node_modules/vee-validate/dist/rules.js\");\n/* harmony import */ var vee_validate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vee-validate */ \"./node_modules/vee-validate/dist/vee-validate.esm.js\");\n\n\n\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"required\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"required\"]), {}, {\n message: \"This field is required\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"email\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"email\"]), {}, {\n message: \"This field must be a valid email\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"confirmed\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"confirmed\"]), {}, {\n message: \"This field confirmation does not match\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"length\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"length\"]), {}, {\n message: \"This field must have 2 options\"\n}));\nObject(vee_validate__WEBPACK_IMPORTED_MODULE_2__[\"extend\"])(\"min\", Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(Object(_Users_liangjianli_go_CasaOSNew_CasaOS_UI_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__[\"default\"])({}, vee_validate_dist_rules__WEBPACK_IMPORTED_MODULE_1__[\"min\"]), {}, {\n message: \"This field must have more than {length} characters\"\n}));\n\n//# sourceURL=webpack:///./src/plugins/vee-validate.js?");
/***/ })

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long