21 Commits

Author SHA1 Message Date
zhangshuai
b773755d92 feat: NEZ-2030 nz-talon组件 OTA 接口开发 2022-07-19 16:55:02 +08:00
方顺健
1740497163 build: 更换minio 服务器 2022-07-12 07:35:04 +00:00
zhangshuai
737a0a9985 feat: NEZ-1843 healthy接口返回值增加 当前时间戳 2022-04-27 17:07:47 +08:00
方顺健
4853fff587 Update .gitlab-ci.yml 2022-04-12 09:58:16 +00:00
方顺健
8be974983c build: 修改ci 基础镜像为 1.3 2022-04-12 08:28:41 +00:00
fangshunjian
5473010797 Merge branch 'dev-ci' of https://git.mesalab.cn/nezha/nz-talon.git into
dev-ci
2022-04-06 15:26:07 +08:00
fangshunjian
3f9ff7e918 feat: 新增 ci 2022-03-31 10:44:28 +08:00
shizhendong
7ea335e945 build: 更新log4j版本为,2.17.0 2021-12-20 12:05:36 +08:00
fangshunjian
3fa413e189 build: 更新 log4j版本 2021-12-10 19:48:31 +08:00
shizhendong
0ce7dd2377 fix: 修改配置文件内 promtail 组件 systemd 启停命令 2021-10-03 22:40:29 +08:00
shizhendong
d5f54f40b1 fix: healthy 接口返回 version 2021-09-06 11:39:32 +08:00
tanghao
6347041b36 fix: 修改配置文件中错误 2021-08-17 17:33:31 +08:00
hyx
97b385e65e NEZ-902 nz-talon 增加 promtail 代理接口 2021-08-10 11:09:35 +08:00
hyx
70da6cb473 Merge branch 'dev' of https://git.mesalab.cn/nezha/nz-talon.git into dev 2021-08-09 17:42:48 +08:00
hyx
82e7eab8bf 修改错误的日志信息描述 2021-08-09 17:41:31 +08:00
tanghao
3564d79f56 fix: 配置文件启动由dev改为prod 2021-08-09 17:04:56 +08:00
tanghao
d1db955718 fix: 配置文件修改 2021-08-09 16:47:22 +08:00
hyx
309921826e Merge branch 'dev' of https://git.mesalab.cn/nezha/nz-talon.git into dev 2021-08-06 17:32:35 +08:00
hyx
dbed910b9c nz-talon 增加配置下发成功后,进行服务重启 2021-08-06 17:28:00 +08:00
tanghao
5173074b68 fix: 打包时跳过单元测试 支持xjar打包 2021-08-06 15:54:51 +08:00
hyx
e725329063 nz-talon首次提交 2021-07-09 17:01:27 +08:00
39 changed files with 4364 additions and 0 deletions

32
.classpath Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target/

72
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,72 @@
# docker镜像
image: git.mesalab.cn:7443/nezha/nz-build-env:1.3
# 定义全局变量
variables:
MINIO_HOST: 'http://192.168.41.160:2020/'
MINIO_USER: 'admin'
MINIO_PWD: "Nezha@02!"
MAVEN_REPO: "/etc/maven/repository/"
# 依赖的docker服务
services:
# - mariadb
# - redis
# 开始执行脚本前所需执行脚本
before_script:
- echo "begin ci"
# 脚本执行完后的钩子,执行所需脚本
after_script:
- echo "end ci"
# 该ci pipeline适合的场景
stages:
- build
- test
# maven setting /usr/share/maven/conf/settings.xml
cache:
paths:
- $MAVEN_REPO
# 定义的任务
build_rpm:
stage: build
# 所需执行的脚本
script:
- env | sort
- pwd
- chmod +x ./tools/package.sh
- ./tools/package.sh
artifacts:
name: "$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA"
when: on_success
paths:
- ./target/*.xjar
- ./target/xjar
expire_in: 1 week
# 在哪个分支上可用
only:
- /^rel-.*$/i
# 指定哪个ci runner跑该工作
tags:
- nezha
# 定义的任务
dev_build:
stage: test
# 所需执行的脚本
script:
- env | sort
- pwd
- mvn clean install -Dxjar.password=111111 -Dxjar.excludes=/db/*,/static/**/*
- cd ./target && go build xjar.go && cd ..
artifacts:
name: "$CI_PROJECT_NAME-$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA"
when: on_success
paths:
- ./target/*.xjar
- ./target/xjar
expire_in: 1 week
# 在哪个分支上可用
only:
- /^dev-.*$/i
# 指定哪个ci runner跑该工作
tags:
- nezha

23
.project Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>nz-talon</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

310
mvnw vendored Normal file
View File

@@ -0,0 +1,310 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

182
mvnw.cmd vendored Normal file
View File

@@ -0,0 +1,182 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%

167
pom.xml Normal file
View File

@@ -0,0 +1,167 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>net.geedge</groupId>
<artifactId>nz-talon</artifactId>
<version>2.0</version>
<name>nz-talon</name>
<description>nezha promtail config sync talon</description>
<properties>
<java.version>1.8</java.version>
<log4j2.version>2.17.0</log4j2.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.2</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.45</version>
</dependency>
<!-- 添加 XJar 依赖 -->
<!-- <dependency>-->
<!-- <groupId>com.github.core-lib</groupId>-->
<!-- <artifactId>xjar</artifactId>-->
<!-- <version>4.0.1</version>-->
<!-- &lt;!&ndash; <scope>test</scope> &ndash;&gt;-->
<!-- </dependency>-->
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<!-- 跳过单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<!-- 添加 XJar Maven 插件 -->
<plugin>
<groupId>com.mesalab.xjar-maven-plugin</groupId>
<artifactId>mesalab-xjar-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
<phase>package</phase>
<configuration>
<!-- <password>111111</password>-->
<!-- <includes>-->
<!-- <include>cn/nis/ntc/**</include>-->
<!-- </includes>-->
<!-- <excludes>-->
<!-- <exclude>cn/nis/ntc/api/config/Swagger2Configuration.class</exclude>-->
<!-- </excludes>-->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<!-- 配置私服地址 -->
<repository>
<id>nexus</id>
<name>Team Nexus Repository</name>
<url>http://192.168.40.125:8099/content/groups/public/</url>
</repository>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
<!--opennum仓库-->
<repository>
<id>opennms</id>
<name>opennms</name>
<url>https://repo.opennms.org/maven2/</url>
</repository>
<!-- 设置 jitpack.io 仓库 -->
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>nexus</id>
<name>Team Nexus Repository</name>
<url>http://192.168.40.125:8099/content/groups/public/</url>
</pluginRepository>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<!-- 设置 jitpack.io 插件仓库 -->
<pluginRepository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</pluginRepository>
</pluginRepositories>
</project>

View File

@@ -0,0 +1,15 @@
package net.geedge.confagent;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
@SpringBootApplication
@PropertySource(value = { "classpath:version.properties" }, encoding = "utf-8", ignoreResourceNotFound = true)
public class ConfagentApplication {
public static void main(String[] args) {
SpringApplication.run(ConfagentApplication.class, args);
}
}

View File

@@ -0,0 +1,9 @@
package net.geedge.confagent.annotation;
import java.lang.annotation.*;
@Target( {ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UnCheckToken {
}

View File

@@ -0,0 +1,39 @@
package net.geedge.confagent.config;
import net.geedge.confagent.interceptor.TokenInterceptor;
import org.apache.catalina.connector.Connector;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class ConfagentConfiguration implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
@Bean(name={"tomcatServletWebServerFactory"})
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.setProperty("relaxedPathChars", "\"<>[\\]^`{|}");
connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}");
}
});
return factory;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
}
}

View File

@@ -0,0 +1,101 @@
package net.geedge.confagent.controller;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.hutool.log.Log;
import net.geedge.confagent.annotation.UnCheckToken;
import net.geedge.confagent.entity.AuthEntity;
import net.geedge.confagent.util.R;
import net.geedge.confagent.util.RCode;
import net.geedge.confagent.util.Tool;
@RestController
@RequestMapping(value={"/auth"})
public class AuthController extends BaseController{
private final static Log log = Log.get();
@Value("${confagent.authFile:auth.yml}")
private String authFile;
private static String rootPath = Tool.WebPathUtil.getRootPath();
/**
* @Description 每次请求auth接口重新生成 token并记录到文件
* @Author rui
* @Date 2021/3/23
*/
@RequestMapping
@UnCheckToken
public R auth(AuthEntity auth){
if(Tool.StrUtil.isBlank(auth.getName())||Tool.StrUtil.isBlank(auth.getPin())){
return R.error(RCode.AUTH_NAME_PIN_ISNULL);
}
File af = Tool.FileUtil.file(rootPath, authFile);
log.debug("auth file path : {}" ,af.getAbsolutePath());
Properties properties = Tool.YamlUtil.yamlToProperties(af.getAbsolutePath());
String name = properties.getProperty("auth.name","nezha");
String pin = properties.getProperty("auth.pin","nezha");
if(Tool.StrUtil.equals(name,auth.getName())&& Tool.StrUtil.equals(pin,auth.getPin())){
String token = Tool.IdUtil.fastShortUUID();
log.debug("write token {} to {}",token,af.getAbsolutePath());
writeToken(token);
Map<String,String> map = new HashMap<>();
map.put("token", token);
return R.ok(map);
}
return R.error(RCode.AUTH_NAME_PIN_INVALID);
}
/**
* @Description 验证当前token是否和文件记录一致一致后重新生成则更新文件并返回最新token
* @Author rui
* @Date 2021/3/24
*/
@GetMapping("/refresh")
public R refresh(){
String t = Tool.IdUtil.fastShortUUID();
writeToken(t);
Map<String,String> map = new HashMap<>();
map.put("token", t);
return R.ok(map);
}
/**
* @Description 注销当前 token
* @Author rui
* @Date 2021/3/24
*/
@GetMapping("logout")
public R logout(){
File tf = Tool.FileUtil.file(rootPath, tokenFile);
log.debug("token file path : {}" ,tf.getAbsolutePath());
if(Tool.FileUtil.exist(tf)){
Tool.FileUtil.del(tf);
}
if(Tool.FileUtil.exist(promtailConfPath)){
Tool.YamlUtil.writeAsMap(null,promtailConfPath);
}
return R.ok();
}
private void writeToken(String token){
File tf = Tool.FileUtil.file(rootPath, tokenFile);
log.debug("token file path : {}" ,tf.getAbsolutePath());
Tool.FileUtil.writeUtf8String(token, tf);
}
}

