Skip to content

Commit

Permalink
Merge pull request #10869 from tangruotian/issue-10586
Browse files Browse the repository at this point in the history
worker和agent支持java17和java8同步运行 #10586
  • Loading branch information
bkci-bot authored Nov 25, 2024
2 parents 45abbab + 47a2386 commit 38508ff
Show file tree
Hide file tree
Showing 51 changed files with 1,432 additions and 714 deletions.
1 change: 1 addition & 0 deletions src/agent/agent/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ require (
)

require (
// 非稳定库,目前只在windows升级中简单使用且主要做对go-ole的封装简化,大规模使用前需要评估
github.com/capnspacehook/taskmaster v0.0.0-20210519235353-1629df7c85e9
github.com/docker/cli v23.0.1+incompatible
github.com/docker/go-connections v0.4.0
Expand Down
20 changes: 0 additions & 20 deletions src/agent/agent/src/cmd/daemon/main_win.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ package main
import (
"errors"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -129,14 +128,6 @@ func watch() {
cmd := exec.Command(agentPath)
cmd.Dir = workDir

// 获取 agent 的错误输出,这样有助于打印出崩溃的堆栈方便排查问题
stdErr, errstd := cmd.StderrPipe()
if errstd != nil {
logs.WithError(errstd).Error("get agent stderr pipe error")
} else {
defer stdErr.Close()
}

logs.Info("start devops agent")
if !fileutil.Exists(agentPath) {
logs.Errorf("agent file: %s not exists", agentPath)
Expand Down Expand Up @@ -172,17 +163,6 @@ func watch() {
}
}
logs.WithError(err).Error("agent process error")

// 读取可能的报错
if errstd != nil {
return
}
out, err := io.ReadAll(stdErr)
if err != nil {
logs.WithError(err).Error("read agent stderr out error")
} else {
logs.Error("agent process error out", string(out))
}
}
logs.Info("agent process exited")

Expand Down
2 changes: 2 additions & 0 deletions src/agent/agent/src/cmd/upgrader/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ func main() {
}
}()

logs.Infof("version: %s", config.AgentVersion)

if ok := systemutil.CheckProcess(upgraderProcess); !ok {
logs.Warn("get process lock failed, exit")
return
Expand Down
6 changes: 6 additions & 0 deletions src/agent/agent/src/pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
package agent

import (
"github.com/TencentBlueKing/bk-ci/agent/src/pkg/util/systemutil"
"github.com/TencentBlueKing/bk-ci/agent/src/third_components"
"time"

"github.com/TencentBlueKing/bk-ci/agentcommon/logs"
Expand All @@ -47,6 +49,10 @@ import (

func Run(isDebug bool) {
config.Init(isDebug)
if err := third_components.Init(); err != nil {
logs.WithError(err).Error("init third_components error")
systemutil.ExitProcess(1)
}

// 初始化国际化
i18n.InitAgentI18n()
Expand Down
9 changes: 5 additions & 4 deletions src/agent/agent/src/pkg/agent/ask.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package agent

import (
"github.com/TencentBlueKing/bk-ci/agent/src/third_components"
"runtime"

"github.com/TencentBlueKing/bk-ci/agentcommon/logs"
Expand All @@ -27,13 +28,13 @@ func genHeartInfoAndUpgrade(
})
}

if err := upgrade.SyncJdkVersion(); err != nil {
if err := third_components.Jdk.Jdk17.SyncJdkVersion(); err != nil {
logs.Error("ask sync jdkVersion error", err)
}
if err := upgrade.SyncDockerInitFileMd5(); err != nil {
logs.Error("ask sync docker file md5 error", err)
}
jdkVersion := upgrade.JdkVersion.GetVersion()
jdkVersion := third_components.Jdk.Jdk17.GetVersion()
dockerInitFile := api.DockerInitFileInfo{
FileMd5: upgrade.DockerFileMd5.Md5,
NeedUpgrade: upgrade.DockerFileMd5.NeedUpgrade,
Expand All @@ -42,7 +43,7 @@ func genHeartInfoAndUpgrade(
var upg *api.UpgradeInfo = nil
if upgradeEnable {
upg = &api.UpgradeInfo{
WorkerVersion: config.GAgentEnv.SlaveVersion,
WorkerVersion: third_components.Worker.GetVersion(),
GoAgentVersion: config.AgentVersion,
JdkVersion: jdkVersion,
DockerInitFileInfo: dockerInitFile,
Expand All @@ -51,7 +52,7 @@ func genHeartInfoAndUpgrade(

return api.AgentHeartbeatInfo{
MasterVersion: config.AgentVersion,
SlaveVersion: config.GAgentEnv.SlaveVersion,
SlaveVersion: third_components.Worker.GetVersion(),
HostName: config.GAgentEnv.HostName,
AgentIp: config.GAgentEnv.GetAgentIp(),
ParallelTaskCount: config.GAgentConfig.ParallelTaskCount,
Expand Down
3 changes: 2 additions & 1 deletion src/agent/agent/src/pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ package api

import (
"fmt"
"github.com/TencentBlueKing/bk-ci/agent/src/third_components"
"reflect"
"strconv"

Expand Down Expand Up @@ -64,7 +65,7 @@ func AgentStartup() (*httputil.DevopsResult, error) {
HostIp: config.GAgentEnv.GetAgentIp(),
DetectOs: config.GAgentEnv.OsName,
MasterVersion: config.AgentVersion,
SlaveVersion: config.GAgentEnv.SlaveVersion,
SlaveVersion: third_components.Worker.GetVersion(),
}

return httputil.NewHttpClient().Post(url).Body(startInfo, false).
Expand Down
179 changes: 20 additions & 159 deletions src/agent/agent/src/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import (
"net/http"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -69,7 +68,9 @@ const (
KeyBatchInstall = "devops.agent.batch.install"
KeyLogsKeepHours = "devops.agent.logs.keep.hours"
// KeyJdkDirPath 这个key不会预先出现在配置文件中,因为workdir未知,需要第一次动态获取
KeyJdkDirPath = "devops.agent.jdk.dir.path"
KeyJdkDirPath = "devops.agent.jdk.dir.path"
// KeyJdk17DirPath 最新的 jdk 路径,因为需要一段时间的兼容所以和 KeyJdkDirPath 共存
KeyJdk17DirPath = "devops.agent.jdk17.dir.path"
KeyDockerTaskCount = "devops.docker.parallel.task.count"
keyEnableDockerBuild = "devops.docker.enable"
KeyLanguage = "devops.language"
Expand All @@ -95,6 +96,7 @@ type AgentConfig struct {
BatchInstallKey string
LogsKeepHours int
JdkDirPath string
Jdk17DirPath string
DockerParallelTaskCount int
EnableDockerBuild bool
Language string
Expand All @@ -107,9 +109,10 @@ type AgentEnv struct {
OsName string
agentIp string
HostName string
SlaveVersion string
AgentVersion string
AgentInstallPath string
// WinTask 启动windows进程的组件如 服务/执行计划
WinTask string
}

func (e *AgentEnv) GetAgentIp() string {
Expand Down Expand Up @@ -162,8 +165,8 @@ func LoadAgentEnv() {

GAgentEnv.HostName = systemutil.GetHostName()
GAgentEnv.OsName = systemutil.GetOsName()
GAgentEnv.SlaveVersion = DetectWorkerVersion()
GAgentEnv.AgentVersion = DetectAgentVersion()
GAgentEnv.WinTask = GetWinTaskType()
}

// DetectAgentVersion 检测Agent版本
Expand Down Expand Up @@ -200,130 +203,6 @@ func DetectAgentVersionByDir(workDir string) string {
return strings.TrimSpace(agentVersion)
}

// DetectWorkerVersion 检查worker版本
func DetectWorkerVersion() string {
return DetectWorkerVersionByDir(systemutil.GetWorkDir())
}

// DetectWorkerVersionByDir 检测指定目录下的Worker文件版本
func DetectWorkerVersionByDir(workDir string) string {
jar := fmt.Sprintf("%s/%s", workDir, WorkAgentFile)
tmpDir, _ := systemutil.MkBuildTmpDir()
output, err := command.RunCommand(GetJava(),
[]string{"-Djava.io.tmpdir=" + tmpDir, "-Xmx256m", "-cp", jar, "com.tencent.devops.agent.AgentVersionKt"},
workDir, nil)

if err != nil {
logs.Errorf("detect worker version failed: %s, output: %s", err.Error(), string(output))
exitcode.CheckSignalWorkerError(err)
GAgentEnv.SlaveVersion = ""
return ""
}

detectVersion := parseWorkerVersion(string(output))

// 更新下 worker 的版本信息
if detectVersion == "" {
logs.Warn("parseWorkerVersion null")
} else {
GAgentEnv.SlaveVersion = detectVersion
}

return detectVersion
}

// parseWorkerVersion 解析worker版本
func parseWorkerVersion(output string) string {
// 用函数匹配正确的版本信息, 主要解决tmp空间不足的情况下,jvm会打印出提示信息,导致识别不到worker版本号
// 兼容旧版本,防止新agent发布后无限升级
versionRegexp := regexp.MustCompile(`^v(\d+\.)(\d+\.)(\d+)((-RELEASE)|(-SNAPSHOT)?)$`)
lines := strings.Split(output, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if !(line == "") && !strings.Contains(line, " ") && !strings.Contains(line, "OPTIONS") {
if len(line) > 64 {
line = line[:64]
}
// 先使用新版本的匹配逻辑匹配,匹配不通则使用旧版本
if matchWorkerVersion(line) {
logs.Info("match worker version: ", line)
return line
} else {
if versionRegexp != nil {
if versionRegexp.MatchString(line) {
logs.Info("regexp worker version: ", line)
return line
} else {
continue
}
} else {
// 当正则式出错时(versionRegexp = nil),继续使用原逻辑
logs.Info("regexp nil worker version: ", line)
return line
}
}
}
}
return ""
}

// matchWorkerVersion 匹配worker版本信息
// 版本号为 v数字.数字.数字 || v数字.数字.数字-字符.数字
// 只匹配以v开头的数字版本即可
func matchWorkerVersion(line string) bool {
if !strings.HasPrefix(line, "v") {
logs.Warnf("line %s matchWorkerVersion no start 'v'", line)
return false
}

// 去掉v方便后面计算
subline := strings.Split(strings.TrimPrefix(line, "v"), ".")
sublen := len(subline)
if sublen < 3 || sublen > 4 {
logs.Warnf("line %s matchWorkerVersion len no match", line)
return false
}

// v数字.数字.数字 这种去掉v后应该全是数字
if sublen == 3 {
return checkNumb(subline, line)
}

// v数字.数字.数字-字符.数字,按照 - 分隔,前面的与len 3一致,后面的两个分别判断,不是数字的是字符,不是字符的是数字
fSubline := strings.Split(strings.TrimPrefix(line, "v"), "-")
if len(fSubline) != 2 {
logs.Warnf("line %s matchWorkerVersion len no match", line)
return false
}

if !checkNumb(strings.Split(fSubline[0], "."), line) {
return false
}

fSubline2 := strings.Split(fSubline[1], ".")
if checkNumb([]string{fSubline2[0]}, line) {
logs.Warnf("line %s matchWorkerVersion not char", line)
return false
}

if !checkNumb([]string{fSubline2[1]}, line) {
return false
}

return true
}

func checkNumb(subs []string, line string) bool {
for _, s := range subs {
_, err := strconv.ParseInt(s, 10, 64)
if err != nil {
logs.Warnf("line %s matchWorkerVersion not numb", line)
return false
}
}
return true
}

// BuildAgentJarPath 生成jar寻址路径
func BuildAgentJarPath() string {
return fmt.Sprintf("%s/%s", systemutil.GetWorkDir(), WorkAgentFile)
Expand Down Expand Up @@ -402,7 +281,15 @@ func LoadAgentConfig() error {
jdkDirPath := conf.Section("").Key(KeyJdkDirPath).String()
// 如果路径为空,是第一次,需要主动去拿一次
if jdkDirPath == "" {
jdkDirPath = getJavaDir()
workDir := systemutil.GetWorkDir()
if _, err := os.Stat(workDir + "/jdk"); err != nil && !os.IsExist(err) {
jdkDirPath = workDir + "/jre"
}
jdkDirPath = workDir + "/jdk"
}
jdk17DirPath := conf.Section("").Key(KeyJdk17DirPath).String()
if jdk17DirPath == "" {
jdk17DirPath = systemutil.GetWorkDir() + "/jdk17"
}

// 兼容旧版本 .agent.properties 没有这个键
Expand Down Expand Up @@ -481,6 +368,9 @@ func LoadAgentConfig() error {
GAgentConfig.JdkDirPath = jdkDirPath
logs.Info("jdkDirPath: ", GAgentConfig.JdkDirPath)

GAgentConfig.Jdk17DirPath = jdk17DirPath
logs.Info("jdk17DirPath: ", GAgentConfig.Jdk17DirPath)

GAgentConfig.DockerParallelTaskCount = dockerParallelTaskCount
logs.Info("DockerParallelTaskCount: ", GAgentConfig.DockerParallelTaskCount)

Expand Down Expand Up @@ -525,6 +415,7 @@ func (a *AgentConfig) SaveConfig() error {
content.WriteString(KeyIgnoreLocalIps + "=" + GAgentConfig.IgnoreLocalIps + "\n")
content.WriteString(KeyLogsKeepHours + "=" + strconv.Itoa(GAgentConfig.LogsKeepHours) + "\n")
content.WriteString(KeyJdkDirPath + "=" + GAgentConfig.JdkDirPath + "\n")
content.WriteString(KeyJdk17DirPath + "=" + GAgentConfig.Jdk17DirPath + "\n")
content.WriteString(KeyDockerTaskCount + "=" + strconv.Itoa(GAgentConfig.DockerParallelTaskCount) + "\n")
content.WriteString(keyEnableDockerBuild + "=" + strconv.FormatBool(GAgentConfig.EnableDockerBuild) + "\n")
content.WriteString(KeyLanguage + "=" + GAgentConfig.Language + "\n")
Expand All @@ -549,36 +440,6 @@ func (a *AgentConfig) GetAuthHeaderMap() map[string]string {
return authHeaderMap
}

// GetJava 获取本地java命令路径
func GetJava() string {
if systemutil.IsMacos() {
return GAgentConfig.JdkDirPath + "/Contents/Home/bin/java"
} else {
return GAgentConfig.JdkDirPath + "/bin/java"
}
}

func SaveJdkDir(dir string) {
if dir == GAgentConfig.JdkDirPath {
return
}
GAgentConfig.JdkDirPath = dir
err := GAgentConfig.SaveConfig()
if err != nil {
logs.Errorf("config.go|SaveJdkDir(dir=%s) failed: %s", dir, err.Error())
return
}
}

// getJavaDir 获取本地java文件夹
func getJavaDir() string {
workDir := systemutil.GetWorkDir()
if _, err := os.Stat(workDir + "/jdk"); err != nil && !os.IsExist(err) {
return workDir + "/jre"
}
return workDir + "/jdk"
}

func GetDockerInitFilePath() string {
return systemutil.GetWorkDir() + "/" + DockerInitFile
}
Expand Down
Loading

0 comments on commit 38508ff

Please sign in to comment.