mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 06:47:20 +08:00
fix: s3fs挂载与卸载
This commit is contained in:
@@ -37,12 +37,12 @@ func (s *App) List(w http.ResponseWriter, r *http.Request) {
|
||||
var s3fsList []Mount
|
||||
list, err := s.settingRepo.Get("s3fs", "[]")
|
||||
if err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
|
||||
return
|
||||
}
|
||||
|
||||
if err = json.Unmarshal([]byte(list), &s3fsList); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -64,36 +64,36 @@ func (s *App) Create(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// 检查下地域节点中是否包含bucket,如果包含了,肯定是错误的
|
||||
if strings.Contains(req.URL, req.Bucket) {
|
||||
service.Error(w, http.StatusUnprocessableEntity, "地域节点不能包含 Bucket 名称")
|
||||
service.Error(w, http.StatusUnprocessableEntity, "endpoint should not contain bucket")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查挂载目录是否存在且为空
|
||||
if !io.Exists(req.Path) {
|
||||
if err = io.Mkdir(req.Path, 0755); err != nil {
|
||||
service.Error(w, http.StatusUnprocessableEntity, "挂载目录创建失败")
|
||||
service.Error(w, http.StatusUnprocessableEntity, "failed to create mount path: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if !io.Empty(req.Path) {
|
||||
service.Error(w, http.StatusUnprocessableEntity, "挂载目录必须为空")
|
||||
service.Error(w, http.StatusUnprocessableEntity, "mount path is not empty")
|
||||
return
|
||||
}
|
||||
|
||||
var s3fsList []Mount
|
||||
list, err := s.settingRepo.Get("s3fs", "[]")
|
||||
if err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal([]byte(list), &s3fsList); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
|
||||
return
|
||||
}
|
||||
|
||||
for _, s := range s3fsList {
|
||||
if s.Path == req.Path {
|
||||
service.Error(w, http.StatusUnprocessableEntity, "路径已存在")
|
||||
service.Error(w, http.StatusUnprocessableEntity, "mount path already exists")
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -101,21 +101,21 @@ func (s *App) Create(w http.ResponseWriter, r *http.Request) {
|
||||
id := time.Now().UnixMicro()
|
||||
password := req.Ak + ":" + req.Sk
|
||||
if err = io.Write("/etc/passwd-s3fs-"+cast.ToString(id), password, 0600); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "添加 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to create passwd file: %v", err)
|
||||
return
|
||||
}
|
||||
if _, err = shell.Execf(`echo 's3fs#%s %s fuse _netdev,allow_other,nonempty,url=%s,passwd_file=/etc/passwd-s3fs-%s 0 0' >> /etc/fstab`, req.Bucket, req.Path, req.URL, cast.ToString(id)); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
if mountCheck, err := shell.Execf("mount -a"); err != nil {
|
||||
if _, err = shell.Execf("mount -a"); err != nil {
|
||||
_, _ = shell.Execf(`sed -i 's@^s3fs#%s\s%s.*$@@g' /etc/fstab`, req.Bucket, req.Path)
|
||||
service.Error(w, http.StatusInternalServerError, "/etc/fstab有误:%s", mountCheck)
|
||||
service.Error(w, http.StatusInternalServerError, "invalid /etc/fstab: %v", err)
|
||||
return
|
||||
}
|
||||
if _, err := shell.Execf(`df -h | grep '%s'`, req.Path); err != nil {
|
||||
if _, err = shell.Execf(`df -h | grep '%s'`, req.Path); err != nil {
|
||||
_, _ = shell.Execf(`sed -i 's@^s3fs#%s\s%s.*$@@g' /etc/fstab`, req.Bucket, req.Path)
|
||||
service.Error(w, http.StatusInternalServerError, "挂载失败,请检查配置是否正确")
|
||||
service.Error(w, http.StatusInternalServerError, "mount failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -127,12 +127,12 @@ func (s *App) Create(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
encoded, err := json.Marshal(s3fsList)
|
||||
if err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "添加 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to add s3fs mount")
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.settingRepo.Set("s3fs", string(encoded)); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "添加 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to add s3fs mount")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -150,11 +150,11 @@ func (s *App) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
var s3fsList []Mount
|
||||
list, err := s.settingRepo.Get("s3fs", "[]")
|
||||
if err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal([]byte(list), &s3fsList); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "获取 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to get s3fs list")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -166,15 +166,15 @@ func (s *App) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
if mount.ID == 0 {
|
||||
service.Error(w, http.StatusUnprocessableEntity, "挂载不存在")
|
||||
service.Error(w, http.StatusUnprocessableEntity, "mount not found")
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = shell.Execf(`fusermount -u '%s'`, mount.Path); err != nil {
|
||||
if _, err = shell.Execf(`fusermount -uz '%s'`, mount.Path); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
if _, err = shell.Execf(`umount '%s'`, mount.Path); err != nil {
|
||||
if _, err = shell.Execf(`umount -lfq '%s'`, mount.Path); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
@@ -182,8 +182,8 @@ func (s *App) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
service.Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
if mountCheck, err := shell.Execf("mount -a"); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "/etc/fstab有误:%s", mountCheck)
|
||||
if _, err = shell.Execf("mount -a"); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "invalid /etc/fstab: %v", err)
|
||||
return
|
||||
}
|
||||
if err = io.Remove("/etc/passwd-s3fs-" + cast.ToString(mount.ID)); err != nil {
|
||||
@@ -199,11 +199,11 @@ func (s *App) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
encoded, err := json.Marshal(newS3fsList)
|
||||
if err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "删除 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to delete s3fs mount")
|
||||
return
|
||||
}
|
||||
if err = s.settingRepo.Set("s3fs", string(encoded)); err != nil {
|
||||
service.Error(w, http.StatusInternalServerError, "删除 S3fs 挂载失败")
|
||||
service.Error(w, http.StatusInternalServerError, "failed to delete s3fs mount")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"build": "run-s gen-auto-import type-check build-only copy",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build --force",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"lint": "run-s gen-auto-import lint-only",
|
||||
"lint-only": "eslint . --fix",
|
||||
"format": "prettier --write src/",
|
||||
@@ -27,7 +27,7 @@
|
||||
"@fontsource-variable/jetbrains-mono": "^5.1.1",
|
||||
"@guolao/vue-monaco-editor": "^1.5.4",
|
||||
"@vue-js-cron/naive-ui": "^2.0.9",
|
||||
"@vueuse/core": "^12.0.0",
|
||||
"@vueuse/core": "^12.2.0",
|
||||
"@xterm/addon-attach": "^0.11.0",
|
||||
"@xterm/addon-clipboard": "^0.1.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
@@ -35,60 +35,60 @@
|
||||
"@xterm/addon-web-links": "^0.11.0",
|
||||
"@xterm/addon-webgl": "^0.18.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"alova": "^3.2.4",
|
||||
"axios": "^1.7.7",
|
||||
"alova": "^3.2.7",
|
||||
"axios": "^1.7.9",
|
||||
"cronstrue": "^2.52.0",
|
||||
"echarts": "^5.5.1",
|
||||
"echarts": "^5.6.0",
|
||||
"install": "^0.13.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"luxon": "^3.5.0",
|
||||
"marked": "^15.0.2",
|
||||
"marked": "^15.0.4",
|
||||
"mitt": "^3.0.1",
|
||||
"node-forge": "^1.3.1",
|
||||
"pinia": "^2.2.6",
|
||||
"pinia-plugin-persistedstate": "^4.1.3",
|
||||
"pinia": "^2.3.0",
|
||||
"pinia-plugin-persistedstate": "^4.2.0",
|
||||
"remove": "^0.1.5",
|
||||
"vue": "^3.5.13",
|
||||
"vue-echarts": "^7.0.3",
|
||||
"vue-i18n": "^11.0.0",
|
||||
"vue-router": "^4.4.5"
|
||||
"vue-i18n": "^11.0.1",
|
||||
"vue-router": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "^2.2.275",
|
||||
"@iconify/vue": "^4.1.2",
|
||||
"@iconify/json": "^2.2.290",
|
||||
"@iconify/vue": "^4.2.0",
|
||||
"@rushstack/eslint-patch": "^1.10.4",
|
||||
"@tsconfig/node22": "^22.0.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.9.1",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/node-forge": "^1.3.11",
|
||||
"@unocss/eslint-config": "^0.65.0",
|
||||
"@vitejs/plugin-vue": "^5.2.0",
|
||||
"@unocss/eslint-config": "^0.65.3",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vue/eslint-config-prettier": "^10.1.0",
|
||||
"@vue/eslint-config-typescript": "^14.1.3",
|
||||
"@vue/eslint-config-typescript": "^14.2.0",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"colord": "^2.9.3",
|
||||
"cpx2": "^8.0.0",
|
||||
"eslint": "^9.15.0",
|
||||
"eslint-plugin-vue": "^9.31.0",
|
||||
"md-editor-v3": "^5.0.2",
|
||||
"monaco-editor": "^0.52.0",
|
||||
"naive-ui": "^2.40.1",
|
||||
"npm-run-all2": "^7.0.1",
|
||||
"prettier": "^3.3.3",
|
||||
"eslint": "^9.17.0",
|
||||
"eslint-plugin-vue": "^9.32.0",
|
||||
"md-editor-v3": "^5.1.1",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"naive-ui": "^2.40.4",
|
||||
"npm-run-all2": "^7.0.2",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"sass": "^1.81.0",
|
||||
"sass": "^1.83.0",
|
||||
"tsx": "^4.19.2",
|
||||
"typescript": "5.7.2",
|
||||
"unocss": "^0.65.0",
|
||||
"unocss": "^0.65.3",
|
||||
"unplugin-auto-import": "^0.19.0",
|
||||
"unplugin-icons": "^0.22.0",
|
||||
"unplugin-vue-components": "^0.28.0",
|
||||
"vite": "^6.0.0",
|
||||
"vite": "^6.0.6",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite-plugin-mock": "^3.0.2",
|
||||
"vite-plugin-static-copy": "^2.1.0",
|
||||
"vite-plugin-vue-devtools": "^7.6.4",
|
||||
"vue-tsc": "^2.1.10"
|
||||
"vite-plugin-static-copy": "^2.2.0",
|
||||
"vite-plugin-vue-devtools": "^7.6.8",
|
||||
"vue-tsc": "^2.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
674
web/pnpm-lock.yaml
generated
674
web/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -9,5 +9,6 @@ export default {
|
||||
// 添加
|
||||
add: (data: any): Promise<AxiosResponse<any>> => request.post('/apps/s3fs/mounts', data),
|
||||
// 删除
|
||||
delete: (id: number): Promise<AxiosResponse<any>> => request.post('/apps/s3fs/mounts', { id })
|
||||
delete: (id: number): Promise<AxiosResponse<any>> =>
|
||||
request.delete('/apps/s3fs/mounts', { data: { id } })
|
||||
}
|
||||
|
||||
@@ -139,12 +139,12 @@ onMounted(() => {
|
||||
<n-modal v-model:show="addMountModal" title="添加挂载">
|
||||
<n-card closable @close="() => (addMountModal = false)" title="添加挂载" style="width: 60vw">
|
||||
<n-form :model="addMountModel">
|
||||
<n-form-item path="bucket" label="Bucket(腾讯云COS为: xxxx-用户ID)">
|
||||
<n-form-item path="bucket" label="Bucket">
|
||||
<n-input
|
||||
v-model:value="addMountModel.bucket"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入Bucket名字"
|
||||
placeholder="输入 Bucket 名(COS 为: xxxx-ID)"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="ak" label="AK">
|
||||
@@ -152,7 +152,7 @@ onMounted(() => {
|
||||
v-model:value="addMountModel.ak"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入AK密钥"
|
||||
placeholder="输入 AK 密钥"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="sk" label="SK">
|
||||
@@ -160,7 +160,7 @@ onMounted(() => {
|
||||
v-model:value="addMountModel.sk"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入SK密钥"
|
||||
placeholder="输入 SK 密钥"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="url" label="地域节点">
|
||||
@@ -168,7 +168,7 @@ onMounted(() => {
|
||||
v-model:value="addMountModel.url"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入地域节点的 URL"
|
||||
placeholder="输入地域节点的完整 URL(https://oss-cn-beijing.aliyuncs.com)"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="path" label="挂载目录">
|
||||
@@ -176,7 +176,7 @@ onMounted(() => {
|
||||
v-model:value="addMountModel.path"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入挂载目录"
|
||||
placeholder="输入挂载目录(/oss)"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
Reference in New Issue
Block a user