View File

@@ -0,0 +1,55 @@
package net.geedge.confagent.controller;
import cn.hutool.log.Log;
import net.geedge.confagent.util.Tool;
import org.springframework.beans.factory.annotation.Value;
public abstract class BaseController {
private Log log = Log.get();
protected static final String PROMTAIL_LISTEN_SERVER = "server";
protected static final String PROMTAIL_LISTEN_PORT = "http_listen_port";
@Value("${confagent.tokenFile:config/token.auth}")
protected String tokenFile; //token文件位置
@Value("${confagent.promtail.cmdLine}")
protected String promtailCmdLinePath; // promtail config.conf 启动参数文件存放位置
@Value("${confagent.promtail.defaultIP:127.0.0.1}")
protected String defaultPromtailIP; //promtail 默认监听ip
protected static final int DEFAULT_PROMTAIL_PORT=9080; //prometheus 默认监听端口
@Value("${confagent.promtail.config}")
protected String promtailConfPath;
@Value("${version}")
protected String currentVersion;
/**
* aes 对称加密 密钥
*/
public static final byte[] AES_SECRET_KEY = Tool.HexUtil.decodeHex("bde5430614b21baf1c53bd6f616d1a39");
/**
* 调用 /-/reload 接口,热加载 server 配置文件,
*
* @param cmdLinePath
* @param serverListenAddr
* @param defaultServerPort
* @param defaultServerIP
* @return
*/
// public boolean reloadServerConfiguration(String cmdLinePath, String serverListenAddr, int defaultServerPort, String defaultServerIP) {
// UrlBuilder serverReloadUrl = new UrlBuilder();
// int serverPort = ConfagentUtil.getConfFilePort(cmdLinePath, serverListenAddr, defaultServerPort);
// serverReloadUrl.setScheme("http").setHost(defaultServerIP).setPort(serverPort).addPath("/-/reload");
//
// String url = serverReloadUrl.toString();
// HttpRequest post = Tool.HttpUtil.createPost(url);
// HttpResponse response = post.execute();
// return 200 == response.getStatus();
// }
}

View File

@@ -0,0 +1,106 @@
package net.geedge.confagent.controller;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.http.HttpConnection;
import cn.hutool.log.Log;
import net.geedge.confagent.annotation.UnCheckToken;
import net.geedge.confagent.util.ConfagentUtil;
import net.geedge.confagent.util.R;
import net.geedge.confagent.util.RCode;
import net.geedge.confagent.util.Tool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("healthy")
public class HealthyController extends BaseController{
@Autowired
private ConfagentUtil confagentUtil;
private final static Log log = Log.get();
private UrlBuilder promtailHealthy;
@GetMapping
@UnCheckToken
public R checkHealthy(@RequestHeader(value="Authorization",required = false) String token) {
Map<String,Object> result = new HashMap<>();
buildHealthyURL(result);
if(Tool.StrUtil.isNotBlank(token)){
if(confagentUtil.checkToken(token).getCode() == RCode.SUCCESS.getCode()){
result.put("auth","TRUE");
}else{
result.put("auth","FALSE");
}
}
String version = confagentUtil.readVersion();
result.put("version", version);
result.put("ts", new Date().getTime());
return R.ok(result);
}
public void buildHealthyURL(Map<String,Object> result){
Map<String,Object> promtailConf = Tool.YamlUtil.readAsMap(promtailConfPath);
if(promtailConf==null) {
result.put("promtail","DOWN");
return ;
}
Map<String,Integer> promtailPortMap = (Map<String,Integer>)promtailConf.get(PROMTAIL_LISTEN_SERVER);
if(promtailPortMap==null) {
result.put("promtail","DOWN");
return ;
}
Integer promtailPort = promtailPortMap.get(PROMTAIL_LISTEN_PORT);
if(promtailPort==null) {
promtailPort = DEFAULT_PROMTAIL_PORT;
}
promtailHealthy = new UrlBuilder();
promtailHealthy.setScheme("http").setHost(defaultPromtailIP).setPort(promtailPort).addPath("/ready");
result.put("promtail",checkState(promtailHealthy.toString()));
}
private String checkState(String url){
HttpURLConnection conn = null;
try{
conn = HttpConnection.create(url,null).getHttpURLConnection();
log.debug("connect to {}",url);
conn.connect();
int responseCode = conn.getResponseCode();
if(200 == responseCode){
return "UP";
}
return "DOWN";
}catch (IOException e){
log.error("failed connect ",e);
return "DOWN";
}finally {
if (conn != null) {
conn.disconnect();
conn = null;
}
}
}
}

View File

@@ -0,0 +1,83 @@
package net.geedge.confagent.controller;
import cn.hutool.log.Log;
import net.geedge.confagent.util.ConfagentUtil;
import net.geedge.confagent.util.R;
import net.geedge.confagent.util.RCode;
import net.geedge.confagent.util.Tool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.UUID;
@RestController
public class OTAController extends BaseController{
private static Log log = Log.get();
@Autowired
private ConfagentUtil confagentUtil;
private static final String UPDATE_PACKAGE_PATH = "/tmp/nezha/nz-talon/%s/%s";
@PostMapping("/ota")
public R ota(HttpServletRequest request, @RequestParam(name = "file", required = false) MultipartFile file, String md5 )throws IOException{
//检查token
String token = request.getHeader("Authorization");
if (Tool.StrUtil.isBlank(token)) {
return R.error(RCode.AUTH_TOKEN_ISNULL);
}else {
if (confagentUtil.checkToken(token).getCode() != RCode.SUCCESS.getCode())return R.error(RCode.AUTH_TOKEN_INVALID);
}
//将文件缓存到 /tmp 目录下
String updateFileName = file.getOriginalFilename();
File updatePackagePath = Tool.FileUtil.file(String.format(UPDATE_PACKAGE_PATH , UUID.randomUUID().toString().replaceAll("-", ""), updateFileName));
updatePackagePath.mkdirs();
try {
file.transferTo(updatePackagePath);
} catch (Exception e) {
return R.error(RCode.OTA_FILE_CACHE_ERROR);
}
//校验MD5
String updateFileMd5 = Tool.DigestUtil.md5Hex(new FileInputStream(updatePackagePath));
log.info("updateFileMd5 : {}",updateFileMd5);
md5 = Tool.AesUtil.decrypt(md5 , AES_SECRET_KEY);
if(!updateFileMd5.equals(md5)){
return R.error(RCode.OTA_MD5_ERROR);
}
//校验版本号
String fileName = file.getOriginalFilename();
String updateVersion = fileName.split("-")[2];
updateVersion = updateVersion.substring(0,updateVersion.lastIndexOf("."));
log.info("current version : {} , update version : {}", currentVersion , updateVersion);
if( !(Tool.DateUtil.betweenDay(Tool.DateUtil.parseDate(updateVersion),Tool.DateUtil.parseDate(currentVersion), false) > 0)){
return R.error(RCode.OTA_VERSION_ERROR);
}
//检查atd服务是否启动
InputStream atdStatus = Tool.RuntimeUtil.exec("systemctl status atd").getInputStream();
String atdStatusStr = Tool.IoUtil.read(atdStatus).toString();
if(!atdStatusStr.contains("Active: active (running)")){
return R.error(RCode.OTA_ATD_SERVICE_DOWN);
}
//延迟一分钟更新 使用echo 将更新命令传入at
String atCommand ="echo \"rpm -Uvh %s\" | at now +1 minutes";
atCommand = String.format(atCommand,updatePackagePath);
log.info("update nz-agent : {}", atCommand);
new ProcessBuilder("/bin/bash", "-c", atCommand).start();
return R.ok();
}
}

View File

@@ -0,0 +1,269 @@
package net.geedge.confagent.controller;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.net.url.UrlPath;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpConnection;
import cn.hutool.log.Log;
import net.geedge.confagent.annotation.UnCheckToken;
import net.geedge.confagent.util.ConfagentUtil;
import net.geedge.confagent.util.R;
import net.geedge.confagent.util.RCode;
import net.geedge.confagent.util.Tool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.nio.charset.Charset;
import java.util.*;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/promtail")
public class PromtailController extends BaseController{
private final static Log log = Log.get();
@Autowired
private ConfagentUtil confagentUtil;
@Value("${confagent.promtail.query.auth:true}")
private Boolean queryAuth;
@Value("${confagent.promtail.restart:systemctl restart promtail}")
private String restartCmd;
@Value("${confagent.versionFile:promtail.version}")
private String versionFile;
@Value("${confagent.promtail.startCmd:systemctl start promtail.service}")
private String startCmd;
@Value("${confagent.promtail.stopCmd:systemctl stop promtail.service}")
private String stopCmd;
private final String[] QUERY_API_SUFFIX = {"query","query_range","series","labels","label","values"};
private static String rootPath = Tool.WebPathUtil.getRootPath();
/**
* @Description 获取promtail相关配置
* @Author rui
* @Date 2021/3/24
*/
@GetMapping("/config")
public R queryConfig(){
Map<String,String> cmdLine = ConfagentUtil.loadServiceConfigFile(promtailCmdLinePath);
Map<String,Object> promtailConf = Tool.YamlUtil.readAsMap(promtailConfPath);
String version = confagentUtil.readVersion();
Map<String,Object> result = new LinkedHashMap<>();
result.put("version",version);
result.put("cmdline",cmdLine);
result.put("config",promtailConf);
return R.ok(result);
}
/**
* @Description 写入promtail配置文件
* @Author rui
* @Date 2021/3/25
*/
@PostMapping("/config")
public R overwriteConfig( @RequestBody Map<String,Object> configs){
Object version = configs.get("version");
File tf = Tool.FileUtil.file(rootPath, versionFile);
log.debug("version file path : {}" ,tf.getAbsolutePath());
if(version==null){
return R.error(RCode.PROMTAIL_CONFIG_VERSION_ISNULL);
}else {
Tool.FileUtil.writeUtf8String(version.toString(), tf);
}
Map<String,String> cmdLine =(Map<String,String>) configs.get("cmdline");
Map<String,Object> promtailConf =(Map<String,Object>) configs.get("config");
if(!Tool.MapUtil.isEmpty(cmdLine)){
log.info("write promtail cmdLine conf:{}", Tool.JSONUtil.toJsonStr(cmdLine));
writeServiceConfigFile(cmdLine,promtailCmdLinePath);
}
if(!Tool.MapUtil.isEmpty(promtailConf)){
log.info("write promtail conf:{}", Tool.JSONUtil.toJsonStr(promtailConf));
Tool.YamlUtil.writeAsMap(promtailConf,promtailConfPath);
}
//重启服务promtail
if(Tool.StrUtil.isNotBlank(stopCmd)) {
log.info("stop promtail:"+stopCmd);
try {
Tool.RuntimeUtil.exec(stopCmd);
}catch(Exception e) {
log.error(e);
return R.error(RCode.PROMTAIL_STOP_CMD_ERROR);
}
log.info("stop promtail:"+stopCmd+" end");
}
Tool.ThreadUtil.sleep(1000);
if(Tool.StrUtil.isNotBlank(startCmd)) {
log.info("start promtail:"+startCmd);
try {
// String[] b={"sh","-c",startCmd};
// Tool.RuntimeUtil.exec(b);
Tool.RuntimeUtil.exec(startCmd);
}catch(Exception e) {
log.error(e);
return R.error(RCode.PROMTAIL_START_CMD_ERROR);
}
log.info("start promtail:"+startCmd+" end");
}
return R.ok();
}
/**
* @Description 获取promtail相关配置版本
* @Author rui
* @Date 2021/3/24
*/
@GetMapping("/config/version")
public R queryVersion(){
Map<String,Object> result = new HashMap<>();
String version = confagentUtil.readVersion();
result.put("version",version);
return R.ok(result);
}
/**
* @Description 写 promtail config.conf 启动参数配置文件
* @Author rui
* @Date 2021/3/25
*/
private void writeServiceConfigFile(Map<String,String> conf,String path){
StringBuffer sb = new StringBuffer();
sb.append("OPTION=\"");
for (Map.Entry<String,String> entry:conf.entrySet()){
String key = entry.getKey();
String value = entry.getValue();
sb.append("--"+key+"=");
sb.append("'"+value+"' ");
}
sb.append("\"");
Tool.FileUtil.writeUtf8String(sb.toString(),path);
}
/**
* @Description 代理本promtail 接口
* @Author han
* @Date 2021/8/10
*/
@RequestMapping("/proxy/**")
@UnCheckToken
public void proxy(HttpServletRequest request, HttpServletResponse response){
String promtailPath = request.getServletPath().replace("/promtail/proxy","");
String token = request.getHeader("Authorization");
R r = confagentUtil.checkToken(token);
Boolean isQuery=false;
//queryAuth 配置只限制查询是否需要校验
if(queryAuth){
isQuery = Tool.StrUtil.isNotBlank(Arrays.stream(QUERY_API_SUFFIX).filter(t -> promtailPath.indexOf(t) != -1).findAny().orElse(null));
}
if(isQuery &&r.getCode() != RCode.SUCCESS.getCode()){
ConfagentUtil.writeResponse(response,r);
return;
}
int port = 9080;
Map<String,Object> promtailMap= Tool.YamlUtil.readAsMap(promtailConfPath);
Map<String,Object> serverObj = (Map<String,Object>)promtailMap.get("server");
if(serverObj!=null) {
port = (Integer)serverObj.get("http_listen_port");
}
requestProm(defaultPromtailIP,port,promtailPath,request,response);
}
public void requestProm(String host, int port, String path, HttpServletRequest request, HttpServletResponse response) {
String queryString = ReflectUtil.invoke(request, "getQueryString");
queryString = StrUtil.isNotBlank(queryString)?queryString:"";
String url = UrlBuilder.create().setScheme("http").setHost(host).setPort(port).setPath(UrlPath.of(path, Charset.forName("UTF-8"))).toURL().toString() + "?" + queryString;
log.info("promtail url: {}", url);
String method = request.getMethod();
HttpURLConnection conn = null;
ServletInputStream reqInputStream = null;
ServletOutputStream resOutputStream = null;
OutputStream connOutputStream = null;
InputStream connInputStream = null;
try {
conn = HttpConnection.create(url, null).getHttpURLConnection();
reqInputStream = request.getInputStream();
resOutputStream = response.getOutputStream();
conn.setRequestMethod(method);
// 复制请求头
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String hn = headerNames.nextElement();
if(!"authorization".equalsIgnoreCase(hn)) {
ReflectUtil.invoke(conn,"addRequestProperty",hn,request.getHeader(hn));
}
}
if (!"GET".equalsIgnoreCase(method)) {
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
connOutputStream = conn.getOutputStream();
Tool.IoUtil.copy(reqInputStream, connOutputStream);
}
conn.connect();
int responseCode = conn.getResponseCode();
connInputStream = (responseCode < 400)? conn.getInputStream():conn.getErrorStream();
String responseMessage = conn.getResponseMessage();
Map<String, List<String>> responseHeaders = conn.getHeaderFields();
//复制响应头
for(Map.Entry<String, List<String>> en : responseHeaders.entrySet()) {
String key = en.getKey();
if (Tool.StrUtil.isEmpty(key) || "Transfer-Encoding".equals(key)) continue;
List<String> value = en.getValue();
ReflectUtil.invoke(response,"addHeader",key,Tool.StrUtil.join("; ",value));
}
ReflectUtil.invoke(response, "setStatus", responseCode, responseMessage);
Tool.IoUtil.copy(connInputStream, resOutputStream);
resOutputStream.flush();//flush 输出流
} catch (Exception e) {
try {
response.sendError(500, "request error");
} catch (IOException e1) {
log.error("proxy request error",e1);
}
log.error("request error : ",e);
}finally {
Tool.IoUtil.close(reqInputStream,resOutputStream,connOutputStream,connInputStream);
if(conn != null){
conn.disconnect();
}
}
}
}

View File

@@ -0,0 +1,9 @@
package net.geedge.confagent.entity;
import lombok.Data;
@Data
public class AuthEntity {
private String name;
private String pin;
}

View File

@@ -0,0 +1,66 @@
package net.geedge.confagent.interceptor;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import cn.hutool.log.Log;
import net.geedge.confagent.annotation.UnCheckToken;
import net.geedge.confagent.util.ConfagentUtil;
import net.geedge.confagent.util.R;
import net.geedge.confagent.util.RCode;
import net.geedge.confagent.util.Tool;
@Component
public class TokenInterceptor implements HandlerInterceptor {
private final static Log log = Log.get();
@Autowired
private ConfagentUtil confagentUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(handler instanceof HandlerMethod){
HandlerMethod handlerMethod = (HandlerMethod) handler;
Boolean hasAnnotation = Tool.AnnotationUtil.hasAnnotation(handlerMethod.getMethod(), UnCheckToken.class);
if(hasAnnotation){
return true;
}
hasAnnotation = Tool.AnnotationUtil.hasAnnotation(handlerMethod.getBeanType(),UnCheckToken.class);
if(hasAnnotation){
return true;
}
}
String token = request.getHeader("Authorization");
R r = confagentUtil.checkToken(token);
if(r.getCode() == RCode.SUCCESS.getCode()){
return true;
}
writeResult(response,r);
return false;
}
private void writeResult(HttpServletResponse response,Object o){
PrintWriter writer=null;
try{
writer = response.getWriter();
writer.print(Tool.JSONUtil.parse(o));
writer.flush();
}catch (IOException e){
log.error("un-know error",e);
}finally {
Tool.IoUtil.close(writer);
}
}
}

View File

@@ -0,0 +1,138 @@
package net.geedge.confagent.util;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.log.Log;
@Configuration
@Order(value = 1)
public class ConfagentUtil {
private final static Log log = Log.get();
@Value("${confagent.tokenFile:config/token.auth}")
protected String tokenFile; //token文件位置
@Value("${confagent.versionFile:promtail.version}")
private String versionFile;
private static String rootPath = Tool.WebPathUtil.getRootPath();
/**
* @Description 读取token文件中的token
* @Author rui
* @Date 2021/3/25
*/
public String readToken() throws IORuntimeException {
File tf = Tool.FileUtil.file(rootPath, tokenFile);
log.info("token file path : {}" ,tf.getAbsolutePath());
String token = Tool.FileUtil.readString(tf, Tool.CharsetUtil.UTF_8);
return token;
}
/**
* @Description 读取version
* @Author rui
* @Date 2021/3/25
*/
public String readVersion() throws IORuntimeException {
String version = "1";
File tf = Tool.FileUtil.file(rootPath, versionFile);
if(tf!=null && tf.exists()) {
log.info("version file path : {}" ,tf.getAbsolutePath());
version = Tool.FileUtil.readString(tf, Tool.CharsetUtil.UTF_8);
}
return version;
}
/**
* @Description 检查token 是否和文件中的一致
* @Author rui
* @Date 2021/3/25
*/
public R checkToken(String token){
if(Tool.StrUtil.isBlank(token)){
return R.error(RCode.AUTH_TOKEN_ISNULL);
}
try{
String readToken = this.readToken();
if(Tool.StrUtil.equals(readToken,token)){
return R.ok();
}
return R.error(RCode.AUTH_TOKEN_INVALID);
}catch (IORuntimeException e){
log.error("read token file failed",e);
return R.error(RCode.AUTH_READ_TOKEN_FAILD);
}
}
/**
* @Description 加载service EnvironmentFile中的内容并整理为map
* @Author rui
* @Date 2021/3/24
*/
public static Map<String,String> loadServiceConfigFile(String path){
File file = Tool.FileUtil.file(path);
if(!Tool.FileUtil.exist(file)){
return null;
}
String readLine = Tool.FileUtil.readUtf8String(file);
//匹配有参类型 --[\w\.-]+?\s 可匹配无参类型
Pattern pattern = Pattern.compile("--([\\w\\.-]+?)='?(.+?)'?\\s+?");
Matcher matcher = pattern.matcher(readLine);
Map<String, String> result = new HashMap<>();
while(matcher.find()){
result.put(matcher.group(1).trim(),matcher.group(2).trim());
}
return result;
}
/**
* @Description 获取配置在config.conf启动参数文件中的端口
* @Author rui
* @Date 2021/3/25
*/
public static Integer getConfFilePort(String path,String key,Integer defaultValue){
Map<String, String> configs = loadServiceConfigFile(path);
if(configs!=null) {
String address = configs.get(key);
String[] split = address.split(":");
return Tool.StrUtil.isNotBlank(split[1])? Integer.parseInt(split[1]):defaultValue;
}else {
return defaultValue;
}
}
public static void writeResponse(HttpServletResponse response, Object o) {
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
Tool.IoUtil.writeUtf8 (outputStream,true, Tool.JSONUtil.parseObj(o).toString());
outputStream.flush();
}catch (IOException e){
log.error("write response failed :",e);
}finally {
Tool.IoUtil.close(outputStream);
}
}
}

View File

@@ -0,0 +1,10 @@
package net.geedge.confagent.util;
public class IdUtil extends cn.hutool.core.util.IdUtil {
public static String fastShortUUID(){
String uuid = fastSimpleUUID();
return uuid.substring(0,8);
}
}

View File

@@ -0,0 +1,17 @@
package net.geedge.confagent.util;
import java.io.Closeable;
public class IoUtil extends cn.hutool.core.io.IoUtil {
public static void close(final Closeable ... closeables){
if (closeables == null) {
return;
}
for (final Closeable closeable:closeables){
close(closeable);
}
}
}

View File

@@ -0,0 +1,907 @@
package net.geedge.confagent.util;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.*;
import cn.hutool.json.*;
import cn.hutool.json.serialize.*;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.time.temporal.TemporalAccessor;
import java.util.*;
/**
* JSON工具类
*
* @author Looly
*/
public class JSONUtil {
// -------------------------------------------------------------------- Pause start
/**
* 创建JSONObject
*
* @return JSONObject
*/
public static JSONObject createObj() {
return new JSONObject();
}
/**
* 创建JSONObject
*
* @param config JSON配置
* @return JSONObject
* @since 5.2.5
*/
public static JSONObject createObj(JSONConfig config) {
return new JSONObject(config);
}
/**
* 创建 JSONArray
*
* @return JSONArray
*/
public static JSONArray createArray() {
return new JSONArray();
}
/**
* 创建 JSONArray
*
* @param config JSON配置
* @return JSONArray
* @since 5.2.5
*/
public static JSONArray createArray(JSONConfig config) {
return new JSONArray(config);
}
/**
* JSON字符串转JSONObject对象
*
* @param jsonStr JSON字符串
* @return JSONObject
*/
public static JSONObject parseObj(String jsonStr) {
return new JSONObject(jsonStr);
}
/**
* JSON字符串转JSONObject对象<br>
* 此方法会忽略空值但是对JSON字符串不影响
*
* @param obj Bean对象或者Map
* @return JSONObject
*/
public static JSONObject parseObj(Object obj) {
return new JSONObject(obj);
}
/**
* JSON字符串转JSONObject对象<br>
* 此方法会忽略空值但是对JSON字符串不影响
*
* @param obj Bean对象或者Map
* @param config JSON配置
* @return JSONObject
* @since 5.3.1
*/
public static JSONObject parseObj(Object obj, JSONConfig config) {
return new JSONObject(obj, config);
}
/**
* JSON字符串转JSONObject对象
*
* @param obj Bean对象或者Map
* @param ignoreNullValue 是否忽略空值如果source为JSON字符串不忽略空值
* @return JSONObject
* @since 3.0.9
*/
public static JSONObject parseObj(Object obj, boolean ignoreNullValue) {
return new JSONObject(obj, ignoreNullValue);
}
/**
* JSON字符串转JSONObject对象
*
* @param obj Bean对象或者Map
* @param ignoreNullValue 是否忽略空值如果source为JSON字符串不忽略空值
* @param isOrder 是否有序
* @return JSONObject
* @since 4.2.2
*/
public static JSONObject parseObj(Object obj, boolean ignoreNullValue, boolean isOrder) {
return new JSONObject(obj, ignoreNullValue, isOrder);
}
/**
* JSON字符串转JSONArray
*
* @param jsonStr JSON字符串
* @return JSONArray
*/
public static JSONArray parseArray(String jsonStr) {
return new JSONArray(jsonStr);
}
/**
* JSON字符串转JSONArray
*
* @param arrayOrCollection 数组或集合对象
* @return JSONArray
* @since 3.0.8
*/
public static JSONArray parseArray(Object arrayOrCollection) {
return new JSONArray(arrayOrCollection);
}
/**
* JSON字符串转JSONArray
*
* @param arrayOrCollection 数组或集合对象
* @param config JSON配置
* @return JSONArray
* @since 5.3.1
*/
public static JSONArray parseArray(Object arrayOrCollection, JSONConfig config) {
return new JSONArray(arrayOrCollection, config);
}
/**
* JSON字符串转JSONArray
*
* @param arrayOrCollection 数组或集合对象
* @param ignoreNullValue 是否忽略空值
* @return JSONArray
* @since 3.2.3
*/
public static JSONArray parseArray(Object arrayOrCollection, boolean ignoreNullValue) {
return new JSONArray(arrayOrCollection, ignoreNullValue);
}
/**
* 转换对象为JSON<br>
* 支持的对象:<br>
* String: 转换为相应的对象<br>
* Array Collection转换为JSONArray<br>
* Bean对象转为JSONObject
*
* @param obj 对象
* @return JSON
*/
public static JSON parse(Object obj) {
return parse(obj, JSONConfig.create());
}
/**
* 转换对象为JSON<br>
* 支持的对象:<br>
* String: 转换为相应的对象<br>
* Array、Iterable、Iterator转换为JSONArray<br>
* Bean对象转为JSONObject
*
* @param obj 对象
* @param config JSON配置
* @return JSON
* @since 5.3.1
*/
public static JSON parse(Object obj, JSONConfig config) {
if (null == obj) {
return null;
}
JSON json;
if (obj instanceof JSON) {
json = (JSON) obj;
} else if (obj instanceof CharSequence) {
final String jsonStr = StrUtil.trim((CharSequence) obj);
json = StrUtil.startWith(jsonStr, '[') ? parseArray(jsonStr) : parseObj(jsonStr);
} else if (obj instanceof Iterable || obj instanceof Iterator || ArrayUtil.isArray(obj)) {// 列表
json = new JSONArray(obj, config);
} else {// 对象
json = new JSONObject(obj, config);
}
return json;
}
/**
* XML字符串转为JSONObject
*
* @param xmlStr XML字符串
* @return JSONObject
*/
public static JSONObject parseFromXml(String xmlStr) {
return XML.toJSONObject(xmlStr);
}
/**
* Map转化为JSONObject
*
* @param map {@link Map}
* @return JSONObjec
* @deprecated 请直接使用 {@link #parseObj(Object)}
*/
@Deprecated
public static JSONObject parseFromMap(Map<?, ?> map) {
return new JSONObject(map);
}
/**
* ResourceBundle转化为JSONObject
*
* @param bundle ResourceBundle文件
* @return JSONObject
* @deprecated 请直接使用 {@link #parseObj(Object)}
*/
@Deprecated
public static JSONObject parseFromResourceBundle(ResourceBundle bundle) {
return new JSONObject(bundle);
}
// -------------------------------------------------------------------- Pause end
// -------------------------------------------------------------------- Read start
/**
* 读取JSON
*
* @param file JSON文件
* @param charset 编码
* @return JSON包括JSONObject和JSONArray
* @throws IORuntimeException IO异常
*/
public static JSON readJSON(File file, Charset charset) throws IORuntimeException {
return parse(FileReader.create(file, charset).readString());
}
/**
* 读取JSONObject
*
* @param file JSON文件
* @param charset 编码
* @return JSONObject
* @throws IORuntimeException IO异常
*/
public static JSONObject readJSONObject(File file, Charset charset) throws IORuntimeException {
return parseObj(FileReader.create(file, charset).readString());
}
/**
* 读取JSONArray
*
* @param file JSON文件
* @param charset 编码
* @return JSONArray
* @throws IORuntimeException IO异常
*/
public static JSONArray readJSONArray(File file, Charset charset) throws IORuntimeException {
return parseArray(FileReader.create(file, charset).readString());
}
// -------------------------------------------------------------------- Read end
// -------------------------------------------------------------------- toString start
/**
* 转为JSON字符串
*
* @param json JSON
* @param indentFactor 每一级别的缩进
* @return JSON字符串
*/
public static String toJsonStr(JSON json, int indentFactor) {
if (null == json) {
return null;
}
return json.toJSONString(indentFactor);
}
/**
* 转为JSON字符串
*
* @param json JSON
* @return JSON字符串
*/
public static String toJsonStr(JSON json) {
if (null == json) {
return null;
}
return json.toJSONString(0);
}
/**
* 转为JSON字符串并写出到write
*
* @param json JSON
* @param writer Writer
* @since 5.3.3
*/
public static void toJsonStr(JSON json, Writer writer) {
if (null != json) {
json.write(writer);
}
}
/**
* 转为JSON字符串
*
* @param json JSON
* @return JSON字符串
*/
public static String toJsonPrettyStr(JSON json) {
if (null == json) {
return null;
}
return json.toJSONString(4);
}
/**
* 转换为JSON字符串
*
* @param obj 被转为JSON的对象
* @return JSON字符串
*/
public static String toJsonStr(Object obj) {
if (null == obj) {
return null;
}
if (obj instanceof CharSequence) {
return StrUtil.str((CharSequence) obj);
}
return toJsonStr(parse(obj));
}
/**
* 转换为JSON字符串并写出到writer
*
* @param obj 被转为JSON的对象
* @param writer Writer
* @since 5.3.3
*/
public static void toJsonStr(Object obj, Writer writer) {
if (null != obj) {
toJsonStr(parse(obj), writer);
}
}
/**
* 转换为格式化后的JSON字符串
*
* @param obj Bean对象
* @return JSON字符串
*/
public static String toJsonPrettyStr(Object obj) {
return toJsonPrettyStr(parse(obj));
}
/**
* 转换为XML字符串
*
* @param json JSON
* @return XML字符串
*/
public static String toXmlStr(JSON json) {
return XML.toXml(json);
}
// -------------------------------------------------------------------- toString end
// -------------------------------------------------------------------- toBean start
/**
* JSON字符串转为实体类对象转换异常将被抛出
*
* @param <T> Bean类型
* @param jsonString JSON字符串
* @param beanClass 实体类对象
* @return 实体类对象
* @since 3.1.2
*/
public static <T> T toBean(String jsonString, Class<T> beanClass) {
return toBean(parseObj(jsonString), beanClass);
}
/**
* 转为实体类对象,转换异常将被抛出
*
* @param <T> Bean类型
* @param json JSONObject
* @param beanClass 实体类对象
* @return 实体类对象
*/
public static <T> T toBean(JSONObject json, Class<T> beanClass) {
return null == json ? null : json.toBean(beanClass);
}
/**
* JSON字符串转为实体类对象转换异常将被抛出
*
* @param <T> Bean类型
* @param jsonString JSON字符串
* @param typeReference {@link TypeReference}类型参考子类可以获取其泛型参数中的Type类型
* @param ignoreError 是否忽略错误
* @return 实体类对象
* @since 4.3.2
*/
public static <T> T toBean(String jsonString, TypeReference<T> typeReference, boolean ignoreError) {
return toBean(jsonString, typeReference.getType(), ignoreError);
}
/**
* JSON字符串转为实体类对象转换异常将被抛出
*
* @param <T> Bean类型
* @param jsonString JSON字符串
* @param beanType 实体类对象类型
* @param ignoreError 是否忽略错误
* @return 实体类对象
* @since 4.3.2
*/
public static <T> T toBean(String jsonString, Type beanType, boolean ignoreError) {
return toBean(parse(jsonString), beanType, ignoreError);
}
/**
* 转为实体类对象
*
* @param <T> Bean类型
* @param json JSONObject
* @param typeReference {@link TypeReference}类型参考子类可以获取其泛型参数中的Type类型
* @param ignoreError 是否忽略转换错误
* @return 实体类对象
* @since 4.6.2
*/
public static <T> T toBean(JSON json, TypeReference<T> typeReference, boolean ignoreError) {
return toBean(json, typeReference.getType(), ignoreError);
}
/**
* 转为实体类对象
*
* @param <T> Bean类型
* @param json JSONObject
* @param beanType 实体类对象类型
* @param ignoreError 是否忽略转换错误
* @return 实体类对象
* @since 4.3.2
*/
public static <T> T toBean(JSON json, Type beanType, boolean ignoreError) {
if (null == json) {
return null;
}
return json.toBean(beanType, ignoreError);
}
// -------------------------------------------------------------------- toBean end
/**
* 将JSONArray字符串转换为Bean的List默认为ArrayList
*
* @param <T> Bean类型
* @param jsonArray JSONArray字符串
* @param elementType List中元素类型
* @return List
* @since 5.5.2
*/
public static <T> List<T> toList(String jsonArray, Class<T> elementType) {
return toList(parseArray(jsonArray), elementType);
}
/**
* 将JSONArray转换为Bean的List默认为ArrayList
*
* @param <T> Bean类型
* @param jsonArray {@link JSONArray}
* @param elementType List中元素类型
* @return List
* @since 4.0.7
*/
public static <T> List<T> toList(JSONArray jsonArray, Class<T> elementType) {
return null == jsonArray ? null : jsonArray.toList(elementType);
}
/**
* 通过表达式获取JSON中嵌套的对象<br>
* <ol>
* <li>.表达式可以获取Bean对象中的属性字段值或者Map中key对应的值</li>
* <li>[]表达式可以获取集合等对象中对应index的值</li>
* </ol>
* <p>
* 表达式栗子:
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* </pre>
*
* @param json {@link JSON}
* @param expression 表达式
* @return 对象
* @see JSON#getByPath(String)
*/
public static Object getByPath(JSON json, String expression) {
return (null == json || StrUtil.isBlank(expression)) ? null : json.getByPath(expression);
}
/**
* 设置表达式指定位置或filed对应的值<br>
* 若表达式指向一个JSONArray则设置其坐标对应位置的值若指向JSONObject则put对应key的值<br>
* 注意如果为JSONArray则设置值得下标不能大于已有JSONArray的长度<br>
* <ol>
* <li>.表达式可以获取Bean对象中的属性字段值或者Map中key对应的值</li>
* <li>[]表达式可以获取集合等对象中对应index的值</li>
* </ol>
* <p>
* 表达式栗子:
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* </pre>
*
* @param json JSON可以为JSONObject或JSONArray
* @param expression 表达式
* @param value 值
*/
public static void putByPath(JSON json, String expression, Object value) {
json.putByPath(expression, value);
}
/**
* 对所有双引号做转义处理(使用双反斜杠做转义)<br>
* 为了能在HTML中较好的显示会将&lt;/转义为&lt;\/<br>
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
*
* @param string 字符串
* @return 适合在JSON中显示的字符串
*/
public static String quote(String string) {
return quote(string, true);
}
/**
* 对所有双引号做转义处理(使用双反斜杠做转义)<br>
* 为了能在HTML中较好的显示会将&lt;/转义为&lt;\/<br>
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
*
* @param string 字符串
* @param isWrap 是否使用双引号包装字符串
* @return 适合在JSON中显示的字符串
* @since 3.3.1
*/
public static String quote(String string, boolean isWrap) {
StringWriter sw = new StringWriter();
try {
return quote(string, sw, isWrap).toString();
} catch (IOException ignored) {
// will never happen - we are writing to a string writer
return StrUtil.EMPTY;
}
}
/**
* 对所有双引号做转义处理(使用双反斜杠做转义)<br>
* 为了能在HTML中较好的显示会将&lt;/转义为&lt;\/<br>
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
*
* @param str 字符串
* @param writer Writer
* @return Writer
* @throws IOException IO异常
*/
public static Writer quote(String str, Writer writer) throws IOException {
return quote(str, writer, true);
}
/**
* 对所有双引号做转义处理(使用双反斜杠做转义)<br>
* 为了能在HTML中较好的显示会将&lt;/转义为&lt;\/<br>
* JSON字符串中不能包含控制字符和未经转义的引号和反斜杠
*
* @param str 字符串
* @param writer Writer
* @param isWrap 是否使用双引号包装字符串
* @return Writer
* @throws IOException IO异常
* @since 3.3.1
*/
public static Writer quote(String str, Writer writer, boolean isWrap) throws IOException {
if (StrUtil.isEmpty(str)) {
if (isWrap) {
writer.write("\"\"");
}
return writer;
}
char b; // 前一个字符
char c; // 当前字符
int len = str.length();
if (isWrap) {
writer.write('"');
}
for (int i = 0; i < len; i++) {
// b = c;
c = str.charAt(i);
switch (c) {
case '\\':
case '"':
writer.write("\\");
writer.write(c);
break;
//此处转义导致输出不和预期一致
// case '/':
// if (b == '<') {
// writer.write('\\');
// }
// writer.write(c);
// break;
default:
writer.write(escape(c));
}
}
if (isWrap) {
writer.write('"');
}
return writer;
}
/**
* 转义显示不可见字符
*
* @param str 字符串
* @return 转义后的字符串
*/
public static String escape(String str) {
if (StrUtil.isEmpty(str)) {
return str;
}
final int len = str.length();
final StringBuilder builder = new StringBuilder(len);
char c;
for (int i = 0; i < len; i++) {
c = str.charAt(i);
builder.append(escape(c));
}
return builder.toString();
}
/**
* 在需要的时候包装对象<br>
* 包装包括:
* <ul>
* <li><code>null</code> =》 <code>JSONNull.NULL</code></li>
* <li>array or collection =》 JSONArray</li>
* <li>map =》 JSONObject</li>
* <li>standard property (Double, String, et al) =》 原对象</li>
* <li>来自于java包 =》 字符串</li>
* <li>其它 =》 尝试包装为JSONObject否则返回<code>null</code></li>
* </ul>
*
* @param object 被包装的对象
* @param jsonConfig JSON选项
* @return 包装后的值null表示此值需被忽略
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static Object wrap(Object object, JSONConfig jsonConfig) {
if (object == null) {
return jsonConfig.isIgnoreNullValue() ? null : JSONNull.NULL;
}
if (object instanceof JSON //
|| JSONNull.NULL.equals(object) //
|| object instanceof JSONString //
|| object instanceof CharSequence //
|| object instanceof Number //
|| ObjectUtil.isBasicType(object) //
) {
return object;
}
// 自定义序列化
final JSONSerializer serializer = GlobalSerializeMapping.getSerializer(object.getClass());
if (null != serializer) {
final Type jsonType = TypeUtil.getTypeArgument(serializer.getClass());
if (null != jsonType) {
if (serializer instanceof JSONObjectSerializer) {
serializer.serialize(new JSONObject(jsonConfig), object);
} else if (serializer instanceof JSONArraySerializer) {
serializer.serialize(new JSONArray(jsonConfig), object);
}
}
}
try {
// JSONArray
if (object instanceof Iterable || ArrayUtil.isArray(object)) {
return new JSONArray(object, jsonConfig);
}
// JSONObject
if (object instanceof Map) {
return new JSONObject(object, jsonConfig);
}
// 日期类型原样保存,便于格式化
if (object instanceof Date
|| object instanceof Calendar
|| object instanceof TemporalAccessor
) {
return object;
}
// 枚举类保存其字符串形式4.0.2新增)
if (object instanceof Enum) {
return object.toString();
}
// Java内部类不做转换
if (ClassUtil.isJdkClass(object.getClass())) {
return object.toString();
}
// 默认按照JSONObject对待
return new JSONObject(object, jsonConfig);
} catch (Exception exception) {
return null;
}
}
/**
* 格式化JSON字符串此方法并不严格检查JSON的格式正确与否
*
* @param jsonStr JSON字符串
* @return 格式化后的字符串
* @since 3.1.2
*/
public static String formatJsonStr(String jsonStr) {
return JSONStrFormater.format(jsonStr);
}
/**
* 是否为JSON字符串首尾都为大括号或中括号判定为JSON字符串
*
* @param str 字符串
* @return 是否为JSON字符串
* @since 3.3.0
*/
public static boolean isJson(String str) {
return isJsonObj(str) || isJsonArray(str);
}
/**
* 是否为JSONObject字符串首尾都为大括号判定为JSONObject字符串
*
* @param str 字符串
* @return 是否为JSON字符串
* @since 3.3.0
*/
public static boolean isJsonObj(String str) {
if (StrUtil.isBlank(str)) {
return false;
}
return StrUtil.isWrap(str.trim(), '{', '}');
}
/**
* 是否为JSONArray字符串首尾都为中括号判定为JSONArray字符串
*
* @param str 字符串
* @return 是否为JSON字符串
* @since 3.3.0
*/
public static boolean isJsonArray(String str) {
if (StrUtil.isBlank(str)) {
return false;
}
return StrUtil.isWrap(str.trim(), '[', ']');
}
/**
* 是否为null对象null的情况包括
*
* <pre>
* 1. {@code null}
* 2. {@link JSONNull}
* </pre>
*
* @param obj 对象
* @return 是否为null
* @since 4.5.7
*/
public static boolean isNull(Object obj) {
return null == obj || obj instanceof JSONNull;
}
/**
* XML转JSONObject<br>
* 转换过程中一些信息可能会丢失JSON中无法区分节点和属性相同的节点将被处理为JSONArray。
*
* @param xml XML字符串
* @return JSONObject
* @since 4.0.8
*/
public static JSONObject xmlToJson(String xml) {
return XML.toJSONObject(xml);
}
/**
* 加入自定义的序列化器
*
* @param type 对象类型
* @param serializer 序列化器实现
* @see GlobalSerializeMapping#put(Type, JSONArraySerializer)
* @since 4.6.5
*/
public static void putSerializer(Type type, JSONArraySerializer<?> serializer) {
GlobalSerializeMapping.put(type, serializer);
}
/**
* 加入自定义的序列化器
*
* @param type 对象类型
* @param serializer 序列化器实现
* @see GlobalSerializeMapping#put(Type, JSONObjectSerializer)
* @since 4.6.5
*/
public static void putSerializer(Type type, JSONObjectSerializer<?> serializer) {
GlobalSerializeMapping.put(type, serializer);
}
/**
* 加入自定义的反序列化器
*
* @param type 对象类型
* @param deserializer 反序列化器实现
* @see GlobalSerializeMapping#put(Type, JSONDeserializer)
* @since 4.6.5
*/
public static void putDeserializer(Type type, JSONDeserializer<?> deserializer) {
GlobalSerializeMapping.put(type, deserializer);
}
// --------------------------------------------------------------------------------------------- Private method start
/**
* 转义不可见字符<br>
* 见https://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF
*
* @param c 字符
* @return 转义后的字符串
*/
private static String escape(char c) {
switch (c) {
case '\b':
return "\\b";
case '\t':
return "\\t";
case '\n':
return "\\n";
case '\f':
return "\\f";
case '\r':
return "\\r";
default:
if (c < StrUtil.C_SPACE || //
(c >= '\u0080' && c <= '\u00a0') || //
(c >= '\u2000' && c <= '\u2010') || //
(c >= '\u2028' && c <= '\u202F') || //
(c >= '\u2066' && c <= '\u206F')//
) {
return HexUtil.toUnicodeHex(c);
} else {
return Character.toString(c);
}
}
}
// --------------------------------------------------------------------------------------------- Private method end
}

