wangrong
2026-08-30 4c949c0dc9bcae785c281c9d8125295f09810b15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
#!/bin/bash
action=$1
target=$2
 
DE_BASE=/opt
DE_RUNNING_BASE=${DE_BASE}/dataease2.0
need_init_apisix=false
compose_files="-f docker-compose.yml"
compose_cmd="docker-compose"
server_url=""
current_version=""
latest_version=""
 
set -a
source ${DE_RUNNING_BASE}/.env
set +a
export COMPOSE_HTTP_TIMEOUT=180
 
docker-compose version >/dev/null 2>&1
if [ $? -ne 0 ]; then
   docker compose version >/dev/null 2>&1
   if [ $? -ne 0 ]; then
      compose_cmd="docker compose"
   fi
fi
 
if [[ ! ${DE_EXTERNAL_MYSQL} ]] || [ "${DE_EXTERNAL_MYSQL}" = "false" ]; then
  compose_files="${compose_files} -f docker-compose-mysql.yml"
fi
 
function usage() {
   echo "DATAEASE 控制脚本"
   echo
   echo "Usage: "
   echo "  ./dectl [COMMAND] [ARGS...]"
   echo "  ./dectl --help"
   echo
   echo "Commands: "
   echo "  status                查看 DATAEASE 服务运行状态"
   echo "  start                 启动 DATAEASE 服务"
   echo "  stop                  停止 DATAEASE 服务"
   echo "  restart               重启 DATAEASE 服务"
   echo "  reload                重新加载 DATAEASE 服务"
   echo "  upgrade               升级 DATAEASE 服务"
   echo "  backup                备份 DATAEASE 服务"
   echo "  restore xxx.tar.gz    还原 DATAEASE 服务"
   echo "  clear-images          清理 DATAEASE 旧版本的相关镜像"
   echo "  clear-logs            清理 DATAEASE 历史日志"
   echo "  version               查看 DATAEASE 版本"
}
function _generate_compose_file_args() {
   if [[ $DE_INSTALL_MODE != "community" ]];then
      if [[ -f $DE_RUNNING_BASE/docker-compose-apisix.yml ]] && [[ "$DE_EXTERNAL_APISIX" != "true" ]];then
         compose_files="${compose_files} -f docker-compose-apisix.yml"
      fi
      
      if [[ -f $DE_RUNNING_BASE/docker-compose-task.yml ]] && [[ "$DE_EXTERNAL_SYNC_TASK" != "true" ]];then
         compose_files="${compose_files} -f docker-compose-task.yml"
      fi
 
      if [[ -f $DE_RUNNING_BASE/docker-compose-playwright.yml ]] && [[ "$DE_EXTERNAL_PLAYWRIGHT" != "true" ]];then
         compose_files="${compose_files} -f docker-compose-playwright.yml"
      fi
   fi
}
function _check_apisix_init() {
   if [[ $DE_INSTALL_MODE != "community" ]] && [[ "$DE_EXTERNAL_APISIX" != "true" ]];then
      _prepare_apisix
   fi
}
function _prepare_apisix() {
   if [[ -z $DE_APISIX_KEY ]];then
      need_init_apisix=true
      DE_APISIX_KEY=$(head -c 32 /dev/urandom | base64 | sed 's#/#+#g')
      export DE_APISIX_KEY=$DE_APISIX_KEY
      cd $DE_RUNNING_BASE
      env | grep DE_ >.env
      sed -i -e "s/DE_APISIX_KEY/${DE_APISIX_KEY}/g" $DE_RUNNING_BASE/apisix/apisix_conf/config.yaml
      sed -i -e "s/DE_APISIX_KEY/${DE_APISIX_KEY}/g" $DE_RUNNING_BASE/conf/application.yml
   fi
}
function _healthcheck() {
   echo
   container_name=$(grep "container_name" $DE_RUNNING_BASE/docker-compose.yml | awk -F': ' '{print $2}')
   sleep 1
   if [ -z $(docker ps --filter "name=$container_name" -q) ];then
      echo "未找到容器 $container_name。"
      exit 1
   fi
 
   for b in {1..90}
   do
      sleep 1
      read status healthy<<<$(docker inspect $container_name --format '{{.State.Status}} {{.State.Health.Status}}')
      if [[ "$healthy" == "starting" ]];then
         printf "\rDataEase 服务状态 : 正在启动 ... %3ds" $b
      elif [[ "$status" == "running" ]] && [[ "$healthy" == "healthy" ]];then
         printf "\rDataEase 服务状态 : 正常运行          "
         echo
         return;
      else
         echo
         echo -e "DataEase 服务状态 : \033[31m无法访问\033[0m"
         exit 1
      fi
   done
   echo
   echo "【警告】服务在等待时间内未完全启动!请稍后使用 dectl status 检查服务运行状况。"
   echo
}
function _get_current_version() {
   de_current_version=$(grep "^    image:.*dataease:" ${DE_RUNNING_BASE}/docker-compose.yml | awk -F'dataease:' '{print $2}')
   if test -z $de_current_version; then
      echo "获取当前版本失败,请检查当前版本是否正确"
      exit 1
   fi
   current_version=$de_current_version
}
function _get_available_server() {
   git_urls=('github.com')
 
   for git_url in ${git_urls[*]}; do      
      echo -ne "检测 ${git_url} ... "
      curl -m 5 -kIs https://${git_url} >/dev/null
      if [ $? != 0 ]; then
         echo "failed"
      else
         echo "ok"
         server_url=${git_url}
         break
      fi
   done
}
function _get_latest_version() {
   rm -f /tmp/de_latest_release
 
   _get_available_server
   if [[ "x${server_url}" == "x" ]];then
      echo "无法连接版本服务器,请稍候重试"
      exit 1
   fi
 
   if [[ -x "$(command -v python)" ]]; then
      py_cmd='python'
   elif [[ -x "$(command -v python3)" ]]; then
      py_cmd='python3'
   fi
 
   $py_cmd - <<EOF
# -*- coding: UTF-8 -*-
import os
import json
import re
 
latest_release=""
release_pattern="v2\.\d+\.\d+$"
 
def get_releases(page):
   try:
      releases=os.popen("curl -s https://api.github.com/repos/dataease/dataease/releases?page=%d" % (page)).read()
      releases=[ x["name"] for x in json.loads(releases) if x["prerelease"] == False ]
   except Exception as e:
      print(str(e))
      print("Failed to obtain Release information, please check the network.")
      exit(1)
   else:
      for release in releases:
         if re.search(release_pattern,release) != None:
            return release
 
page = 1
while (page <= 3):
   latest_release = get_releases(page)
   if (latest_release != "" and latest_release != None):
      break
   page += 1
 
if latest_release == None or latest_release == "":
   print("Failed to obtain latest version, please try again.")
   exit(1)
 
# 记录最新版本号
os.popen("echo "+latest_release+" > /tmp/de_latest_release")
EOF
 
   if [ ! -f /tmp/de_latest_release ]; then
      echo "获取最新版本失败,请检查网络连接是否正常"
      exit 1
   fi
   latest_version=$(cat /tmp/de_latest_release)
}
function status() {
   echo
   echo "DataEase 容器运行状态"
   _generate_compose_file_args
   cd ${DE_RUNNING_BASE}
   ${compose_cmd} ${compose_files} ps
 
   echo
   docker_root_dir=$(docker info | grep "Docker Root Dir"  | awk -F': ' '{print $2}')
   echo "Docker 目录及文件大小 : "
   du -sh $docker_root_dir
   echo
   echo "Docker 目录所在磁盘使用情况 : "
   df -H $docker_root_dir
 
   echo
   echo "日志文件大小 : "
   du -Sh ${DE_RUNNING_BASE}/logs/
 
   echo
   echo "DataEase 运行目录及文件大小 : "
   du -sh ${DE_BASE}
   echo
   echo "DataEase 运行目录使用情况 : "
   df -H ${DE_BASE}
 
   _healthcheck
}
function start() {
   echo
   _check_apisix_init
   _generate_compose_file_args
   cd ${DE_RUNNING_BASE}
   ${compose_cmd} ${compose_files} up -d
   _healthcheck
}
function stop() {
   echo
   _generate_compose_file_args
   cd ${DE_RUNNING_BASE}
   ${compose_cmd} ${compose_files} down -v ${target}
}
function restart() {
   stop
   start
}
function reload() {
   start
}
function version() {
   echo
   _get_current_version
   echo "current version is $current_version"
   _get_latest_version
   echo "latest version is $latest_version"
}
function upgrade() {
   version
 
   if [ "${latest_version}" = "" ]; then
      echo "未获取到最新版本"
      exit 1
   elif [ "${latest_version}" = "${current_version}" ]; then
      echo "最新版本与当前版本一致,退出升级过程"
      exit 0
   else
      if [[ ! "$latest_version" =~ ^v2.* ]];then
         echo "获取到的最新版本与当前版本不匹配,请访问 https://community.fit2cloud.com/#/products/dataease/downloads 下载离线安装包"
         exit 1
      else
         echo "检测到 ${server_url} 上最新版本为 ${latest_version} 即将执行在线升级..."
      fi
   fi
   sleep 2
 
   echo "开始下载最新版本..."
   echo "使用下载服务器 ${server_url}"
   cd /tmp
 
   installer_file="dataease-online-installer-${latest_version}-ce.tar.gz"
   download_url="https://${server_url}/dataease/dataease/releases/download/${latest_version}/$installer_file"
   curl -LOk -m 60 -o $installer_file $download_url
   if [ $? -ne 0 ]; then
      echo -e "\e[31m升级失败:连接下载服务器超时!\n可手动下载升级包,然后执行\e[1;33m /bin/bash install.sh \e[0;31m离线升级,也可以重新执行一次 dectl upgrade 命令。\e[0m"
      exit 1
   fi
 
   if [ ! -f $installer_file ]; then
      echo "下载在线安装包失败,请试试重新执行一次安装命令。"
      exit 1
   fi
 
   tar zxf $installer_file
   if [ $? != 0 ]; then
      echo "下载在线安装包失败,请试试重新执行一次安装命令。"
      rm -f $installer_file
      exit 1
   fi
 
   cd ${installer_file%.tar.gz}
   /bin/bash install.sh
 
   cd ..
   rm -rf /tmp/${installer_file%.*}
}
function clear_images() {
   echo
   for f in $DE_RUNNING_BASE/*.yml; do
      [[ -e "$f" ]] || break
      grep "^    image:.*:" "$f" | uniq | while read -r component_image_defined; do
         component_version=$(echo ${component_image_defined} | awk -F":" '{print $3}' | uniq)
         component_image=$(echo ${component_image_defined} | awk -F'image: ' '{print $2}' | awk -F':' '{print $1}')
 
         if [[ $(docker images | grep "$component_image[[:space:]]" | grep -v " $component_version " | wc -l) == 0 ]]; then
            echo "$component_image 不存在旧版本镜像"
         else
            echo "存在非当前版本镜像 : "
            docker images | grep "$component_image[[:space:]]" | grep -v " $component_version "
            echo "清理${component}镜像"
            docker rmi $(docker images | grep "$component_image[[:space:]]" | grep -v " $component_version " | awk -F' ' '{print $1":"$2}')
            echo "清理完毕"
         fi
      done
   done
 
   if [ $(docker images -f dangling=true -q | wc -l) -gt 0 ]; then
      echo "清理虚悬镜像"
      docker rmi $(docker images -f dangling=true -q)
      echo "清理完毕"
   fi
}
function clear_logs() {
   echo "开始清理 DataEase 历史日志"
   rm -rf ${DE_RUNNING_BASE}/logs/dataease/*.????-??-??.*.log
   rm -rf ${DE_RUNNING_BASE}/logs/dataease/sync-task/task-handler-log/*
   echo "" > ${DE_RUNNING_BASE}/logs/dataease/info.log
   echo "" > ${DE_RUNNING_BASE}/logs/dataease/error.log
   echo "清理完毕"
}
function backup() {
   # 检查当前目录是否在 DataEase 安装目录或其子目录下
   if [[ "$(pwd)" == "$DE_RUNNING_BASE" || "$(pwd)" == "$DE_RUNNING_BASE"/* ]]; then
      echo -e "\033[31m当前目录为 DataEase 安装目录,请切换到其他目录后再执行备份操作!\033[0m"
      exit 1
   fi
 
   need_stop=0
   if [[ -z $1 ]];then
      echo "如需备份 DataEase 数据,建议您先停止 DataEase 服务,以保证备份数据的完整性。"
      read -r -p "即将备份 DataEase 数据,是否需要停止 DataEase 服务? [Y/n] " input
 
      case $input in
         [yY][eE][sS]|[yY])
            echo "Yes"
            need_stop=1
            ;;
         [nN][oO]|[nN])
            echo "No"
            ;;
         *)
            echo "无效输入..."
            exit 1
            ;;
      esac
   elif [[ "$1" == "stop" ]];then
      need_stop=1
   fi
 
   if [[ $need_stop == 1 ]];then
      service dataease stop
   else
      echo "不停服进行备份"
   fi
 
   backup_file_name=dataease-backup-$(date +%Y%m%d)_$(date +%H%M%S).tar.gz
   tar --exclude=logs/dataease -zcf $backup_file_name -C $DE_RUNNING_BASE .
   if [ $? -ne 0 ]; then
      echo "备份失败"
      exit 1
   else
      echo "备份成功,备份文件 : $(pwd)/$backup_file_name"
   fi
 
   if [[ $need_stop == 1 ]];then
      service dataease start
   fi
}
function restore() {
   if [[ -z $target ]];then
      echo "未指定需要恢复的备份文件!"
      exit 1
   elif [[ -f $target ]];then
      service dataease stop
      if [[ ! -d $DE_RUNNING_BASE ]];then
         mkdir -p $DE_RUNNING_BASE
      fi
      echo "恢复备份 $target"
      rm -rf $DE_RUNNING_BASE/data/mysql/*
      tar -zxf $target --directory=$DE_RUNNING_BASE
      service dataease start
   else
      echo "未找到备份文件 $target!"
      exit 1
   fi
}
function main() {
   case "${action}" in
      status)
         status
         ;;
      start)
         start
         ;;
      stop)
         stop
         ;;
      restart)
         restart
         ;;
      reload)
         reload
         ;;
      upgrade)
         upgrade
         ;;
      backup)
         backup $target
         ;;
      restore)
         restore $target
         ;;
      clear-images)
         clear_images
         ;;
      clear-logs)
         clear_logs
         ;;
      version)
         version
         ;;
      help)
         usage
         ;;
      --help)
         usage
         ;;
      "")
         usage
         ;;
      *)
         echo "不支持的参数,请使用 help 或 --help 参数获取帮助"
         ;;
   esac
}
main