mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 07:50:25 +08:00 
			
		
		
		
	实现单体实例安装工具
This commit is contained in:
		
							
								
								
									
										2
									
								
								cmd/standalone-instance-installer/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								cmd/standalone-instance-installer/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
standalone-instance-installer*
 | 
			
		||||
prepare.sh
 | 
			
		||||
							
								
								
									
										17
									
								
								cmd/standalone-instance-installer/build.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								cmd/standalone-instance-installer/build.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
OS="${1}"
 | 
			
		||||
ARCH="${2}"
 | 
			
		||||
TAG="${3}"
 | 
			
		||||
 | 
			
		||||
if [ -z "$OS" ]; then
 | 
			
		||||
	echo "usage: build.sh OS ARCH"
 | 
			
		||||
	exit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ -z "$ARCH" ]; then
 | 
			
		||||
	echo "usage: build.sh OS ARCH"
 | 
			
		||||
	exit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
env GOOS=linux GOARCH="${ARCH}" go build -tags="${TAG}" -trimpath -ldflags="-s -w" -o "standalone-instance-installer-${OS}-${ARCH}" main.go
 | 
			
		||||
							
								
								
									
										74
									
								
								cmd/standalone-instance-installer/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								cmd/standalone-instance-installer/main.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/instances"
 | 
			
		||||
	_ "github.com/iwind/TeaGo/bootstrap"
 | 
			
		||||
	"github.com/iwind/TeaGo/lists"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	dbPasswordData, err := os.ReadFile("/usr/local/mysql/generated-password.txt")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("[ERROR]read mysql password failed: " + err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var dbPassword = strings.TrimSpace(string(dbPasswordData))
 | 
			
		||||
 | 
			
		||||
	var isTesting = lists.ContainsString(os.Args, "-test") || lists.ContainsString(os.Args, "--test")
 | 
			
		||||
	if isTesting {
 | 
			
		||||
		fmt.Println("testing mode ...")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var instance = instances.NewInstance(instances.Options{
 | 
			
		||||
		IsTesting: isTesting,
 | 
			
		||||
		Verbose:   lists.ContainsString(os.Args, "-v"),
 | 
			
		||||
		Cacheable: true,
 | 
			
		||||
		WorkDir:   "",
 | 
			
		||||
		SrcDir:    "/usr/local/goedge/src",
 | 
			
		||||
		DB: struct {
 | 
			
		||||
			Host     string
 | 
			
		||||
			Port     int
 | 
			
		||||
			Username string
 | 
			
		||||
			Password string
 | 
			
		||||
			Name     string
 | 
			
		||||
		}{
 | 
			
		||||
			Host:     "127.0.0.1",
 | 
			
		||||
			Port:     3306,
 | 
			
		||||
			Username: "root",
 | 
			
		||||
			Password: dbPassword,
 | 
			
		||||
			Name:     "edges",
 | 
			
		||||
		},
 | 
			
		||||
		AdminNode: struct {
 | 
			
		||||
			Port int
 | 
			
		||||
		}{
 | 
			
		||||
			Port: 7788,
 | 
			
		||||
		},
 | 
			
		||||
		APINode: struct {
 | 
			
		||||
			HTTPPort     int
 | 
			
		||||
			RestHTTPPort int
 | 
			
		||||
		}{
 | 
			
		||||
			HTTPPort:     8001,
 | 
			
		||||
			RestHTTPPort: 8002,
 | 
			
		||||
		},
 | 
			
		||||
		Node: struct{ HTTPPort int }{
 | 
			
		||||
			HTTPPort: 8080,
 | 
			
		||||
		},
 | 
			
		||||
		UserNode: struct {
 | 
			
		||||
			HTTPPort int
 | 
			
		||||
		}{
 | 
			
		||||
			HTTPPort: 7799,
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	err = instance.SetupAll()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("[ERROR]setup failed: " + err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("ok")
 | 
			
		||||
}
 | 
			
		||||
@@ -5,7 +5,6 @@ import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/goman"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
	"github.com/go-sql-driver/mysql"
 | 
			
		||||
	_ "github.com/go-sql-driver/mysql"
 | 
			
		||||
	"github.com/iwind/TeaGo/Tea"
 | 
			
		||||
	"github.com/iwind/TeaGo/dbs"
 | 
			
		||||
@@ -759,10 +758,5 @@ func (this *MetricStatDAO) canIgnore(err error) bool {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 忽略 Error 1213: Deadlock found 错误
 | 
			
		||||
	mysqlErr, ok := err.(*mysql.MySQLError)
 | 
			
		||||
	if ok && mysqlErr.Number == 1213 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
	return CheckSQLErrCode(err, 1213)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@ import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/goman"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
			
		||||
	"github.com/go-sql-driver/mysql"
 | 
			
		||||
	_ "github.com/go-sql-driver/mysql"
 | 
			
		||||
	"github.com/iwind/TeaGo/Tea"
 | 
			
		||||
	"github.com/iwind/TeaGo/dbs"
 | 
			
		||||
@@ -289,10 +288,5 @@ func (this *MetricSumStatDAO) canIgnore(err error) bool {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 忽略 Error 1213: Deadlock found 错误
 | 
			
		||||
	mysqlErr, ok := err.(*mysql.MySQLError)
 | 
			
		||||
	if ok && mysqlErr.Number == 1213 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
	return CheckSQLErrCode(err, 1213)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/go-sql-driver/mysql"
 | 
			
		||||
	"github.com/iwind/TeaGo/dbs"
 | 
			
		||||
	"github.com/iwind/TeaGo/types"
 | 
			
		||||
@@ -60,8 +61,8 @@ func CheckSQLErrCode(err error, code uint16) bool {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 快速判断错误方法
 | 
			
		||||
	mysqlErr, ok := err.(*mysql.MySQLError)
 | 
			
		||||
	if ok && mysqlErr.Number == code { // Error 1050: Table 'xxx' already exists
 | 
			
		||||
	var mysqlErr *mysql.MySQLError
 | 
			
		||||
	if errors.As(err, &mysqlErr) && mysqlErr.Number == code { // Error 1050: Table 'xxx' already exists
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -86,6 +87,6 @@ func IsMySQLError(err error) bool {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	_, ok := err.(*mysql.MySQLError)
 | 
			
		||||
	return ok
 | 
			
		||||
	var mysqlErr *mysql.MySQLError
 | 
			
		||||
	return errors.As(err, &mysqlErr)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								internal/db/models/utils_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								internal/db/models/utils_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
			
		||||
 | 
			
		||||
package models_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/db/models"
 | 
			
		||||
	"github.com/iwind/TeaGo/assert"
 | 
			
		||||
	"github.com/iwind/TeaGo/dbs"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestIsMySQLError(t *testing.T) {
 | 
			
		||||
	var a = assert.NewAssertion(t)
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		var err error
 | 
			
		||||
		a.IsFalse(models.IsMySQLError(err))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		var err = errors.New("hello")
 | 
			
		||||
		a.IsFalse(models.IsMySQLError(err))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		db, err := dbs.Default()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		defer func() {
 | 
			
		||||
			_ = db.Close()
 | 
			
		||||
		}()
 | 
			
		||||
		_, err = db.Exec("SELECT abc")
 | 
			
		||||
		a.IsTrue(models.IsMySQLError(err))
 | 
			
		||||
		a.IsTrue(models.CheckSQLErrCode(err, 1054))
 | 
			
		||||
		a.IsFalse(models.CheckSQLErrCode(err, 1000))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								internal/instances/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								internal/instances/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
# 实例
 | 
			
		||||
 | 
			
		||||
## 目录结构:
 | 
			
		||||
~~~
 | 
			
		||||
/opt/cache
 | 
			
		||||
/usr/local/goedge/
 | 
			
		||||
	edge-admin/
 | 
			
		||||
	   configs/
 | 
			
		||||
	      api_admin.yaml
 | 
			
		||||
	      api_db.yaml
 | 
			
		||||
	      server.yaml
 | 
			
		||||
	edge-api/
 | 
			
		||||
	   configs/api.yaml
 | 
			
		||||
	   configs/db.yaml
 | 
			
		||||
	api-node/
 | 
			
		||||
	   configs/api_node.yaml
 | 
			
		||||
	api-user/
 | 
			
		||||
	   configs/api_user.yaml
 | 
			
		||||
    src/	   
 | 
			
		||||
/usr/bin/
 | 
			
		||||
  edge-admin -> ...
 | 
			
		||||
  edge-api -> ...
 | 
			
		||||
  edge-node -> ...
 | 
			
		||||
  edge-user -> ...
 | 
			
		||||
/usr/local/mysql
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
* 其中 `->` 表示软链接。
 | 
			
		||||
* `src/` 目录下放置zip格式的待安装压缩包
 | 
			
		||||
 | 
			
		||||
## 端口
 | 
			
		||||
* Admin:7788
 | 
			
		||||
* API:8001
 | 
			
		||||
* API HTTP:8002
 | 
			
		||||
* User: 7799
 | 
			
		||||
* Server: 8080
 | 
			
		||||
 | 
			
		||||
## 数据库
 | 
			
		||||
数据库名称为 `edges`
 | 
			
		||||
							
								
								
									
										16
									
								
								internal/instances/api_config.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								internal/instances/api_config.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
			
		||||
 | 
			
		||||
package instances
 | 
			
		||||
 | 
			
		||||
import "gopkg.in/yaml.v3"
 | 
			
		||||
 | 
			
		||||
type APIConfig struct {
 | 
			
		||||
	RPCEndpoints     []string `yaml:"rpc.endpoints,flow,omitempty" json:"rpc.endpoints"`
 | 
			
		||||
	RPCDisableUpdate bool     `yaml:"rpc.disableUpdate,omitempty" json:"rpc.disableUpdate"`
 | 
			
		||||
	NodeId           string   `yaml:"nodeId" json:"nodeId"`
 | 
			
		||||
	Secret           string   `yaml:"secret" json:"secret"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *APIConfig) AsYAML() ([]byte, error) {
 | 
			
		||||
	return yaml.Marshal(this)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1009
									
								
								internal/instances/instance.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1009
									
								
								internal/instances/instance.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										98
									
								
								internal/instances/instance_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								internal/instances/instance_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
			
		||||
 | 
			
		||||
package instances_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAPI/internal/instances"
 | 
			
		||||
	"github.com/iwind/TeaGo/Tea"
 | 
			
		||||
	_ "github.com/iwind/TeaGo/bootstrap"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var instance = instances.NewInstance(instances.Options{
 | 
			
		||||
	Cacheable: true,
 | 
			
		||||
	WorkDir:   Tea.Root + "/standalone-instance",
 | 
			
		||||
	SrcDir:    Tea.Root + "/standalone-instance/src",
 | 
			
		||||
	DB: struct {
 | 
			
		||||
		Host     string
 | 
			
		||||
		Port     int
 | 
			
		||||
		Username string
 | 
			
		||||
		Password string
 | 
			
		||||
		Name     string
 | 
			
		||||
	}{
 | 
			
		||||
		Host:     "127.0.0.1",
 | 
			
		||||
		Port:     3306,
 | 
			
		||||
		Username: "root",
 | 
			
		||||
		Password: "123456",
 | 
			
		||||
		Name:     "edges2",
 | 
			
		||||
	},
 | 
			
		||||
	AdminNode: struct {
 | 
			
		||||
		Port int
 | 
			
		||||
	}{
 | 
			
		||||
		Port: 7788,
 | 
			
		||||
	},
 | 
			
		||||
	APINode: struct {
 | 
			
		||||
		HTTPPort     int
 | 
			
		||||
		RestHTTPPort int
 | 
			
		||||
	}{
 | 
			
		||||
		HTTPPort:     8001,
 | 
			
		||||
		RestHTTPPort: 8002,
 | 
			
		||||
	},
 | 
			
		||||
	Node: struct{ HTTPPort int }{
 | 
			
		||||
		HTTPPort: 8080,
 | 
			
		||||
	},
 | 
			
		||||
	UserNode: struct {
 | 
			
		||||
		HTTPPort int
 | 
			
		||||
	}{
 | 
			
		||||
		HTTPPort: 7799,
 | 
			
		||||
	},
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
func TestInstanceSetupAll(t *testing.T) {
 | 
			
		||||
	err := instance.SetupAll()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInstance_SetupDB(t *testing.T) {
 | 
			
		||||
	err := instance.SetupDB()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInstance_SetupAdminNode(t *testing.T) {
 | 
			
		||||
	err := instance.SetupAdminNode()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInstance_SetupAPINode(t *testing.T) {
 | 
			
		||||
	err := instance.SetupAPINode()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInstance_SetupUserNode(t *testing.T) {
 | 
			
		||||
	err := instance.SetupUserNode()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInstance_SetupNode(t *testing.T) {
 | 
			
		||||
	err := instance.SetupNode()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInstance_Clean(t *testing.T) {
 | 
			
		||||
	err := instance.Clean()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								internal/instances/options.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								internal/instances/options.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
			
		||||
 | 
			
		||||
package instances
 | 
			
		||||
 | 
			
		||||
type Options struct {
 | 
			
		||||
	IsTesting bool
 | 
			
		||||
	Verbose   bool
 | 
			
		||||
	Cacheable bool
 | 
			
		||||
 | 
			
		||||
	WorkDir string
 | 
			
		||||
	SrcDir  string
 | 
			
		||||
	DB      struct {
 | 
			
		||||
		Host     string
 | 
			
		||||
		Port     int
 | 
			
		||||
		Username string
 | 
			
		||||
		Password string
 | 
			
		||||
		Name     string
 | 
			
		||||
	}
 | 
			
		||||
	AdminNode struct {
 | 
			
		||||
		Port int
 | 
			
		||||
	}
 | 
			
		||||
	APINode struct {
 | 
			
		||||
		HTTPPort     int
 | 
			
		||||
		RestHTTPPort int
 | 
			
		||||
	}
 | 
			
		||||
	Node struct {
 | 
			
		||||
		HTTPPort int
 | 
			
		||||
	}
 | 
			
		||||
	UserNode struct {
 | 
			
		||||
		HTTPPort int
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user