在节点手动安装页显示节点安装文件下载链接

This commit is contained in:
刘祥超
2022-09-18 12:38:32 +08:00
parent fef99a0023
commit 70d84acf76
7 changed files with 223 additions and 8 deletions

View File

@@ -5,6 +5,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -27,7 +28,7 @@ func (this *CreateNodeAction) Init() {
func (this *CreateNodeAction) RunGet(params struct {
ClusterId int64
}) {
leftMenuItems := []maps.Map{
var leftMenuItems = []maps.Map{
{
"name": "单个创建",
"url": "/clusters/cluster/createNode?clusterId=" + strconv.FormatInt(params.ClusterId, 10),
@@ -47,7 +48,7 @@ func (this *CreateNodeAction) RunGet(params struct {
this.ErrorPage(err)
return
}
dnsRouteMaps := []maps.Map{}
var dnsRouteMaps = []maps.Map{}
this.Data["dnsDomainId"] = 0
if clusterDNSResp.Domain != nil {
domainId := clusterDNSResp.Domain.Id
@@ -76,8 +77,8 @@ func (this *CreateNodeAction) RunGet(params struct {
this.ErrorPage(err)
return
}
apiNodes := apiNodesResp.ApiNodes
apiEndpoints := []string{}
var apiNodes = apiNodesResp.ApiNodes
var apiEndpoints = []string{}
for _, apiNode := range apiNodes {
if !apiNode.IsOn {
continue
@@ -86,6 +87,9 @@ func (this *CreateNodeAction) RunGet(params struct {
}
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
// 安装文件下载
this.Data["installerFiles"] = clusterutils.ListInstallerFiles()
this.Show()
}

View File

@@ -0,0 +1,70 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package cluster
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/types"
"io"
"net/http"
"os"
"regexp"
)
type DownloadInstallerAction struct {
actionutils.ParentAction
}
func (this *DownloadInstallerAction) Init() {
this.Nav("", "", "")
}
func (this *DownloadInstallerAction) RunGet(params struct {
Name string
}) {
if len(params.Name) == 0 {
this.ResponseWriter.WriteHeader(http.StatusNotFound)
this.WriteString("file not found")
return
}
// 检查文件名
// 以防止路径穿越等风险
if !regexp.MustCompile(`^[a-zA-Z0-9.-]+$`).MatchString(params.Name) {
this.ResponseWriter.WriteHeader(http.StatusNotFound)
this.WriteString("file not found")
return
}
var zipFile = Tea.Root + "/edge-api/deploy/" + params.Name
fp, err := os.OpenFile(zipFile, os.O_RDWR, 0444)
if err != nil {
if os.IsNotExist(err) {
this.ResponseWriter.WriteHeader(http.StatusNotFound)
this.WriteString("file not found")
return
}
this.ResponseWriter.WriteHeader(http.StatusInternalServerError)
this.WriteString("file can not be opened")
return
}
defer func() {
_ = fp.Close()
}()
stat, err := fp.Stat()
if err != nil {
this.ResponseWriter.WriteHeader(http.StatusInternalServerError)
this.WriteString("file can not be opened")
return
}
this.AddHeader("Content-Disposition", "attachment; filename=\""+params.Name+"\";")
this.AddHeader("Content-Type", "application/zip")
this.AddHeader("Content-Length", types.String(stat.Size()))
_, _ = io.Copy(this.ResponseWriter, fp)
}

View File

@@ -35,6 +35,7 @@ func init() {
GetPost("/updateNodeSSH", new(UpdateNodeSSHAction)).
GetPost("/installManual", new(InstallManualAction)).
Post("/suggestLoginPorts", new(SuggestLoginPortsAction)).
Get("/downloadInstaller", new(DownloadInstallerAction)).
// 节点相关
Prefix("/clusters/cluster/node").

View File

@@ -1,12 +1,16 @@
package node
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/clusterutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"path/filepath"
"strings"
)
@@ -32,6 +36,20 @@ func (this *InstallAction) RunGet(params struct {
return
}
// 最近运行目录
var exeRoot = ""
if len(node.StatusJSON) > 0 {
var nodeStatus = &nodeconfigs.NodeStatus{}
err = json.Unmarshal(node.StatusJSON, nodeStatus)
if err == nil {
var exePath = nodeStatus.ExePath
if len(exePath) > 0 {
exeRoot = filepath.Dir(filepath.Dir(exePath))
}
}
}
this.Data["exeRoot"] = exeRoot
// 安装信息
if node.InstallStatus != nil {
this.Data["installStatus"] = maps.Map{
@@ -70,7 +88,7 @@ func (this *InstallAction) RunGet(params struct {
this.ErrorPage(err)
return
}
apiNodes := apiNodesResp.ApiNodes
var apiNodes = apiNodesResp.ApiNodes
apiEndpoints := []string{}
for _, apiNode := range apiNodes {
if !apiNode.IsOn {
@@ -87,6 +105,10 @@ func (this *InstallAction) RunGet(params struct {
nodeMap["secret"] = node.Secret
nodeMap["cluster"] = clusterMap
// 安装文件
var installerFiles = clusterutils.ListInstallerFiles()
this.Data["installerFiles"] = installerFiles
this.Show()
}

View File

@@ -0,0 +1,66 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package clusterutils
import (
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/iwind/TeaGo/Tea"
"path/filepath"
"regexp"
"sort"
"strings"
)
type installerFile struct {
Name string `json:"name"`
OS string `json:"os"`
Arch string `json:"arch"`
Version string `json:"version"`
}
func ListInstallerFiles() []*installerFile {
var dir = Tea.Root + "/edge-api/deploy"
matches, err := filepath.Glob(dir + "/edge-node-*.zip")
if err != nil {
return nil
}
var result = []*installerFile{}
var reg = regexp.MustCompile(`^edge-node-(\w+)-(\w+)-v([\w.]+)\.zip$`)
for _, match := range matches {
var baseName = filepath.Base(match)
var subMatches = reg.FindStringSubmatch(baseName)
if len(subMatches) >= 4 {
var osName = subMatches[1]
if len(osName) > 0 {
osName = strings.ToUpper(osName[:1]) + osName[1:]
}
var arch = subMatches[2]
if arch == "amd64" {
arch = "x86_64"
}
var version = subMatches[3]
if version != teaconst.Version { // 只能下载当前版本
continue
}
result = append(result, &installerFile{
Name: subMatches[0],
OS: osName,
Arch: arch,
Version: version,
})
}
}
// 排序将x86_64排在最上面
if len(result) > 0 {
sort.Slice(result, func(i, j int) bool {
return result[i].Arch == "x86_64"
})
}
return result
}

View File

@@ -140,7 +140,7 @@
<!-- 手动安装 -->
<div v-if="installMethod == 'manual'">
<div class="row">上传边缘节点程序到服务器并解压,然后在边缘节点安装目录下,复制<code-label>configs/api.template.yaml</code-label><code-label>configs/api.yaml</code-label>然后修改文件里面的内容为以下内容:</div>
<div class="row">上传边缘节点程序到服务器并解压,然后在边缘节点安装目录下,复制<code-label>configs/api.template.yaml</code-label><code-label>configs/api.yaml</code-label>,修改文件里面的内容为以下内容:</div>
<div class="margin"></div>
<source-code-box id="rpc-code" type="text/yaml">rpc:
endpoints: [ {{apiEndpoints}} ]
@@ -148,6 +148,30 @@ nodeId: "{{node.uniqueId}}"
secret: "{{node.secret}}"</source-code-box>
<div class="margin"></div>
<div class="row">然后再使用<code-label>bin/edge-node start</code-label>命令启动节点。</div>
<div class="margin"></div>
<div v-if="installerFiles != null && installerFiles.length > 0">
<h4>边缘节点安装文件下载</h4>
<table class="ui table celled">
<thead class="full-width">
<tr>
<th>文件名</th>
<th>操作系统</th>
<th>CPU架构</th>
<th>版本</th>
</tr>
</thead>
<tr v-for="installerFile in installerFiles">
<td>
<a :href="'/clusters/cluster/downloadInstaller?name=' + installerFile.name" target="_blank" style="font-weight: normal">{{installerFile.name}}</a>
</td>
<td>{{installerFile.os}}</td>
<td>{{installerFile.arch}}</td>
<td>v{{installerFile.version}}</td>
</tr>
</table>
</div>
<div>
<div class="ui divider"></div>
<a href="" @click.prevent="finish">安装完成</a>

View File

@@ -23,6 +23,29 @@
<h4>方法2手动安装</h4>
<table class="ui table definition selectable">
<tr v-if="installerFiles != null && installerFiles.length > 0">
<td>安装文件</td>
<td>
<table class="ui table celled">
<thead class="full-width">
<tr>
<th>文件名</th>
<th>操作系统</th>
<th>CPU架构</th>
<th>版本</th>
</tr>
</thead>
<tr v-for="installerFile in installerFiles">
<td>
<a :href="'/clusters/cluster/downloadInstaller?name=' + installerFile.name" target="_blank" style="font-weight: normal">{{installerFile.name}}</a>
</td>
<td>{{installerFile.os}}</td>
<td>{{installerFile.arch}}</td>
<td>v{{installerFile.version}}</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>配置文件<em>configs/api.yaml</em><br/>
<em><download-link :v-element="'rpc-code'" :v-file="'api.yaml'">[下载]</download-link ></em></td>
@@ -37,8 +60,9 @@ secret: "{{node.secret}}"</source-code-box>
<tr>
<td class="title">安装目录</td>
<td>
<div v-if="node.installDir.length == 0">使用集群设置<span
v-if="node.cluster != null && node.cluster.installDir.length > 0">{{node.cluster.installDir}}</span>
<div v-if="node.installDir.length == 0">
<span v-if="node.cluster != null && node.cluster.installDir.length > 0">建议使用集群设置{{node.cluster.installDir}}</span>
<span v-else>建议安装在 /usr/local/goedge/edge-node</span>
</div>
<span v-else>{{node.installDir}}</span>
</td>
@@ -71,6 +95,10 @@ secret: "{{node.secret}}"</source-code-box>
<span v-else>{{node.installDir}}</span>
</td>
</tr>
<tr v-if="exeRoot.length > 0">
<td>最近运行目录</td>
<td>{{exeRoot}}</td>
</tr>
</table>
<div>