View File

@@ -0,0 +1,66 @@
package net.geedge.confagent.util;
import java.util.HashMap;
/**
* 返回数据
*
* 错误码、错误内容统一在枚举类RCode中定义 错误码格式见RCode注释错误码内容必须用英文作为国际化的code
* 自定义的错误类型必须加注释
*/
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public R() {
put("code", RCode.SUCCESS.getCode());
put("msg", RCode.SUCCESS.getMsg());
}
public static R error() {
return error(RCode.ERROR.getCode(), RCode.ERROR.getMsg());
}
public static R error(RCode rCode) {
R r = new R();
r.put("code", rCode.getCode());
r.put("msg", rCode.getMsg());
return r;
}
public static R error(Integer code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok() {
return new R();
}
public static R ok(Object data) {
R r = new R();
r.put("data", data);
return r;
}
@Override
public R put(String key, Object value) {
super.put(key, value);
return this;
}
public Integer getCode(){
return (Integer) super.get("code");
}
public String getMsg(){
return (String) super.get("msg");
}
}

View File

@@ -0,0 +1,41 @@
package net.geedge.confagent.util;
public enum RCode {
SUCCESS(200, "success"), //成功
AUTH_NAME_PIN_ISNULL(10000,"The name and password is required"),
AUTH_NAME_PIN_INVALID(10001,"The name or password is invalid"),
AUTH_TOKEN_INVALID(10002,"The token is invalid"),
AUTH_TOKEN_ISNULL(10003,"Token is required"),
AUTH_READ_TOKEN_FAILD(10004,"Read token failed"),
CONFIG_PROMTAIL_RELOAD_FAILED(10005,"Reload prometheus failed"),
CONFIG_BLAVKBOX_RELOAD_FAILED(10006,"Reload blackbox_exporter failed"),
CONFIG_SNMP_EXPORTER_RELOAD_FAILED(10007,"Reload snmp_exporter failed"),
PROMTAIL_CONFIG_VERSION_ISNULL(10008,"The promtail config version is required"),
PROMTAIL_START_CMD_ERROR(10009,"The promtail start command is error"),
PROMTAIL_STOP_CMD_ERROR(10010,"The promtail stop command is error"),
OTA_FILE_CACHE_ERROR(10011,"Cache rpm package failed"),
OTA_MD5_ERROR(10012,"MD5 is error"),
OTA_VERSION_ERROR(10013,"The updated version is lower than the current version"),
OTA_ATD_SERVICE_DOWN(10014,"The ATD service is down"),
ERROR(999, "error"); //通用错误/未知错误
private RCode(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
private Integer code;
private String msg;
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,112 @@
package net.geedge.confagent.util;
import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.yaml.snakeyaml.Yaml;
import java.io.BufferedReader;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class YamlUtil {
public static void writeAsMap(Map map,String path){
Map writeObj = map;
if(writeObj == null)
writeObj = new HashMap<>();
Yaml yaml = new Yaml();
Tool.FileUtil.writeUtf8String(yaml.dumpAsMap(writeObj), path);
}
/**
* @Description 将yaml文件中的内容读取到map中
* @Author rui
* @Date 2021/3/24
*/
public static Map<String,Object> readAsMap(String path){
File file = Tool.FileUtil.file(path);
Yaml yaml = new Yaml();
BufferedReader reader = Tool.FileUtil.getReader(file, Tool.CharsetUtil.UTF_8);
Map<String,Object> map = yaml.loadAs(reader, Map.class);
Tool.IoUtil.close(reader);
return map;
}
/**
* @Description 读取yaml文件中的属性支持spring.profiles.active 连点形式
* @Author rui
* @Date 2021/3/23
*/
public String readProperty(String file,String key){
Resource resource = getResource(file);
Properties properties = yamlToProperties(resource);
return properties.getProperty(key);
}
/**
* @Description 读取yaml文件中的属性可以指定默认值
* @Author rui
* @Date 2021/3/23
*/
public String readProperty(String file,String key,String defValue){
Resource resource = getResource(file);
Properties properties = yamlToProperties(resource);
return properties.getProperty(key,defValue);
}
/**
* @Description 获取application相关配置文件
* @Author rui
* @Date 2021/3/23
*/
public static Resource getApplication(String mode, String profile){
return getResource("application"+ (StrUtil.isEmpty(profile)?"":"-"+profile )+".yml");
}
/**
* @Description 获取配置文件
* @Author rui
* @Date 2021/3/23
*/
public static Resource getResource(String file){
return new FileSystemResource(file);
}
/**
* @Description 读取yaml文件并转为properties对象
* @Author rui
* @Date 2021/3/23
*/
public static Properties yamlToProperties(String file){
Resource resource = getResource(file);
return yamlToProperties(resource);
}
public static Properties yamlToProperties(String ... filepath){
return yamlToProperties(getFileAbsolutePath(filepath));
}
/**
* @Description 读取yaml文件并转为properties对象
* @Author rui
* @Date 2021/3/23
*/
public static Properties yamlToProperties(Resource resource){
YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
// 2:将加载的配置文件交给 YamlPropertiesFactoryBean
yamlPropertiesFactoryBean.setResources(resource);
// 3将yml转换成 keyval
return yamlPropertiesFactoryBean.getObject();
}
public static String getFileAbsolutePath(String ... path){
return Tool.FileUtil.file(path).getAbsolutePath();
}
}

View File

@@ -0,0 +1,12 @@
confagent:
promtail:
cmdLine: D:\config\config.conf
config: D:\config\promtail.yml
defaultIP: 192.168.40.42
startCmd: sh -c start_promtail.sh
stopCmd: kill -9 26590
resourcePath: ./
logging:
config: src/main/resources/logback-spring.xml

View File

@@ -0,0 +1,10 @@
confagent:
promtail:
cmdLine: /opt/nezha/promtail/config.conf
config: /opt/nezha/promtail/promtail.yaml
defaultIP: 127.0.0.1
startCmd: systemctl start promtail
stopCmd: systemctl stop promtail
logging:
config: config/logback-spring.xml

View File

@@ -0,0 +1,24 @@
server:
tomcat:
uri-encoding: UTF-8
basedir: /opt/nezha/nz-talon/tmp
port: 10092
servlet:
context-path: /nz-talon
spring:
profiles:
active: prod
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
enabled: true
confagent:
tokenFile: ./config/token.auth
authFile: ./config/auth.yml
versionFile: ./config/promtail.version
promtail:
query:
auth: false

View File

@@ -0,0 +1,3 @@
auth:
name: nezha
pin: nezha

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1 @@
088723c3

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.springframework.web" level="info" />
<logger name="org.springboot.sample" level="info" />
<logger name="org.apache" level="info" />
<logger name="org.springframework" level="info" />
<logger name="druid.sql" level="info" />
<logger name="com.springboot" level="debug" />
<property name="log.path" value="./logs/" />
<!-- 输出格式 -->
<property name="out.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n" />
<!-- 活动文件的大小 -->
<property name="max.file.size" value="100MB"/>
<!-- 保留的归档文件的最大数量 -->
<property name="max.history" value="30"/>
<!-- 控制所有归档日志文件的总大小 -->
<property name="total.size.cap" value="5GB"/>
<!-- 2.2 level为 INFO 日志,时间滚动输出 -->
<appender name="LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/nz-talon.log</file>
<!--日志文档输出格式 -->
<encoder>
<pattern>${out.pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/nz-talon-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>${max.file.size}</maxFileSize>
<maxHistory>${max.history}</maxHistory>
<totalSizeCap>${total.size.cap}</totalSizeCap>
</rollingPolicy>
</appender>
<!-- 2.1 level为 ERROR 日志,时间滚动输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/nz-talon-error.log</file>
<!--日志文档输出格式 -->
<encoder>
<pattern>${out.pattern}</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${log.path}/nz-talon-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>${max.file.size}</maxFileSize>
<maxHistory>${max.history}</maxHistory>
<totalSizeCap>${total.size.cap}</totalSizeCap>
</rollingPolicy>
<!-- 此日志文档只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="INFO">
<appender-ref ref="LOG_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</configuration>

View File

@@ -0,0 +1,13 @@
package net.geedge.confagent;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ConfagentApplicationTests {
@Test
void contextLoads() {
}
}

93
tools/afterinstall.sh Normal file
View File

@@ -0,0 +1,93 @@
#!/bin/sh
# Find Java
if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
JAVA_EXE="$JAVA_HOME/bin/java"
elif type -p java > /dev/null 2>&1; then
JAVA_EXE=$(type -p java)
elif [[ -x "/usr/bin/java" ]]; then
JAVA_EXE="/usr/bin/java"
else
echo "Unable to find Java"
JAVA_EXE="java"
# exit 1
fi
# install
if [ 1 -eq $1 ];then
cat > /usr/lib/systemd/system/nz-talon.service <<EOF
[Unit]
Description=nz-talon
After=network.target
[Service]
WorkingDirectory=/opt/nezha/nz-talon
ExecStart=/opt/nezha/nz-talon/xjar ${JAVA_EXE} -Dnz-agent.dir=/opt/nezha/nz-talon -jar /opt/nezha/nz-talon/nz-talon.xjar
RestartSec=5s
Restart=always
[Install]
WantedBy=multi-user.target
EOF
cat > /usr/lib/systemd/system/promtail.service <<"EOF"
[Unit]
Description=nz-talon
After=network.target
[Service]
WorkingDirectory=/opt/nezha/promtail
EnvironmentFile=/opt/nezha/promtail/config.conf
ExecStart=/opt/nezha/promtail/promtail $OPTION
RestartSec=5s
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable nz-talon && systemctl restart nz-talon
systemctl enable promtail && systemctl restart promtail
echo 'install nz-talon success !'
fi
compareMD5()
{
if [ ! -f $1 ] || [ ! -f $2 ];then
echo 1
return 1
fi
local f1MD5=`md5sum $1|awk '{print $1}'`
local f2MD5=`md5sum $2|awk '{print $1}'`
if [ ${f1MD5} = ${f2MD5} ];then
echo 0
return 0
else
echo 1
return 1
fi
}
# update
if [ 2 -eq $1 ];then
TALON_PATH=/opt/nezha/nz-talon
TMP_PATH=/tmp/nezha/nz-talon
PROMTAIL_PATH=/opt/nezha/promtail
echo 'move backup config file...'
if [ -d $TMP_PATH ];then
# 恢复 nz-talon 配置文件
for i in $(ls $TALON_PATH/config);do
if [ 1 -eq `compareMD5 $WEB_PATH/config/$i $TMP_PATH/config/$i` ];then
echo 'return config file '${i}
cp -f $TMP_PATH/config/$i $TALON_PATH/config/$i
fi
done
# 恢复 promtail 配置文件
for n in $(ls $TMP_PATH/promtail);do
if [ -f "$PROMTAIL_PATH/$n" ];then
echo 'return config file '${n}
cp -f $TMP_PATH/promtail/$n $PROMTAIL_PATH/$n
fi
done
fi
systemctl restart nz-talon
systemctl restart promtail
fi

20
tools/afterremove.sh Normal file
View File

@@ -0,0 +1,20 @@
#!/bin/sh
if [ 0 -eq $1 ];then
echo 'start remove nz-talon module from disk...'
systemctl stop nz-talon.service
systemctl stop promtail.service
rm -rf /opt/nezha/nz-talon
rm -rf /opt/nezha/promtail
systemctl disable nz-talon.service
systemctl disable promtail.service
rm -rf /usr/lib/systemd/system/{nz-talon.service,promtail.service}
systemctl daemon-reload
echo 'uninstall success!'
fi

32
tools/beforeinstall.sh Normal file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
TALON_PATH=/opt/nezha/nz-talon
PROMTAIL_PATH=/opt/nezha/promtail
if [ 2 -eq $1 ];then
if [ ! -d ${TALON_PATH}/config ];then
exit 0
fi
systemctl stop nz-talon
systemctl stop promtail
TMP_PATH=/tmp/nezha/nz-talon
rm -rf $TMP_PATH
mkdir -p $TMP_PATH
mkdir -p $TMP_PATH/promtail
cp -rf $TALON_PATH/config $TMP_PATH
[ -f "$PROMTAIL_PATH/promtail.yaml" ] && cp -rf $PROMTAIL_PATH/promtail.yaml $TMP_PATH/promtail
[ -f "$PROMTAIL_PATH/config.conf" ] && cp -rf $PROMTAIL_PATH/config.conf $TMP_PATH/promtail
echo 'backup config file from '${TALON_PATH}
if [ 0 -lt $(rpm -aq nz-talon|wc -w) ];then
echo 'clean before install...'
rm -rf $TALON_PATH
rm -rf $PROMTAIL_PATH
fi
fi

1
tools/config.conf Normal file
View File

@@ -0,0 +1 @@
OPTION=" -config.file /opt/nezha/promtail/promtail.yaml "

69
tools/package.sh Normal file
View File

@@ -0,0 +1,69 @@
#!/bin/bash
set -evx
CUR_PWD=`pwd`
PACKAGE_NAME=nz-talon
BRANCH_ARRAY=(${CI_COMMIT_REF_NAME//-/ })
PACKAGE_VERSION=${BRANCH_ARRAY[1]}.$CI_COMMIT_SHORT_SHA
ITERATION=Beta
if [[ "${BRANCH_ARRAY[0]}" == "rel" ]] ; then
ITERATION='Release';
fi
RPM_FULL_NAME=${PACKAGE_NAME}-${PACKAGE_VERSION}-${ITERATION}.x86_64.rpm
# 初始化 minio
mc alias set nz $MINIO_HOST $MINIO_USER $MINIO_PWD
BUILD_PATH=$CUR_PWD/build
RPM_TALON_PATH=$BUILD_PATH/opt/nezha/nz-talon
RPM_PROMTAIL_PATH=$BUILD_PATH/opt/nezha/promtail
mkdir -p $RPM_TALON_PATH $RPM_PROMTAIL_PATH
mkdir -p $RPM_TALON_PATH/config
echo 'packaging nz-talon ...'
#添加版本信息
cat >./src/main/resources/version.properties<<EOF
version=${BRANCH_ARRAY[1]}
commit=$CI_COMMIT_SHORT_SHA
buildDate=`date +'%Y%m%d%H%m%S'`
EOF
# mvn 编译 nz-talon
mvn clean install -Dxjar.password=111111 -Dxjar.excludes=/db/*,/static/**/*
cd ./target && go build xjar.go
cd $CUR_PWD
# 设置可执行权限
chmod +x ./target/xjar
cp -f ./target/nz-talon.xjar $RPM_TALON_PATH
cp -f ./target/xjar $RPM_TALON_PATH
cp -f ./src/main/resources/{application-prod.yml,application.yml,logback-spring.xml,config/auth.yml,config/token.auth,config/promtail.version} ${RPM_TALON_PATH}/config
sed -i 's/<property name="log.path" value=".*"/<property name="log.path" value="\/var\/log\/nezha\/nz-talon\/"/g' ${RPM_TALON_PATH}/config/logback-spring.xml
# 下载 promtail
mc cp nz/depends/loki/promtail-linux-amd64.zip ./
unzip -o promtail-linux-amd64.zip -d $RPM_PROMTAIL_PATH
mv $RPM_PROMTAIL_PATH/promtail-linux-amd64 $RPM_PROMTAIL_PATH/promtail
cp -f ./tools/config.conf $RPM_PROMTAIL_PATH
cp -f ./tools/promtail.yaml $RPM_PROMTAIL_PATH
#修改日志地址 2021_08_26
sed -i 's/<property name="log.path" value=".*"/<property name="log.path" value="\/var\/log\/nezha\/nz-talon\/"/g' ${RPM_TALON_PATH}/config/logback-spring.xml
fpm -s dir -t rpm -n ${PACKAGE_NAME} -v ${PACKAGE_VERSION} --iteration ${ITERATION} --rpm-os 'linux' \
--pre-install ./tools/beforeinstall.sh \
--post-install ./tools/afterinstall.sh \
--post-uninstall ./tools/afterremove.sh \
-C $BUILD_PATH -f \
-p $BUILD_PATH
# 计算md5值
cd $BUILD_PATH && md5sum $RPM_FULL_NAME > $RPM_FULL_NAME.md5sum.txt
cd $CUR_PWD
# 上传编译的rpm 文件
mc cp $BUILD_PATH/$RPM_FULL_NAME nz/release/nz-talon/$RPM_FULL_NAME
mc cp $BUILD_PATH/$RPM_FULL_NAME.md5sum.txt nz/release/nz-talon/$RPM_FULL_NAME.md5sum.txt
echo 'package nz-talon finished'

13
tools/promtail.yaml Normal file
View File

@@ -0,0 +1,13 @@
server:
http_listen_address: 127.0.0.1
http_listen_port: 19080
grpc_listen_port: 19081
positions:
filename: /tmp/positions.yaml
clients:
- url: http://127.0.0.1
scrape_configs:
- job_name: init
pipeline_stages:
syslog:
listen_address: 127.0.0.1:56799