mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-26 08:46:28 +08:00
fix: Fix SSH log export exception when logs are empty (#10114)
This commit is contained in:
parent
2e06b78409
commit
99b04e3635
14 changed files with 103 additions and 34 deletions
|
|
@ -2,10 +2,6 @@ package v2
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
|
|
@ -231,7 +227,7 @@ func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
|
|||
// @Summary Export host SSH logs
|
||||
// @Accept json
|
||||
// @Param request body dto.SearchSSHLog true "request"
|
||||
// @Success 200 {object} dto.PageResult
|
||||
// @Success 200 {string} path
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /hosts/ssh/log/export [post]
|
||||
|
|
@ -245,19 +241,7 @@ func (b *BaseApi) ExportSSHLogs(c *gin.Context) {
|
|||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
file, err := os.Open(tmpFile)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = file.Close()
|
||||
_ = os.RemoveAll(tmpFile)
|
||||
}()
|
||||
info, _ := file.Stat()
|
||||
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
|
||||
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
|
||||
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), file)
|
||||
helper.SuccessWithData(c, tmpFile)
|
||||
}
|
||||
|
||||
// @Tags SSH
|
||||
|
|
|
|||
|
|
@ -478,6 +478,9 @@ func (u *SSHService) ExportLog(ctx *gin.Context, req dto.SearchSSHLog) (string,
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(logs) == 0 {
|
||||
return "", buserr.New("ErrRecordNotFound")
|
||||
}
|
||||
tmpFileName := path.Join(global.Dir.TmpDir, "export/ssh-log", fmt.Sprintf("1panel-ssh-log-%s.csv", time.Now().Format(constant.DateTimeSlimLayout)))
|
||||
if _, err := os.Stat(path.Dir(tmpFileName)); err != nil {
|
||||
_ = os.MkdirAll(path.Dir(tmpFileName), constant.DirPerm)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,15 @@ ErrAppVersionDeprecated: "The {{ .name }} application is not compatible with the
|
|||
ErrDockerFailed: "The state of Docker is abnormal, please check the service status"
|
||||
ErrDockerComposeCmdNotFound: "The Docker Compose command does not exist, please install this command on the host machine first"
|
||||
|
||||
#ssh
|
||||
ExportIP: "Login IP"
|
||||
ExportArea: "Location"
|
||||
ExportPort: "Port"
|
||||
ExportAuthMode: "Login Method"
|
||||
ExportUser: "User"
|
||||
ExportStatus: "Login Status"
|
||||
ExportDate: "Time"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: 'This file does not support preview'
|
||||
ErrFileToLarge: 'The file is larger than 10M and cannot be opened'
|
||||
|
|
|
|||
|
|
@ -93,6 +93,15 @@ ErrAppVersionDeprecated: "{{ .name }} アプリケーションは現在の 1Pane
|
|||
ErrDockerFailed: "Docker の状態が異常です。サービス状態を確認してください"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose コマンドは存在しません。ホストマシンにこのコマンドを先にインストールしてください"
|
||||
|
||||
#ssh
|
||||
ExportIP: "ログインIP"
|
||||
ExportArea: "地域"
|
||||
ExportPort: "ポート"
|
||||
ExportAuthMode: "ログイン方式"
|
||||
ExportUser: "ユーザー"
|
||||
ExportStatus: "ログイン状態"
|
||||
ExportDate: "時間"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: 'このファイルはプレビューをサポートしていません'
|
||||
ErrFileToLarge: 'ファイルは 10M より大きいため開けません'
|
||||
|
|
|
|||
|
|
@ -93,6 +93,15 @@ ErrAppVersionDeprecated: "{{ .name }} 응용 프로그램은 현재 1Panel 버
|
|||
ErrDockerFailed: "Docker의 상태가 비정상입니다. 서비스 상태를 확인하세요"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose 명령이 없습니다. 호스트 머신에 먼저 이 명령을 설치하세요"
|
||||
|
||||
#ssh
|
||||
ExportIP: "로그인 IP"
|
||||
ExportArea: "위치"
|
||||
ExportPort: "포트"
|
||||
ExportAuthMode: "로그인 방식"
|
||||
ExportUser: "사용자"
|
||||
ExportStatus: "로그인 상태"
|
||||
ExportDate: "시간"
|
||||
|
||||
#파일
|
||||
ErrFileCanNotRead: '이 파일은 미리보기를 지원하지 않습니다'
|
||||
ErrFileToLarge: '파일이 10M보다 커서 열 수 없습니다'
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ ErrAppVersionDeprecated: "Aplikasi {{ .name }} tidak sesuai dengan versi 1Panel
|
|||
ErrDockerFailed: "Keadaan Docker tidak normal, sila periksa status perkhidmatan"
|
||||
ErrDockerComposeCmdNotFound: "Perintah Docker Compose tidak wujud, sila pasang perintah ini di mesin tuan terlebih dahulu"
|
||||
|
||||
#ssh
|
||||
ExportIP: "IP Log Masuk"
|
||||
ExportArea: "Lokasi"
|
||||
ExportPort: "Port"
|
||||
ExportAuthMode: "Kaedah Log Masuk"
|
||||
ExportUser: "Pengguna"
|
||||
ExportStatus: "Status Log Masuk"
|
||||
ExportDate: "Masa"
|
||||
|
||||
#fail
|
||||
ErrFileCanNotRead: 'Fail ini tidak menyokong pratonton'
|
||||
ErrFileToLarge: 'Fail lebih besar daripada 10M dan tidak boleh dibuka'
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ ErrAppVersionDeprecated: "O aplicativo {{ .name }} não é compatível com a ver
|
|||
ErrDockerFailed: "O estado do Docker está anormal, verifique o status do serviço"
|
||||
ErrDockerComposeCmdNotFound: "O comando Docker Compose não existe, por favor, instale este comando na máquina host primeiro"
|
||||
|
||||
#ssh
|
||||
ExportIP: "IP de Login"
|
||||
ExportArea: "Localização"
|
||||
ExportPort: "Porta"
|
||||
ExportAuthMode: "Método de Login"
|
||||
ExportUser: "Usuário"
|
||||
ExportStatus: "Status de Login"
|
||||
ExportDate: "Hora"
|
||||
|
||||
#arquivo
|
||||
ErrFileCanNotRead: 'Este arquivo não suporta visualização'
|
||||
ErrFileToLarge: 'O arquivo é maior que 10M e não pode ser aberto'
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ ErrAppVersionDeprecated: "Приложение {{ .name }} несовмести
|
|||
ErrDockerFailed: "Состояние Docker аномально, проверьте состояние сервиса"
|
||||
ErrDockerComposeCmdNotFound: "Команда Docker Compose отсутствует, пожалуйста, установите эту команду на хост-машине сначала"
|
||||
|
||||
#ssh
|
||||
ExportIP: "IP входа"
|
||||
ExportArea: "Местоположение"
|
||||
ExportPort: "Порт"
|
||||
ExportAuthMode: "Способ входа"
|
||||
ExportUser: "Пользователь"
|
||||
ExportStatus: "Статус входа"
|
||||
ExportDate: "Время"
|
||||
|
||||
#файл
|
||||
ErrFileCanNotRead: 'Этот файл не поддерживает предварительный просмотр'
|
||||
ErrFileToLarge: 'Файл больше 10 МБ и не может быть открыт'
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ ErrAppVersionDeprecated: "{{ .name }} uygulaması mevcut 1Panel sürümü ile uy
|
|||
ErrDockerFailed: "Docker durumu anormal, lütfen servis durumunu kontrol edin"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose komutu mevcut değil, lütfen önce bu komutu host makinesine yükleyin"
|
||||
|
||||
#ssh
|
||||
ExportIP: "Giriş IP"
|
||||
ExportArea: "Konum"
|
||||
ExportPort: "Port"
|
||||
ExportAuthMode: "Giriş Yöntemi"
|
||||
ExportUser: "Kullanıcı"
|
||||
ExportStatus: "Giriş Durumu"
|
||||
ExportDate: "Zaman"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: 'Bu dosya önizlemeyi desteklemiyor'
|
||||
ErrFileToLarge: 'Dosya 10M'dan büyük ve açılamıyor'
|
||||
|
|
|
|||
|
|
@ -92,6 +92,15 @@ ErrAppVersionDeprecated: "{{ .name }} 應用不適配目前 1Panel 版本,跳
|
|||
ErrDockerFailed: "Docker 狀態異常,請檢查服務狀態"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose 命令不存在,請先在宿主機安裝此命令"
|
||||
|
||||
#ssh
|
||||
ExportIP: "登入IP"
|
||||
ExportArea: "歸屬地"
|
||||
ExportPort: "端口"
|
||||
ExportAuthMode: "登入方式"
|
||||
ExportUser: "使用者"
|
||||
ExportStatus: "登入狀態"
|
||||
ExportDate: "時間"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: '此檔案不支援預覽'
|
||||
ErrFileToLarge: '檔案超過10M,無法開啟'
|
||||
|
|
|
|||
|
|
@ -92,6 +92,15 @@ ErrAppVersionDeprecated: " {{ .name }} 应用不适配当前 1Panel 版本,跳
|
|||
ErrDockerFailed: "Docker 状态异常,请检查服务状态"
|
||||
ErrDockerComposeCmdNotFound: "Docker Compose 命令不存在,请先在宿主机安装此命令"
|
||||
|
||||
#ssh
|
||||
ExportIP: "登录 IP"
|
||||
ExportArea: "归属地"
|
||||
ExportPort: "端口"
|
||||
ExportAuthMode: "登录方式"
|
||||
ExportUser: "用户"
|
||||
ExportStatus: "登录状态"
|
||||
ExportDate: "时间"
|
||||
|
||||
#file
|
||||
ErrFileCanNotRead: "此文件不支持预览"
|
||||
ErrFileToLarge: "文件超过10M,无法打开"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||
)
|
||||
|
||||
func ExportSSHLogs(filename string, logs []dto.SSHHistory) error {
|
||||
|
|
@ -18,7 +19,15 @@ func ExportSSHLogs(filename string, logs []dto.SSHHistory) error {
|
|||
writer := csv.NewWriter(file)
|
||||
defer writer.Flush()
|
||||
|
||||
if err := writer.Write([]string{"IP", "Area", "Port", "AuthMode", "User", "Status", "Date"}); err != nil {
|
||||
if err := writer.Write([]string{
|
||||
i18n.GetMsgByKey("ExportIP"),
|
||||
i18n.GetMsgByKey("ExportArea"),
|
||||
i18n.GetMsgByKey("ExportPort"),
|
||||
i18n.GetMsgByKey("ExportAuthMode"),
|
||||
i18n.GetMsgByKey("ExportUser"),
|
||||
i18n.GetMsgByKey("ExportStatus"),
|
||||
i18n.GetMsgByKey("ExportDate"),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,8 +99,5 @@ export const loadSSHLogs = (params: Host.searchSSHLog) => {
|
|||
return http.post<ResPage<Host.sshHistory>>(`/hosts/ssh/log`, params);
|
||||
};
|
||||
export const exportSSHLogs = (params: Host.searchSSHLog) => {
|
||||
return http.download<BlobPart>('/hosts/ssh/log/export', params, {
|
||||
responseType: 'blob',
|
||||
timeout: TimeoutEnum.T_40S,
|
||||
});
|
||||
return http.post<string>('/hosts/ssh/log/export', params, TimeoutEnum.T_40S);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -89,11 +89,11 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { dateFormat, getDateStr } from '@/utils/util';
|
||||
import { dateFormat, downloadFile } from '@/utils/util';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { exportSSHLogs, loadSSHLogs } from '@/api/modules/host';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import i18n from '@/lang';
|
||||
import { GlobalStore } from '@/store';
|
||||
const globalStore = GlobalStore();
|
||||
|
||||
const loading = ref();
|
||||
const data = ref();
|
||||
|
|
@ -146,14 +146,9 @@ const onSubmitExport = async () => {
|
|||
};
|
||||
await exportSSHLogs(params)
|
||||
.then((res) => {
|
||||
const downloadUrl = window.URL.createObjectURL(new Blob([res]));
|
||||
const a = document.createElement('a');
|
||||
a.style.display = 'none';
|
||||
a.href = downloadUrl;
|
||||
a.download = '1panel-ssh-log-' + getDateStr() + '.csv';
|
||||
const event = new MouseEvent('click');
|
||||
a.dispatchEvent(event);
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
if (res.data) {
|
||||
downloadFile(res.data, globalStore.currentNode);
|
||||
}
|
||||
open.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue