feat: SSH 服务支持开机自启设置 (#2578)

Refs #2225
This commit is contained in:
ssongliu 2023-10-17 17:52:34 +08:00 committed by GitHub
parent a33094d169
commit e9eea9c795
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 118 additions and 36 deletions

View file

@ -3,6 +3,7 @@ package dto
import "time" import "time"
type SSHInfo struct { type SSHInfo struct {
AutoStart bool `json:"authStart"`
Status string `json:"status"` Status string `json:"status"`
Message string `json:"message"` Message string `json:"message"`
Port string `json:"port"` Port string `json:"port"`

View file

@ -45,6 +45,7 @@ func NewISSHService() ISSHService {
func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) { func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
data := dto.SSHInfo{ data := dto.SSHInfo{
AutoStart: true,
Status: constant.StatusEnable, Status: constant.StatusEnable,
Message: "", Message: "",
Port: "22", Port: "22",
@ -67,7 +68,7 @@ func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
data.Status = constant.StatusEnable data.Status = constant.StatusEnable
} }
} }
data.AutoStart, _ = systemctl.IsEnable(serviceName)
sshConf, err := os.ReadFile(sshPath) sshConf, err := os.ReadFile(sshPath)
if err != nil { if err != nil {
data.Message = err.Error() data.Message = err.Error()
@ -98,19 +99,19 @@ func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
} }
func (u *SSHService) OperateSSH(operation string) error { func (u *SSHService) OperateSSH(operation string) error {
if operation == "start" || operation == "stop" || operation == "restart" { serviceName, err := loadServiceName()
serviceName, err := loadServiceName() if err != nil {
if err != nil { return err
return err
}
sudo := cmd.SudoHandleCmd()
stdout, err := cmd.Execf("%s systemctl %s %s", sudo, operation, serviceName)
if err != nil {
return fmt.Errorf("%s %s failed, stdout: %s, err: %v", operation, serviceName, stdout, err)
}
return nil
} }
return fmt.Errorf("not support such operation: %s", operation) sudo := cmd.SudoHandleCmd()
if operation == "enable" || operation == "disable" {
serviceName += ".service"
}
stdout, err := cmd.Execf("%s systemctl %s %s", sudo, operation, serviceName)
if err != nil {
return fmt.Errorf("%s %s failed, stdout: %s, err: %v", operation, serviceName, stdout, err)
}
return nil
} }
func (u *SSHService) Update(key, value string) error { func (u *SSHService) Update(key, value string) error {

View file

@ -2,9 +2,10 @@ package systemctl
import ( import (
"fmt" "fmt"
"github.com/pkg/errors"
"os/exec" "os/exec"
"strings" "strings"
"github.com/pkg/errors"
) )
func RunSystemCtl(args ...string) (string, error) { func RunSystemCtl(args ...string) (string, error) {
@ -24,6 +25,14 @@ func IsActive(serviceName string) (bool, error) {
return out == "active\n", nil return out == "active\n", nil
} }
func IsEnable(serviceName string) (bool, error) {
out, err := RunSystemCtl("is-enabled", serviceName)
if err != nil {
return false, err
}
return out == "enabled\n", nil
}
func IsExist(serviceName string) (bool, error) { func IsExist(serviceName string) (bool, error) {
out, err := RunSystemCtl("list-unit-files") out, err := RunSystemCtl("list-unit-files")
if err != nil { if err != nil {

View file

@ -14818,6 +14818,9 @@ const docTemplate = `{
"dto.SSHInfo": { "dto.SSHInfo": {
"type": "object", "type": "object",
"properties": { "properties": {
"authStart": {
"type": "boolean"
},
"listenAddress": { "listenAddress": {
"type": "string" "type": "string"
}, },
@ -16277,6 +16280,21 @@ const docTemplate = `{
}, },
"showHidden": { "showHidden": {
"type": "boolean" "type": "boolean"
},
"sortBy": {
"type": "string",
"enum": [
"name",
"size",
"modTime"
]
},
"sortOrder": {
"type": "string",
"enum": [
"ascending",
"descending"
]
} }
} }
}, },

View file

@ -14811,6 +14811,9 @@
"dto.SSHInfo": { "dto.SSHInfo": {
"type": "object", "type": "object",
"properties": { "properties": {
"authStart": {
"type": "boolean"
},
"listenAddress": { "listenAddress": {
"type": "string" "type": "string"
}, },
@ -16270,6 +16273,21 @@
}, },
"showHidden": { "showHidden": {
"type": "boolean" "type": "boolean"
},
"sortBy": {
"type": "string",
"enum": [
"name",
"size",
"modTime"
]
},
"sortOrder": {
"type": "string",
"enum": [
"ascending",
"descending"
]
} }
} }
}, },

View file

@ -1861,6 +1861,8 @@ definitions:
type: object type: object
dto.SSHInfo: dto.SSHInfo:
properties: properties:
authStart:
type: boolean
listenAddress: listenAddress:
type: string type: string
message: message:
@ -2832,6 +2834,17 @@ definitions:
type: string type: string
showHidden: showHidden:
type: boolean type: boolean
sortBy:
enum:
- name
- size
- modTime
type: string
sortOrder:
enum:
- ascending
- descending
type: string
type: object type: object
request.FilePathCheck: request.FilePathCheck:
properties: properties:

View file

@ -955,6 +955,9 @@ const message = {
fileHeper: 'Note: 1. Sorting is not supported after searching 2. Folders are not supported by size sorting', fileHeper: 'Note: 1. Sorting is not supported after searching 2. Folders are not supported by size sorting',
}, },
ssh: { ssh: {
autoStart: 'Auto Start',
enable: 'Enable Autostart',
disable: 'Disable Autostart',
sshAlert: sshAlert:
'The list data is sorted based on login time, but please note that changing time zones or other operations may cause deviations in the time of login logs.', 'The list data is sorted based on login time, but please note that changing time zones or other operations may cause deviations in the time of login logs.',
sshOperate: 'Operation [{0}] on the SSH service is performed. Do you want to continue?', sshOperate: 'Operation [{0}] on the SSH service is performed. Do you want to continue?',

View file

@ -919,6 +919,9 @@ const message = {
fileHeper: '注意1.搜尋之後不支援排序 2.依大小排序不支援資料夾', fileHeper: '注意1.搜尋之後不支援排序 2.依大小排序不支援資料夾',
}, },
ssh: { ssh: {
autoStart: '開機自啟',
enable: '設置開機自啟',
disable: '關閉開機自啟',
sshAlert: '列表數據根據登錄時間排序但請註意切換時區或其他操作可能導致登錄日誌的時間出現偏差', sshAlert: '列表數據根據登錄時間排序但請註意切換時區或其他操作可能導致登錄日誌的時間出現偏差',
sshOperate: ' SSH 服務進行 [{0}] 操作是否繼續', sshOperate: ' SSH 服務進行 [{0}] 操作是否繼續',
sshChange: 'SSH 配置修改', sshChange: 'SSH 配置修改',

View file

@ -919,6 +919,9 @@ const message = {
fileHeper: '注意1.搜索之后不支持排序 2.按大小排序不支持文件夹', fileHeper: '注意1.搜索之后不支持排序 2.按大小排序不支持文件夹',
}, },
ssh: { ssh: {
autoStart: '开机自启',
enable: '设置开机自启',
disable: '关闭开机自启',
sshAlert: '列表数据根据登录时间排序但请注意切换时区或其他操作可能导致登录日志的时间出现偏差', sshAlert: '列表数据根据登录时间排序但请注意切换时区或其他操作可能导致登录日志的时间出现偏差',
sshOperate: ' SSH 服务进行 [{0}] 操作是否继续', sshOperate: ' SSH 服务进行 [{0}] 操作是否继续',
sshChange: 'SSH 配置修改', sshChange: 'SSH 配置修改',

View file

@ -22,23 +22,28 @@
</el-tag> </el-tag>
</template> </template>
</el-popover> </el-popover>
<span v-if="form.status === 'Enable'" class="buttons"> <span class="buttons">
<el-button type="primary" @click="onOperate('stop')" link> <el-button v-if="form.status === 'Enable'" type="primary" @click="onOperate('stop')" link>
{{ $t('commons.button.stop') }} {{ $t('commons.button.stop') }}
</el-button> </el-button>
<el-divider direction="vertical" /> <el-button v-if="form.status === 'Disable'" type="primary" @click="onOperate('start')" link>
<el-button type="primary" @click="onOperate('restart')" link>
{{ $t('container.restart') }}
</el-button>
</span>
<span v-if="form.status === 'Disable'" class="buttons">
<el-button type="primary" @click="onOperate('start')" link>
{{ $t('commons.button.start') }} {{ $t('commons.button.start') }}
</el-button> </el-button>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-button type="primary" @click="onOperate('restart')" link> <el-button type="primary" @click="onOperate('restart')" link>
{{ $t('container.restart') }} {{ $t('container.restart') }}
</el-button> </el-button>
<el-divider direction="vertical" />
<el-button type="primary" link>
{{ $t('ssh.autoStart') }}
</el-button>
<el-switch
style="margin-left: 10px"
inactive-value="disable"
active-value="enable"
@change="onOperate(autoStart)"
v-model="autoStart"
/>
</span> </span>
</div> </div>
</el-card> </el-card>
@ -170,6 +175,8 @@ const portRef = ref();
const addressRef = ref(); const addressRef = ref();
const rootsRef = ref(); const rootsRef = ref();
const autoStart = ref('enable');
const sshConf = ref(); const sshConf = ref();
const form = reactive({ const form = reactive({
status: 'enable', status: 'enable',
@ -218,22 +225,28 @@ const onChangeAddress = () => {
}; };
const onOperate = async (operation: string) => { const onOperate = async (operation: string) => {
ElMessageBox.confirm(i18n.global.t('ssh.sshOperate', [i18n.global.t('commons.button.' + operation)]), 'SSH', { let msg = operation === 'enable' || operation === 'disable' ? 'ssh.' : 'commons.button.';
ElMessageBox.confirm(i18n.global.t('ssh.sshOperate', [i18n.global.t(msg + operation)]), 'SSH', {
confirmButtonText: i18n.global.t('commons.button.confirm'), confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'), cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info', type: 'info',
}).then(async () => { })
loading.value = true; .then(async () => {
await operateSSH(operation) loading.value = true;
.then(() => { await operateSSH(operation)
loading.value = false; .then(() => {
MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); loading.value = false;
search(); MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
}) search();
.catch(() => { })
loading.value = false; .catch(() => {
}); autoStart.value = operation === 'enable' ? 'disable' : 'enable';
}); loading.value = false;
});
})
.catch(() => {
autoStart.value = operation === 'enable' ? 'disable' : 'enable';
});
}; };
const onSave = async (formEl: FormInstance | undefined, key: string, value: string) => { const onSave = async (formEl: FormInstance | undefined, key: string, value: string) => {