优化安装界面

This commit is contained in:
marvzhang
2020-03-07 10:28:34 +08:00
parent 215c4a7274
commit 0521cd4b63
11 changed files with 273 additions and 71 deletions

View File

@@ -6,4 +6,5 @@ const (
RpcUninstallDep = "uninstall_dep"
RpcGetDepList = "get_dep_list"
RpcGetInstalledDepList = "get_installed_dep_list"
RpcGetLang = "get_lang"
)

View File

@@ -11,3 +11,10 @@ const (
Nodejs = "node"
Java = "java"
)
const (
InstallStatusNotInstalled = "not-installed"
InstallStatusInstalling = "installing"
InstallStatusInstallingOther = "installing-other"
InstallStatusInstalled = "installed"
)

View File

@@ -20,6 +20,9 @@ type NodeMessage struct {
// 爬虫相关
SpiderId string `json:"spider_id"` //爬虫ID
// 语言相关
Lang Lang `json:"lang"`
// 错误相关
Error string `json:"error"`
}

View File

@@ -19,7 +19,8 @@ type Lang struct {
ExecutableName string `json:"executable_name"`
ExecutablePaths []string `json:"executable_paths"`
DepExecutablePath string `json:"dep_executable_path"`
Installed bool `json:"installed"`
LockPath string `json:"lock_path"`
InstallStatus string `json:"install_status"`
}
type Dependency struct {

View File

@@ -1,5 +1,8 @@
#!/bin/bash
# lock global
touch /tmp/install.lock
# lock
touch /tmp/install-java.lock
@@ -11,3 +14,6 @@ ln -s /usr/bin/java /usr/local/bin/java
# unlock
rm /tmp/install-java.lock
# unlock global
rm /tmp/install.lock

View File

@@ -1,5 +1,8 @@
#!/bin/bash
# lock global
touch /tmp/install.lock
# lock
touch /tmp/install-nodejs.lock
@@ -39,3 +42,6 @@ npm install puppeteer-chromium-resolver crawlab-sdk -g --unsafe-perm=true --regi
# unlock
rm /tmp/install-nodejs.lock
# unlock global
rm /tmp/install.lock

View File

@@ -1,4 +1,4 @@
#/bin/bash
#!/bin/bash
# install node.js
if [ "${CRAWLAB_SERVER_LANG_NODE}" = "Y" ];

View File

@@ -21,6 +21,8 @@ type RpcMessage struct {
Result string `json:"result"`
}
// ========安装语言========
func RpcServerInstallLang(msg RpcMessage) RpcMessage {
lang := GetRpcParam("lang", msg.Params)
if lang == constants.Nodejs {
@@ -34,6 +36,7 @@ func RpcClientInstallLang(nodeId string, lang string) (output string, err error)
params := map[string]string{}
params["lang"] = lang
// 发起 RPC 请求并阻塞,获取服务端数据
data, err := RpcClientFunc(nodeId, constants.RpcInstallLang, params, 600)()
if err != nil {
return
@@ -44,6 +47,41 @@ func RpcClientInstallLang(nodeId string, lang string) (output string, err error)
return
}
// ========./安装语言========
// ========获取语言========
func RpcServerGetLang(msg RpcMessage) RpcMessage {
langName := GetRpcParam("lang", msg.Params)
lang := GetLangFromLangNamePlain(langName)
// 序列化
resultStr, _ := json.Marshal(lang)
msg.Result = string(resultStr)
return msg
}
func RpcClientGetLang(nodeId string, langName string) (lang entity.Lang, err error) {
params := map[string]string{}
params["lang"] = langName
data, err := RpcClientFunc(nodeId, constants.RpcGetLang, params, 10)()
if err != nil {
return
}
// 反序列化结果
if err := json.Unmarshal([]byte(data), &lang); err != nil {
return lang, err
}
return
}
// ========./获取语言========
// ========安装依赖========
func RpcServerInstallDep(msg RpcMessage) RpcMessage {
lang := GetRpcParam("lang", msg.Params)
depName := GetRpcParam("dep_name", msg.Params)
@@ -69,6 +107,10 @@ func RpcClientInstallDep(nodeId string, lang string, depName string) (output str
return
}
// ========./安装依赖========
// ========卸载依赖========
func RpcServerUninstallDep(msg RpcMessage) RpcMessage {
lang := GetRpcParam("lang", msg.Params)
depName := GetRpcParam("dep_name", msg.Params)
@@ -94,6 +136,10 @@ func RpcClientUninstallDep(nodeId string, lang string, depName string) (output s
return
}
// ========./卸载依赖========
// ========获取已安装依赖列表========
func RpcServerGetInstalledDepList(nodeId string, msg RpcMessage) RpcMessage {
lang := GetRpcParam("lang", msg.Params)
if lang == constants.Python {
@@ -125,6 +171,9 @@ func RpcClientGetInstalledDepList(nodeId string, lang string) (list []entity.Dep
return
}
// ========./获取已安装依赖列表========
// RPC 客户端函数
func RpcClientFunc(nodeId string, method string, params map[string]string, timeout int) func() (string, error) {
return func() (result string, err error) {
// 请求ID
@@ -159,10 +208,12 @@ func RpcClientFunc(nodeId string, method string, params map[string]string, timeo
}
}
// 获取 RPC 参数
func GetRpcParam(key string, params map[string]string) string {
return params[key]
}
// Object 转化为 String
func ObjectToString(params interface{}) string {
bytes, _ := json.Marshal(params)
return utils.BytesToString(bytes)
@@ -174,6 +225,7 @@ func StopRpcService() {
IsRpcStopped = true
}
// 初始化 RPC 服务
func InitRpcService() error {
go func() {
for {
@@ -213,6 +265,8 @@ func InitRpcService() error {
replyMsg = RpcServerInstallLang(msg)
} else if msg.Method == constants.RpcGetInstalledDepList {
replyMsg = RpcServerGetInstalledDepList(node.Id.Hex(), msg)
} else if msg.Method == constants.RpcGetLang {
replyMsg = RpcServerGetLang(msg)
} else {
continue
}

View File

@@ -62,19 +62,48 @@ func GetSystemInfo(nodeId string) (sysInfo entity.SystemInfo, err error) {
return
}
func getLangList() []entity.Lang {
list := []entity.Lang{
{
Name: "Python",
ExecutableName: "python",
ExecutablePaths: []string{"/usr/bin/python", "/usr/local/bin/python"},
DepExecutablePath: "/usr/local/bin/pip",
LockPath: "/tmp/install-python.lock",
},
{
Name: "Node.js",
ExecutableName: "node",
ExecutablePaths: []string{"/usr/bin/node", "/usr/local/bin/node"},
DepExecutablePath: "/usr/local/bin/npm",
LockPath: "/tmp/install-nodejs.lock",
},
{
Name: "Java",
ExecutableName: "java",
ExecutablePaths: []string{"/usr/bin/java", "/usr/local/bin/java"},
LockPath: "/tmp/install-java.lock",
},
}
return list
}
// 获取语言列表
func GetLangList(nodeId string) []entity.Lang {
list := []entity.Lang{
{Name: "Python", ExecutableName: "python", ExecutablePaths: []string{"/usr/bin/python", "/usr/local/bin/python"}, DepExecutablePath: "/usr/local/bin/pip"},
{Name: "Node.js", ExecutableName: "node", ExecutablePaths: []string{"/usr/bin/node", "/usr/local/bin/node"}, DepExecutablePath: "/usr/local/bin/npm"},
//{Name: "Java", ExecutableName: "java", ExecutablePaths: []string{"/usr/bin/java", "/usr/local/bin/java"}},
}
list := getLangList()
for i, lang := range list {
list[i].Installed = IsInstalledLang(nodeId, lang)
status, _ := GetLangInstallStatus(nodeId, lang)
list[i].InstallStatus = status
}
return list
}
// 获取语言列表
func GetLangListPlain() []entity.Lang {
list := getLangList()
return list
}
// 根据语言名获取语言实例
func GetLangFromLangName(nodeId string, name string) entity.Lang {
langList := GetLangList(nodeId)
@@ -86,6 +115,63 @@ func GetLangFromLangName(nodeId string, name string) entity.Lang {
return entity.Lang{}
}
// 根据语言名获取语言实例,不包含状态
func GetLangFromLangNamePlain(name string) entity.Lang {
langList := GetLangListPlain()
for _, lang := range langList {
if lang.ExecutableName == name {
return lang
}
}
return entity.Lang{}
}
func GetLangInstallStatus(nodeId string, lang entity.Lang) (string, error) {
if IsMasterNode(nodeId) {
lang := GetLangLocal(lang)
return lang.InstallStatus, nil
} else {
lang, err := GetLangRemote(nodeId, lang)
if err != nil {
return "", err
}
return lang.InstallStatus, nil
}
}
func GetLangLocal(lang entity.Lang) entity.Lang{
// 检查是否存在执行路径
for _, p := range lang.ExecutablePaths {
if utils.Exists(p) {
lang.InstallStatus = constants.InstallStatusInstalled
return lang
}
}
// 检查是否正在安装
if utils.Exists(lang.LockPath) {
lang.InstallStatus = constants.InstallStatusInstalling
return lang
}
// 检查其他语言是否在安装
if utils.Exists("/tmp/install.lock") {
lang.InstallStatus = constants.InstallStatusInstallingOther
return lang
}
lang.InstallStatus = constants.InstallStatusNotInstalled
return lang
}
func GetLangRemote(nodeId string, lang entity.Lang) (entity.Lang, error) {
l, err := RpcClientGetLang(nodeId, lang.Name)
if err != nil {
return l, err
}
return l, nil
}
// 是否已安装该依赖
func IsInstalledLang(nodeId string, lang entity.Lang) bool {
sysInfo, err := GetSystemInfo(nodeId)

View File

@@ -38,65 +38,98 @@
<el-tabs v-model="activeTab" @tab-click="onTabChange">
<el-tab-pane v-for="lang in langList" :key="lang.name" :label="lang.name" :name="lang.executable_name"/>
</el-tabs>
<template v-if="activeLang.installed">
<el-table
height="calc(100vh - 280px)"
:data="computedDepList"
:empty-text="depName ? $t('No Data') : $t('Please search dependencies')"
v-loading="loading"
border
>
<el-table-column
:label="$t('Name')"
prop="name"
width="180"
/>
<el-table-column
:label="!isShowInstalled ? $t('Latest Version') : $t('Version')"
prop="version"
width="100"
/>
<el-table-column
v-if="!isShowInstalled"
:label="$t('Description')"
prop="description"
/>
<el-table-column
:label="$t('Action')"
<template v-if="activeLang.install_status === 'installed'">
<template v-if="activeLang.executable_name === 'java'">
<div class="install-wrapper">
<el-button
icon="el-icon-check"
disabled
type="success"
>
{{$t('Installed')}}
</el-button>
</div>
</template>
<template v-else>
<el-table
height="calc(100vh - 280px)"
:data="computedDepList"
:empty-text="depName ? $t('No Data') : $t('Please search dependencies')"
v-loading="loading"
border
>
<template slot-scope="scope">
<el-button
v-if="!scope.row.installed"
v-loading="getDepLoading(scope.row)"
:disabled="getDepLoading(scope.row)"
size="mini"
type="primary"
@click="onClickInstallDep(scope.row)"
>
{{$t('Install')}}
</el-button>
<el-button
v-else
v-loading="getDepLoading(scope.row)"
:disabled="getDepLoading(scope.row)"
size="mini"
type="danger"
@click="onClickUninstallDep(scope.row)"
>
{{$t('Uninstall')}}
</el-button>
</template>
</el-table-column>
</el-table>
<el-table-column
:label="$t('Name')"
prop="name"
width="180"
/>
<el-table-column
:label="!isShowInstalled ? $t('Latest Version') : $t('Version')"
prop="version"
width="100"
/>
<el-table-column
v-if="!isShowInstalled"
:label="$t('Description')"
prop="description"
/>
<el-table-column
:label="$t('Action')"
>
<template slot-scope="scope">
<el-button
v-if="!scope.row.installed"
v-loading="getDepLoading(scope.row)"
:disabled="getDepLoading(scope.row)"
size="mini"
type="primary"
@click="onClickInstallDep(scope.row)"
>
{{$t('Install')}}
</el-button>
<el-button
v-else
v-loading="getDepLoading(scope.row)"
:disabled="getDepLoading(scope.row)"
size="mini"
type="danger"
@click="onClickUninstallDep(scope.row)"
>
{{$t('Uninstall')}}
</el-button>
</template>
</el-table-column>
</el-table>
</template>
</template>
<template v-else>
<template v-else-if="activeLang.install_status === 'installing'">
<div class="install-wrapper">
<h3>{{activeLang.name + $t(' is not installed, do you want to install it?')}}</h3>
<el-button
v-loading="isLoadingInstallLang"
:disabled="isLoadingInstallLang"
icon="el-icon-loading"
disabled
type="warning"
>
{{$t('Installing')}}
</el-button>
</div>
</template>
<template v-else-if="activeLang.install_status === 'installing-other'">
<div class="install-wrapper">
<el-button
loading="el-icon-close"
disabled
type="warning"
>
{{$t('Other language installing')}}
</el-button>
</div>
</template>
<template v-else-if="activeLang.install_status === 'not-installed'">
<div class="install-wrapper">
<h4>{{$t('This language is not installed yet.')}}</h4>
<el-button
icon="el-icon-check"
type="primary"
style="width: 240px;font-weight: bolder;font-size: 18px"
@click="onClickInstallLang"
>
{{$t('Install')}}
@@ -175,6 +208,9 @@ export default {
}
},
async getInstalledDepList () {
if (this.activeLang.install_status !== 'installed') return
if (this.activeLang.name === 'Java') return
this.loading = true
this.installedDepList = []
const res = await this.$request.get(`/nodes/${this.nodeForm._id}/deps/installed`, {
@@ -295,19 +331,17 @@ export default {
const res = await this.$request.get(`/nodes/${id}/langs`)
this.langList = res.data.data
this.activeTab = this.langList[0].executable_name || ''
await this.getInstalledDepList()
setTimeout(() => {
this.getInstalledDepList()
}, 100)
}
}
</script>
<style scoped>
.node-installation >>> .el-button .el-loading-spinner {
margin-top: -13px;
height: 28px;
}
.node-installation >>> .el-button .el-loading-spinner .circular {
width: 28px;
height: 28px;
.node-installation >>> .install-wrapper .el-button {
min-width: 240px;
font-weight: bolder;
font-size: 18px
}
</style>

View File

@@ -346,6 +346,10 @@ export default {
'Executables': '执行文件',
'Latest Version': '最新版本',
'Version': '版本',
'Installed': '已安装',
'Installing': '正在安装',
'Other language installing': '其他语言正在安装',
'This language is not installed yet.': '语言还未安装',
// 弹出框
'Notification': '提示',