Browse Source

Merge remote-tracking branch 'upstream/branch-1.0.2' into 102

pull/2/head
baoliang 6 years ago
parent
commit
9f4e6438db
  1. 41
      Dockerfile
  2. 2
      README.md
  3. 31
      conf/escheduler.conf
  4. 310
      conf/install.sh
  5. 105
      conf/run.sh
  6. 30
      conf/zoo.cfg
  7. 10
      docs/zh_CN/后端部署文档.md
  8. 2
      escheduler-alert/src/main/resources/alert.properties
  9. 39
      escheduler-alert/src/main/resources/mail_templates/alert_mail_template.ftl
  10. 4
      escheduler-api/pom.xml
  11. 10
      escheduler-api/src/main/java/cn/escheduler/api/quartz/QuartzExecutors.java
  12. 7
      escheduler-api/src/main/java/cn/escheduler/api/service/SchedulerService.java
  13. 16
      escheduler-common/pom.xml
  14. 5
      escheduler-common/src/main/java/cn/escheduler/common/Constants.java
  15. 1
      escheduler-common/src/main/resources/zookeeper.properties
  16. 6
      escheduler-dao/pom.xml
  17. 4
      escheduler-server/pom.xml
  18. 56
      escheduler-server/src/main/java/cn/escheduler/server/zk/ZKMasterClient.java
  19. 5
      escheduler-ui/.env
  20. 240
      escheduler-ui/install-escheduler-ui.sh
  21. 18
      escheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss
  22. 25
      escheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue
  23. 17
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/sql.vue
  24. 20
      escheduler-ui/src/js/conf/home/pages/dag/_source/udp/udp.vue
  25. 16
      escheduler-ui/src/js/conf/home/pages/dag/_source/variable/index.vue
  26. 117
      escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/list.vue
  27. 2
      escheduler-ui/src/js/conf/home/pages/projects/pages/index/index.vue
  28. 7
      escheduler-ui/src/js/conf/home/pages/projects/pages/instance/pages/gantt/_source/gantt.js
  29. 80
      escheduler-ui/src/js/conf/home/pages/projects/pages/instance/pages/list/_source/list.vue
  30. 12
      escheduler-ui/src/js/conf/home/pages/projects/pages/taskInstance/_source/list.vue
  31. 2
      escheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/details/index.vue
  32. 3
      escheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue
  33. 15
      escheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/rename.vue
  34. 14
      escheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/rename.vue
  35. 19
      escheduler-ui/src/js/conf/home/pages/security/pages/tenement/_source/list.vue
  36. 36
      escheduler-ui/src/js/conf/home/store/dag/actions.js
  37. 6
      escheduler-ui/src/js/module/i18n/locale/en_US.js
  38. 6
      escheduler-ui/src/js/module/i18n/locale/zh_CN.js
  39. 46
      install.sh
  40. 2
      script/env/.escheduler_env.sh
  41. 40
      script/monitor_server.py

41
Dockerfile

@ -1,41 +0,0 @@
#Maintin by jimmy
#Email: zhengge2012@gmail.com
FROM anapsix/alpine-java:8_jdk
WORKDIR /tmp
RUN wget http://archive.apache.org/dist/maven/maven-3/3.6.1/binaries/apache-maven-3.6.1-bin.tar.gz
RUN tar -zxvf apache-maven-3.6.1-bin.tar.gz && rm apache-maven-3.6.1-bin.tar.gz
RUN mv apache-maven-3.6.1 /usr/lib/mvn
RUN chown -R root:root /usr/lib/mvn
RUN ln -s /usr/lib/mvn/bin/mvn /usr/bin/mvn
RUN wget https://archive.apache.org/dist/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz
RUN tar -zxvf zookeeper-3.4.6.tar.gz
RUN mv zookeeper-3.4.6 /opt/zookeeper
RUN rm -rf zookeeper-3.4.6.tar.gz
RUN echo "export ZOOKEEPER_HOME=/opt/zookeeper" >>/etc/profile
RUN echo "export PATH=$PATH:$ZOOKEEPER_HOME/bin" >>/etc/profile
ADD conf/zoo.cfg /opt/zookeeper/conf/zoo.cfg
#RUN source /etc/profile
#RUN zkServer.sh start
RUN apk add --no-cache git npm nginx mariadb mariadb-client mariadb-server-utils pwgen
WORKDIR /opt
RUN git clone https://github.com/analysys/EasyScheduler.git
WORKDIR /opt/EasyScheduler
RUN mvn -U clean package assembly:assembly -Dmaven.test.skip=true
RUN mv /opt/EasyScheduler/target/escheduler-1.0.0-SNAPSHOT /opt/easyscheduler
WORKDIR /opt/EasyScheduler/escheduler-ui
RUN npm install
RUN npm audit fix
RUN npm run build
RUN mkdir -p /opt/escheduler/front/server
RUN cp -rfv dist/* /opt/escheduler/front/server
WORKDIR /
RUN rm -rf /opt/EasyScheduler
#configure mysql server https://github.com/yobasystems/alpine-mariadb/tree/master/alpine-mariadb-amd64
ADD conf/run.sh /scripts/run.sh
RUN mkdir /docker-entrypoint-initdb.d && \
mkdir /scripts/pre-exec.d && \
mkdir /scripts/pre-init.d && \
chmod -R 755 /scripts
RUN rm -rf /var/cache/apk/*
EXPOSE 8888
ENTRYPOINT ["/scripts/run.sh"]

2
README.md

@ -1,4 +1,4 @@
Easy Scheduler
Easy Scheduler
============
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)

31
conf/escheduler.conf

@ -1,31 +0,0 @@
server {
listen 8888;# 访问端口
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /opt/escheduler/front/server; # 静态文件目录
index index.html index.html;
}
location /escheduler {
proxy_pass http://127.0.0.1:12345; # 接口地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header x_real_ipP $remote_addr;
proxy_set_header remote_addr $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_connect_timeout 4s;
proxy_read_timeout 30s;
proxy_send_timeout 12s;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

310
conf/install.sh

@ -1,310 +0,0 @@
#!/bin/sh
workDir=`/opt/easyscheduler`
workDir=`cd ${workDir};pwd`
#To be compatible with MacOS and Linux
txt=""
if [[ "$OSTYPE" == "darwin"* ]]; then
# Mac OSX
txt="''"
elif [[ "$OSTYPE" == "linux-gnu" ]]; then
# linux
txt=""
elif [[ "$OSTYPE" == "cygwin" ]]; then
# POSIX compatibility layer and Linux environment emulation for Windows
echo "Easy Scheduler not support Windows operating system"
exit 1
elif [[ "$OSTYPE" == "msys" ]]; then
# Lightweight shell and GNU utilities compiled for Windows (part of MinGW)
echo "Easy Scheduler not support Windows operating system"
exit 1
elif [[ "$OSTYPE" == "win32" ]]; then
echo "Easy Scheduler not support Windows operating system"
exit 1
elif [[ "$OSTYPE" == "freebsd"* ]]; then
# ...
txt=""
else
# Unknown.
echo "Operating system unknown, please tell us(submit issue) for better service"
exit 1
fi
source ${workDir}/conf/config/run_config.conf
source ${workDir}/conf/config/install_config.conf
# mysql配置
# mysql 地址,端口
mysqlHost="127.0.0.1:3306"
# mysql 数据库名称
mysqlDb="easyscheduler"
# mysql 用户名
mysqlUserName="easyscheduler"
# mysql 密码
mysqlPassword="easyschedulereasyscheduler"
# conf/config/install_config.conf配置
# 安装路径,不要当前路径(pwd)一样
installPath="/opt/easyscheduler"
# 部署用户
deployUser="escheduler"
# zk集群
zkQuorum="192.168.xx.xx:2181,192.168.xx.xx:2181,192.168.xx.xx:2181"
# 安装hosts
ips="ark0,ark1,ark2,ark3,ark4"
# conf/config/run_config.conf配置
# 运行Master的机器
masters="ark0,ark1"
# 运行Worker的机器
workers="ark2,ark3,ark4"
# 运行Alert的机器
alertServer="ark3"
# 运行Api的机器
apiServers="ark1"
# alert配置
# 邮件协议
mailProtocol="SMTP"
# 邮件服务host
mailServerHost="smtp.exmail.qq.com"
# 邮件服务端口
mailServerPort="25"
# 发送人
mailSender="xxxxxxxxxx"
# 发送人密码
mailPassword="xxxxxxxxxx"
# 下载Excel路径
xlsFilePath="/tmp/xls"
# hadoop 配置
# 是否启动hdfs,如果启动则为true,需要配置以下hadoop相关参数;
# 不启动设置为false,如果为false,以下配置不需要修改
hdfsStartupSate="false"
# namenode地址,支持HA,需要将core-site.xml和hdfs-site.xml放到conf目录下
namenodeFs="hdfs://mycluster:8020"
# resourcemanager HA配置,如果是单resourcemanager,这里为空即可
yarnHaIps="192.168.xx.xx,192.168.xx.xx"
# 如果是单 resourcemanager,只需要配置一个主机名称,如果是resourcemanager HA,则默认配置就好
singleYarnIp="ark1"
# hdfs根路径,根路径的owner必须是部署用户
hdfsPath="/escheduler"
# common 配置
# 程序路径
programPath="/tmp/escheduler"
#下载路径
downloadPath="/tmp/escheduler/download"
# 任务执行路径
execPath="/tmp/escheduler/exec"
# SHELL环境变量路径
shellEnvPath="$installPath/conf/env/.escheduler_env.sh"
# Python换将变量路径
pythonEnvPath="$installPath/conf/env/escheduler_env.py"
# 资源文件的后缀
resSuffixs="txt,log,sh,conf,cfg,py,java,sql,hql,xml"
# 开发状态,如果是true,对于SHELL脚本可以在execPath目录下查看封装后的SHELL脚本,如果是false则执行完成直接删除
devState="true"
# zk 配置
# zk根目录
zkRoot="/escheduler"
# 用来记录挂掉机器的zk目录
zkDeadServers="/escheduler/dead-servers"
# masters目录
zkMasters="/escheduler/masters"
# workers目录
zkWorkers="/escheduler/workers"
# zk master分布式锁
mastersLock="/escheduler/lock/masters"
# zk worker分布式锁
workersLock="/escheduler/lock/workers"
# zk master容错分布式锁
mastersFailover="/escheduler/lock/failover/masters"
# zk worker容错分布式锁
workersFailover="/escheduler/lock/failover/masters"
# zk session 超时
zkSessionTimeout="300"
# zk 连接超时
zkConnectionTimeout="300"
# zk 重试间隔
zkRetrySleep="100"
# zk重试最大次数
zkRetryMaxtime="5"
# master 配置
# master执行线程最大数,流程实例的最大并行度
masterExecThreads="100"
# master任务执行线程最大数,每一个流程实例的最大并行度
masterExecTaskNum="20"
# master心跳间隔
masterHeartbeatInterval="10"
# master任务提交重试次数
masterTaskCommitRetryTimes="5"
# master任务提交重试时间间隔
masterTaskCommitInterval="100"
# master最大cpu平均负载,用来判断master是否还有执行能力
masterMaxCupLoadAvg="10"
# master预留内存,用来判断master是否还有执行能力
masterReservedMemory="1"
# worker 配置
# worker执行线程
workerExecThreads="100"
# worker心跳间隔
workerHeartbeatInterval="10"
# worker一次抓取任务数
workerFetchTaskNum="10"
# worker最大cpu平均负载,用来判断master是否还有执行能力
workerMaxCupLoadAvg="10"
# worker预留内存,用来判断master是否还有执行能力
workerReservedMemory="1"
# api 配置
# api 服务端口
apiServerPort="12345"
# api session 超时
apiServerSessionTimeout="7200"
# api 上下文路径
apiServerContextPath="/escheduler/"
# spring 最大文件大小
springMaxFileSize="1024MB"
# spring 最大请求文件大小
springMaxRequestSize="1024MB"
# api 最大post请求大小
apiMaxHttpPostSize="5000000"
# 1,替换文件
echo "1,替换文件"
sed -i ${txt} "s#spring.datasource.url.*#spring.datasource.url=jdbc:mysql://${mysqlHost}/${mysqlDb}?characterEncoding=UTF-8#g" conf/dao/data_source.properties
sed -i ${txt} "s#spring.datasource.username.*#spring.datasource.username=${mysqlUserName}#g" conf/dao/data_source.properties
sed -i ${txt} "s#spring.datasource.password.*#spring.datasource.password=${mysqlPassword}#g" conf/dao/data_source.properties
sed -i ${txt} "s#org.quartz.dataSource.myDs.URL.*#org.quartz.dataSource.myDs.URL=jdbc:mysql://${mysqlHost}/${mysqlDb}?characterEncoding=UTF-8#g" conf/quartz.properties
sed -i ${txt} "s#org.quartz.dataSource.myDs.user.*#org.quartz.dataSource.myDs.user=${mysqlUserName}#g" conf/quartz.properties
sed -i ${txt} "s#org.quartz.dataSource.myDs.password.*#org.quartz.dataSource.myDs.password=${mysqlPassword}#g" conf/quartz.properties
sed -i ${txt} "s#fs.defaultFS.*#fs.defaultFS=${namenodeFs}#g" conf/common/hadoop/hadoop.properties
sed -i ${txt} "s#yarn.resourcemanager.ha.rm.ids.*#yarn.resourcemanager.ha.rm.ids=${yarnHaIps}#g" conf/common/hadoop/hadoop.properties
sed -i ${txt} "s#yarn.application.status.address.*#yarn.application.status.address=http://${singleYarnIp}:8088/ws/v1/cluster/apps/%s#g" conf/common/hadoop/hadoop.properties
sed -i ${txt} "s#data.basedir.path.*#data.basedir.path=${programPath}#g" conf/common/common.properties
sed -i ${txt} "s#data.download.basedir.path.*#data.download.basedir.path=${downloadPath}#g" conf/common/common.properties
sed -i ${txt} "s#process.exec.basepath.*#process.exec.basepath=${execPath}#g" conf/common/common.properties
sed -i ${txt} "s#data.store2hdfs.basepath.*#data.store2hdfs.basepath=${hdfsPath}#g" conf/common/common.properties
sed -i ${txt} "s#hdfs.startup.state.*#hdfs.startup.state=${hdfsStartupSate}#g" conf/common/common.properties
sed -i ${txt} "s#escheduler.env.path.*#escheduler.env.path=${shellEnvPath}#g" conf/common/common.properties
sed -i ${txt} "s#escheduler.env.py.*#escheduler.env.py=${pythonEnvPath}#g" conf/common/common.properties
sed -i ${txt} "s#resource.view.suffixs.*#resource.view.suffixs=${resSuffixs}#g" conf/common/common.properties
sed -i ${txt} "s#development.state.*#development.state=${devState}#g" conf/common/common.properties
sed -i ${txt} "s#zookeeper.quorum.*#zookeeper.quorum=${zkQuorum}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.root.*#zookeeper.escheduler.root=${zkRoot}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.dead.servers.*#zookeeper.escheduler.dead.servers=${zkDeadServers}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.masters.*#zookeeper.escheduler.masters=${zkMasters}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.workers.*#zookeeper.escheduler.workers=${zkWorkers}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.lock.masters.*#zookeeper.escheduler.lock.masters=${mastersLock}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.lock.workers.*#zookeeper.escheduler.lock.workers=${workersLock}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.lock.failover.masters.*#zookeeper.escheduler.lock.failover.masters=${mastersFailover}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.lock.failover.workers.*#zookeeper.escheduler.lock.failover.workers=${workersFailover}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.session.timeout.*#zookeeper.session.timeout=${zkSessionTimeout}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.connection.timeout.*#zookeeper.connection.timeout=${zkConnectionTimeout}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.retry.sleep.*#zookeeper.retry.sleep=${zkRetrySleep}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.retry.maxtime.*#zookeeper.retry.maxtime=${zkRetryMaxtime}#g" conf/zookeeper.properties
sed -i ${txt} "s#master.exec.threads.*#master.exec.threads=${masterExecThreads}#g" conf/master.properties
sed -i ${txt} "s#master.exec.task.number.*#master.exec.task.number=${masterExecTaskNum}#g" conf/master.properties
sed -i ${txt} "s#master.heartbeat.interval.*#master.heartbeat.interval=${masterHeartbeatInterval}#g" conf/master.properties
sed -i ${txt} "s#master.task.commit.retryTimes.*#master.task.commit.retryTimes=${masterTaskCommitRetryTimes}#g" conf/master.properties
sed -i ${txt} "s#master.task.commit.interval.*#master.task.commit.interval=${masterTaskCommitInterval}#g" conf/master.properties
sed -i ${txt} "s#master.max.cpuload.avg.*#master.max.cpuload.avg=${masterMaxCupLoadAvg}#g" conf/master.properties
sed -i ${txt} "s#master.reserved.memory.*#master.reserved.memory=${masterReservedMemory}#g" conf/master.properties
sed -i ${txt} "s#worker.exec.threads.*#worker.exec.threads=${workerExecThreads}#g" conf/worker.properties
sed -i ${txt} "s#worker.heartbeat.interval.*#worker.heartbeat.interval=${workerHeartbeatInterval}#g" conf/worker.properties
sed -i ${txt} "s#worker.fetch.task.num.*#worker.fetch.task.num=${workerFetchTaskNum}#g" conf/worker.properties
sed -i ${txt} "s#worker.max.cpuload.avg.*#worker.max.cpuload.avg=${workerMaxCupLoadAvg}#g" conf/worker.properties
sed -i ${txt} "s#worker.reserved.memory.*#worker.reserved.memory=${workerReservedMemory}#g" conf/worker.properties
sed -i ${txt} "s#server.port.*#server.port=${apiServerPort}#g" conf/application.properties
sed -i ${txt} "s#server.session.timeout.*#server.session.timeout=${apiServerSessionTimeout}#g" conf/application.properties
sed -i ${txt} "s#server.context-path.*#server.context-path=${apiServerContextPath}#g" conf/application.properties
sed -i ${txt} "s#spring.http.multipart.max-file-size.*#spring.http.multipart.max-file-size=${springMaxFileSize}#g" conf/application.properties
sed -i ${txt} "s#spring.http.multipart.max-request-size.*#spring.http.multipart.max-request-size=${springMaxRequestSize}#g" conf/application.properties
sed -i ${txt} "s#server.max-http-post-size.*#server.max-http-post-size=${apiMaxHttpPostSize}#g" conf/application.properties
sed -i ${txt} "s#mail.protocol.*#mail.protocol=${mailProtocol}#g" conf/alert.properties
sed -i ${txt} "s#mail.server.host.*#mail.server.host=${mailServerHost}#g" conf/alert.properties
sed -i ${txt} "s#mail.server.port.*#mail.server.port=${mailServerPort}#g" conf/alert.properties
sed -i ${txt} "s#mail.sender.*#mail.sender=${mailSender}#g" conf/alert.properties
sed -i ${txt} "s#mail.passwd.*#mail.passwd=${mailPassword}#g" conf/alert.properties
sed -i ${txt} "s#xls.file.path.*#xls.file.path=${xlsFilePath}#g" conf/alert.properties
sed -i ${txt} "s#installPath.*#installPath=${installPath}#g" conf/config/install_config.conf
sed -i ${txt} "s#deployUser.*#deployUser=${deployUser}#g" conf/config/install_config.conf
sed -i ${txt} "s#ips.*#ips=${ips}#g" conf/config/install_config.conf
sed -i ${txt} "s#masters.*#masters=${masters}#g" conf/config/run_config.conf
sed -i ${txt} "s#workers.*#workers=${workers}#g" conf/config/run_config.conf
sed -i ${txt} "s#alertServer.*#alertServer=${alertServer}#g" conf/config/run_config.conf
sed -i ${txt} "s#apiServers.*#apiServers=${apiServers}#g" conf/config/run_config.conf

105
conf/run.sh

@ -1,105 +0,0 @@
#!/bin/sh
# execute any pre-init scripts
for i in /scripts/pre-init.d/*sh
do
if [ -e "${i}" ]; then
echo "[i] pre-init.d - processing $i"
. "${i}"
fi
done
if [ -d "/run/mysqld" ]; then
echo "[i] mysqld already present, skipping creation"
chown -R mysql:mysql /run/mysqld
else
echo "[i] mysqld not found, creating...."
mkdir -p /run/mysqld
chown -R mysql:mysql /run/mysqld
fi
if [ -d /var/lib/mysql/mysql ]; then
echo "[i] MySQL directory already present, skipping creation"
chown -R mysql:mysql /var/lib/mysql
else
echo "[i] MySQL data directory not found, creating initial DBs"
chown -R mysql:mysql /var/lib/mysql
mysql_install_db --user=mysql --ldata=/var/lib/mysql > /dev/null
if [ "$MYSQL_ROOT_PASSWORD" = "" ]; then
MYSQL_ROOT_PASSWORD=`pwgen 16 1`
echo "[i] MySQL root Password: $MYSQL_ROOT_PASSWORD"
fi
MYSQL_DATABASE="easyscheduler"
MYSQL_USER="easyscheduler"
MYSQL_PASSWORD="easyschedulereasyscheduler"
tfile=`mktemp`
if [ ! -f "$tfile" ]; then
return 1
fi
cat << EOF > $tfile
USE mysql;
FLUSH PRIVILEGES ;
GRANT ALL ON *.* TO 'root'@'%' identified by '$MYSQL_ROOT_PASSWORD' WITH GRANT OPTION ;
GRANT ALL ON *.* TO 'root'@'localhost' identified by '$MYSQL_ROOT_PASSWORD' WITH GRANT OPTION ;
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MYSQL_ROOT_PASSWORD}') ;
DROP DATABASE IF EXISTS test ;
FLUSH PRIVILEGES ;
EOF
if [ "$MYSQL_DATABASE" != "" ]; then
echo "[i] Creating database: $MYSQL_DATABASE"
echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` CHARACTER SET utf8 COLLATE utf8_general_ci;" >> $tfile
if [ "$MYSQL_USER" != "" ]; then
echo "[i] Creating user: $MYSQL_USER with password $MYSQL_PASSWORD"
echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* to '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';" >> $tfile
fi
fi
/usr/bin/mysqld --user=mysql --bootstrap --verbose=0 --skip-name-resolve --skip-networking=0 < $tfile
rm -f $tfile
for f in /docker-entrypoint-initdb.d/*; do
case "$f" in
*.sql) echo "$0: running $f"; /usr/bin/mysqld --user=mysql --bootstrap --verbose=0 --skip-name-resolve --skip-networking=0 < "$f"; echo ;;
*.sql.gz) echo "$0: running $f"; gunzip -c "$f" | /usr/bin/mysqld --user=mysql --bootstrap --verbose=0 --skip-name-resolve --skip-networking=0 < "$f"; echo ;;
*) echo "$0: ignoring or entrypoint initdb empty $f" ;;
esac
echo
done
echo
echo 'MySQL init process done. Ready for start up.'
echo
echo "exec /usr/bin/mysqld --user=mysql --console --skip-name-resolve --skip-networking=0" "$@"
fi
# execute any pre-exec scripts
for i in /scripts/pre-exec.d/*sh
do
if [ -e "${i}" ]; then
echo "[i] pre-exec.d - processing $i"
. ${i}
fi
done
mysql -ueasyscheduler -peasyschedulereasyscheduler --one-database easyscheduler -h127.0.0.1 < /opt/easyscheduler/sql/escheduler.sql
mysql -ueasyscheduler -peasyschedulereasyscheduler --one-database easyscheduler -h127.0.0.1 < /opt/easyscheduler/sql/quartz.sql
source /etc/profile
zkServer.sh start
cd /opt/easyscheduler
rm -rf /etc/nginx/conf.d/default.conf
sh ./bin/escheduler-daemon.sh start master-server
sh ./bin/escheduler-daemon.sh start worker-server
sh ./bin/escheduler-daemon.sh start api-server
sh ./bin/escheduler-daemon.sh start logger-server
sh ./bin/escheduler-daemon.sh start alert-server
nginx -c /etc/nginx/nginx.conf
exec /usr/bin/mysqld --user=mysql --console --skip-name-resolve --skip-networking=0 $@

30
conf/zoo.cfg

@ -1,30 +0,0 @@
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
dataDir=/opt/zookeeper/data
dataLogDir=/opt/zookeeper/logs

10
docs/zh_CN/后端部署文档.md

@ -4,7 +4,7 @@
## 1、准备工作
目前最新安装包版本是1.0.2,下载地址: [码云下载](https://gitee.com/easyscheduler/EasyScheduler/attach_files/) ,下载escheduler-backend-1.0.2.tar.gz(后端简称escheduler-backend),escheduler-ui-1.0.2.tar.gz(前端简称escheduler-ui)
目前最新安装包版本是1.0.3,下载地址: [码云下载](https://gitee.com/easyscheduler/EasyScheduler/attach_files/) ,下载escheduler-backend-1.0.3.tar.gz(后端简称escheduler-backend),escheduler-ui-1.0.3.tar.gz(前端简称escheduler-ui)
#### 准备一: 基础软件安装(必装项请自行安装)
@ -101,6 +101,12 @@ install.sh : 一键部署脚本
- 修改部署参数(根据自己服务器及业务情况):
- 修改 **install.sh**中的各参数,替换成自身业务所需的值
- monitorServerState 开关变量,在1.0.3版本中增加,控制是否启动自启动脚本(监控master,worker状态,如果掉线会自动启动)
默认值为"false"表示不启动自启动脚本,如果需要启动改为"true"
- hdfsStartupSate 开关变量,控制是否启动hdfs
默认值为"false"表示不启动hdfs
如果需要启动改为"true",启动hdfs需要自行创建hdfs根路径,也就是install.sh中的 hdfsPath
- 如果使用hdfs相关功能,需要拷贝**hdfs-site.xml**和**core-site.xml**到conf目录下
@ -143,7 +149,7 @@ install.sh : 一键部署脚本
### 2.2 编译源码来部署
将源码包release版本1.0.2下载后,解压进入根目录
将源码包release版本1.0.3下载后,解压进入根目录
* 执行编译命令:

2
escheduler-alert/src/main/resources/alert.properties

@ -9,7 +9,7 @@ mail.sender=xxxxxxx
mail.passwd=xxxxxxx
#xls file path,need create if not exist
xls.file.path=/opt/xls
xls.file.path=/tmp/xls

39
escheduler-alert/src/main/resources/mail_templates/alert_mail_template.ftl

@ -1,38 +1 @@
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>
<html>
<head><title> easyscheduler </title>
<meta name='Keywords' content=''>
<meta name='Description' content=''>
<style type="text/css">table {
font-size: 14px;
color: #333333;
border-width: 1px;
border-color: #666666;
border-collapse: collapse;
}
table th {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: #dedede;
}
table td {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: #ffffff;
}</style>
</head>
<body>
<table>
<thead>
<#if title??> ${title} </#if>
</thead>
<#if content??> ${content} </#if>
</table>
</body>
</html>
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'><html><head><title> easyscheduler</title><meta name='Keywords' content=''><meta name='Description' content=''><style type="text/css">table { margin-top:0px; padding-top:0px; border:1px solid; font-size: 14px; color: #333333; border-width: 1px; border-color: #666666; border-collapse: collapse; } table th { border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #dedede; } table td { border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #ffffff; }</style></head><body style="margin:0;padding:0"><table border="1px" cellpadding="5px" cellspacing="-10px"><thead><#if title??> ${title}</#if></thead><#if content??> ${content}</#if></table></body></html>

4
escheduler-api/pom.xml

@ -34,6 +34,10 @@
<artifactId>leveldbjni-all</artifactId>
<groupId>org.fusesource.leveldbjni</groupId>
</exclusion>
<exclusion>
<artifactId>protobuf-java</artifactId>
<groupId>com.google.protobuf</groupId>
</exclusion>
</exclusions>
</dependency>

10
escheduler-api/src/main/java/cn/escheduler/api/quartz/QuartzExecutors.java

@ -26,8 +26,8 @@ import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.*;
import java.util.Calendar;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@ -226,8 +226,12 @@ public class QuartzExecutors {
public boolean deleteJob(String jobName, String jobGroupName) {
lock.writeLock().lock();
try {
logger.info("try to delete job, job name: {}, job group name: {},", jobName, jobGroupName);
return scheduler.deleteJob(new JobKey(jobName, jobGroupName));
JobKey jobKey = new JobKey(jobName,jobGroupName);
if(scheduler.checkExists(jobKey)){
logger.info("try to delete job, job name: {}, job group name: {},", jobName, jobGroupName);
return scheduler.deleteJob(jobKey);
}
} catch (SchedulerException e) {
logger.error(String.format("delete job : %s failed",jobName), e);
} finally {

7
escheduler-api/src/main/java/cn/escheduler/api/service/SchedulerService.java

@ -514,6 +514,13 @@ public class SchedulerService extends BaseService {
putMsg(result, Status.SCHEDULE_CRON_NOT_EXISTS, scheduleId);
return result;
}
// Determine if the login user is the owner of the schedule
if (loginUser.getId() != schedule.getUserId()) {
putMsg(result, Status.USER_NO_OPERATION_PERM);
return result;
}
// check schedule is already online
if(schedule.getReleaseState() == ReleaseState.ONLINE){
putMsg(result, Status.SCHEDULE_CRON_STATE_ONLINE,schedule.getId());

16
escheduler-common/pom.xml

@ -148,10 +148,10 @@
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</exclusion>
<!--<exclusion>-->
<!--<groupId>com.google.protobuf</groupId>-->
<!--<artifactId>protobuf-java</artifactId>-->
<!--</exclusion>-->
</exclusions>
</dependency>
@ -175,10 +175,10 @@
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</exclusion>
<!--<exclusion>-->
<!--<groupId>com.google.protobuf</groupId>-->
<!--<artifactId>protobuf-java</artifactId>-->
<!--</exclusion>-->
<exclusion>
<groupId>org.fusesource.leveldbjni</groupId>
<artifactId>leveldbjni-all</artifactId>

5
escheduler-common/src/main/java/cn/escheduler/common/Constants.java

@ -162,6 +162,11 @@ public final class Constants {
*/
public static final String ZOOKEEPER_ESCHEDULER_LOCK_FAILOVER_WORKERS = "zookeeper.escheduler.lock.failover.workers";
/**
* MasterServer startup failover runing and fault tolerance process
*/
public static final String ZOOKEEPER_ESCHEDULER_LOCK_FAILOVER_STARTUP_MASTERS = "zookeeper.escheduler.lock.failover.startup.masters";
/**
* need send warn times when master server or worker server failover
*/

1
escheduler-common/src/main/resources/zookeeper.properties

@ -16,6 +16,7 @@ zookeeper.escheduler.lock.workers=/escheduler/lock/workers
#escheduler failover directory
zookeeper.escheduler.lock.failover.masters=/escheduler/lock/failover/masters
zookeeper.escheduler.lock.failover.workers=/escheduler/lock/failover/workers
zookeeper.escheduler.lock.failover.startup.masters=/escheduler/lock/failover/startup-masters
#escheduler failover directory
zookeeper.session.timeout=300

6
escheduler-dao/pom.xml

@ -125,6 +125,12 @@
<dependency>
<groupId>cn.analysys</groupId>
<artifactId>escheduler-common</artifactId>
<exclusions>
<exclusion>
<artifactId>protobuf-java</artifactId>
<groupId>com.google.protobuf</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>

4
escheduler-server/pom.xml

@ -18,6 +18,10 @@
<groupId>cn.analysys</groupId>
<artifactId>escheduler-common</artifactId>
<exclusions>
<exclusion>
<artifactId>protobuf-java</artifactId>
<groupId>com.google.protobuf</groupId>
</exclusion>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>

56
escheduler-server/src/main/java/cn/escheduler/server/zk/ZKMasterClient.java

@ -31,6 +31,7 @@ import cn.escheduler.dao.model.TaskInstance;
import cn.escheduler.server.ResInfo;
import cn.escheduler.server.utils.ProcessUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.imps.CuratorFrameworkState;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
@ -111,21 +112,46 @@ public class ZKMasterClient extends AbstractZKClient {
// init dao
this.initDao();
// init system znode
this.initSystemZNode();
InterProcessMutex mutex = null;
try {
// create distributed lock with the root node path of the lock space as /escheduler/lock/failover/master
String znodeLock = getMasterStartUpLockPath();
mutex = new InterProcessMutex(zkClient, znodeLock);
mutex.acquire();
// init system znode
this.initSystemZNode();
// monitor master
this.listenerMaster();
// monitor master
this.listenerMaster();
// monitor worker
this.listenerWorker();
// monitor worker
this.listenerWorker();
// register master
this.registMaster();
// register master
this.registMaster();
// check if fault tolerance is required,failure and tolerance
if (getActiveMasterNum() == 1) {
processDao.selfFaultTolerant(ExecutionStatus.RUNNING_EXEUTION.ordinal(),ExecutionStatus.NEED_FAULT_TOLERANCE.ordinal());
}
}catch (Exception e){
logger.error("master start up exception : " + e.getMessage(),e);
}finally {
if (mutex != null){
try {
mutex.release();
} catch (Exception e) {
if(e.getMessage().equals("instance must be started before calling this method")){
logger.warn("lock release");
}else{
logger.error("lock release failed : " + e.getMessage(),e);
}
// check if fault tolerance is required,failure and tolerance
if (getActiveMasterNum() == 1) {
processDao.selfFaultTolerant(ExecutionStatus.RUNNING_EXEUTION.ordinal(),ExecutionStatus.NEED_FAULT_TOLERANCE.ordinal());
}
}
}
}
@ -417,6 +443,14 @@ public class ZKMasterClient extends AbstractZKClient {
return conf.getString(Constants.ZOOKEEPER_ESCHEDULER_LOCK_MASTERS);
}
/**
* get master start up lock path
* @return
*/
public String getMasterStartUpLockPath(){
return conf.getString(Constants.ZOOKEEPER_ESCHEDULER_LOCK_FAILOVER_STARTUP_MASTERS);
}
/**
* get master failover lock path
* @return

5
escheduler-ui/.env

@ -1,6 +1,5 @@
# 后端接口地址11
# 后端接口地址
API_BASE = http://192.168.xx.xx:12345
# 本地开发如需ip访问项目把"#"号去掉
#DEV_HOST = 192.168.xx.xx
#DEV_HOST = 192.168.xx.xx

240
escheduler-ui/install-escheduler-ui.sh

@ -1,66 +1,17 @@
#!/bin/bash
# 当前路径
esc_basepath=$(cd `dirname $0`; pwd)
echo "欢迎使用easy scheduler前端部署脚本,目前前端部署脚本仅支持Centos"
echo "请在 escheduler-ui 目录下执行"
# 配置前端访问端口
esc_proxy="8888"
# 配置代理后端接口
esc_proxy_port="http://192.168.xx.xx:12345"
# 本机ip
esc_ipaddr='127.0.0.1'
esc_ipaddr=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}')
#To be compatible with MacOS and Linux
if [[ "$OSTYPE" == "darwin"* ]]; then
# Mac OSX
echo "Easy Scheduler ui install not support Mac OSX operating system"
exit 1
elif [[ "$OSTYPE" == "linux-gnu" ]]; then
# linux
echo "linux"
elif [[ "$OSTYPE" == "cygwin" ]]; then
# POSIX compatibility layer and Linux environment emulation for Windows
echo "Easy Scheduler ui not support Windows operating system"
exit 1
elif [[ "$OSTYPE" == "msys" ]]; then
# Lightweight shell and GNU utilities compiled for Windows (part of MinGW)
echo "Easy Scheduler ui not support Windows operating system"
exit 1
elif [[ "$OSTYPE" == "win32" ]]; then
echo "Easy Scheduler ui not support Windows operating system"
exit 1
elif [[ "$OSTYPE" == "freebsd"* ]]; then
# ...
echo "freebsd"
else
# Unknown.
echo "Operating system unknown, please tell us(submit issue) for better service"
exit 1
fi
# 区分版本
version=`cat /etc/redhat-release|sed -r 's/.* ([0-9]+)\..*/\1/'`
echo "========================================================================配置信息======================================================================="
echo "前端访问端口:${esc_proxy}"
echo "后端代理接口地址:${esc_proxy_port}"
echo "静态文件地址:${esc_basepath}/dist"
echo "当前路径:${esc_basepath}"
echo "本机ip:${esc_ipaddr}"
echo "========================================================================配置信息======================================================================="
echo ""
menu(){
cat <<END
=================================================
1.CentOS6安装
2.CentOS7安装
3.Ubuntu安装
4.退出
=================================================
END
}
# 创建文件并配置nginx
@ -72,7 +23,7 @@ eschedulerConf(){
E_http_upgrade='$http_upgrade'
echo "
server {
listen $esc_proxy;# 访问端口
listen $1;# 访问端口
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
@ -81,16 +32,16 @@ eschedulerConf(){
index index.html index.html;
}
location /escheduler {
proxy_pass ${esc_proxy_port}; # 接口地址
proxy_pass $2; # 接口地址
proxy_set_header Host $E_host;
proxy_set_header X-Real-IP $E_remote_addr;
proxy_set_header x_real_ipP $E_remote_addr;
proxy_set_header remote_addr $E_remote_addr;
proxy_set_header X-Forwarded-For $E_proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_connect_timeout 4s;
proxy_read_timeout 30s;
proxy_send_timeout 12s;
proxy_connect_timeout 300s;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_set_header Upgrade $E_http_upgrade;
proxy_set_header Connection "upgrade";
}
@ -106,15 +57,32 @@ eschedulerConf(){
}
ubuntu(){
#更新源
apt-get update
#安装nginx
apt-get install -y nginx
# 配置nginx
eschedulerConf $1 $2
# 启动nginx
/etc/init.d/nginx start
sleep 1
if [ $? -ne 0 ];then
/etc/init.d/nginx start
fi
nginx -s reload
}
centos7(){
# nginx是否安装
sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
sudo yum install -y nginx
echo "nginx 安装成功"
rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
yum install -y nginx
# 配置nginx
eschedulerConf
eschedulerConf $1 $2
# 解决 0.0.0.0:8888 问题
yum -y install policycoreutils-python
@ -123,11 +91,13 @@ centos7(){
# 开放前端访问端口
firewall-cmd --zone=public --add-port=$esc_proxy/tcp --permanent
# 重启防火墙
firewall-cmd --reload
# 启动nginx
systemctl start nginx
sleep 1
if [ $? -ne 0 ];then
systemctl start nginx
fi
nginx -s reload
# 调整SELinux的参数
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
@ -138,37 +108,22 @@ centos7(){
centos6(){
# yum
E_basearch='$basearch'
E_releasever='$releasever'
echo "
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$E_releasever/$E_basearch/
gpgcheck=0
enabled=1
" >> /etc/yum.repos.d/nginx.repo
rpm -ivh http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm
# install nginx
yum install nginx -y
# 配置nginx
eschedulerConf
# 防火墙
E_iptables=`lsof -i:$esc_proxy | wc -l`
if [ "$E_iptables" -gt "0" ];then
# 已开启端口防火墙重启
service iptables restart
else
# 未开启防火墙添加端口再重启
iptables -I INPUT 5 -i eth0 -p tcp --dport $esc_proxy -m state --state NEW,ESTABLISHED -j ACCEPT
service iptables save
service iptables restart
fi
eschedulerConf $1 $2
# start
# 启动nginx
/etc/init.d/nginx start
sleep 1
if [ $? -ne 0 ];then
/etc/init.d/nginx start
fi
nginx -s reload
# 调整SELinux的参数
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
@ -178,16 +133,87 @@ centos6(){
}
# centos 6
if [[ $version -eq 6 ]]; then
centos6
fi
# centos 7
if [[ $version -eq 7 ]]; then
centos7
fi
function main(){
echo "欢迎使用easy scheduler前端部署脚本,目前前端部署脚本仅支持CentOS,Ubuntu"
echo "请在 escheduler-ui 目录下执行"
#To be compatible with MacOS and Linux
if [[ "$OSTYPE" == "darwin"* ]]; then
# Mac OSX
echo "Easy Scheduler ui install not support Mac OSX operating system"
exit 1
elif [[ "$OSTYPE" == "linux-gnu" ]]; then
# linux
echo "linux"
elif [[ "$OSTYPE" == "cygwin" ]]; then
# POSIX compatibility layer and Linux environment emulation for Windows
echo "Easy Scheduler ui not support Windows operating system"
exit 1
elif [[ "$OSTYPE" == "msys" ]]; then
# Lightweight shell and GNU utilities compiled for Windows (part of MinGW)
echo "Easy Scheduler ui not support Windows operating system"
exit 1
elif [[ "$OSTYPE" == "win32" ]]; then
echo "Easy Scheduler ui not support Windows operating system"
exit 1
elif [[ "$OSTYPE" == "freebsd"* ]]; then
# ...
echo "freebsd"
else
# Unknown.
echo "Operating system unknown, please tell us(submit issue) for better service"
exit 1
fi
# 配置前端访问端口
read -p "请输入nginx代理端口,不输入,则默认8888 :" esc_proxy_port
if [ -z "${esc_proxy_port}" ];then
esc_proxy_port="8888"
fi
read -p "请输入api server代理ip,必须输入,例如:192.168.xx.xx :" esc_api_server_ip
if [ -z "${esc_api_server_ip}" ];then
echo "api server代理ip不能为空."
exit 1
fi
read -p "请输入api server代理端口,不输入,则默认12345 :" esc_api_server_port
if [ -z "${esc_api_server_port}" ];then
esc_api_server_port="12345"
fi
# api server后端地址
esc_api_server="http://$esc_api_server_ip:$esc_api_server_port"
# 本机ip地址
esc_ipaddr=$(ip a | grep inet | grep -v inet6 | grep -v 127 | sed 's/^[ \t]*//g' | cut -d ' ' -f2 | head -n 1 | awk -F '/' '{print $1}')
# 提示信息
menu
read -p "请输入安装编号(1|2|3|4):" num
case $num in
1)
centos6 ${esc_proxy_port} ${esc_api_server}
;;
2)
centos7 ${esc_proxy_port} ${esc_api_server}
;;
3)
ubuntu ${esc_proxy_port} ${esc_api_server}
;;
4)
echo $"Usage :sh $0"
exit 1
;;
*)
echo $"Usage :sh $0"
exit 1
esac
echo "请浏览器访问:http://${esc_ipaddr}:${esc_proxy_port}"
}
echo "请浏览器访问:http://${esc_ipaddr}:${esc_proxy}"
main

18
escheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss

@ -138,11 +138,27 @@
.assist-btn {
position: absolute;
left: 10px;
top: 8px;
top: 7px;
>.name {
padding-left: 6px;
vertical-align: middle;
}
>.copy-name {
cursor: pointer;
padding-left: 4px;
position: relative;
top: -2px;
&:hover {
i {
color: #47c3ff;
}
}
i {
color: #333;
font-size: 18px;
vertical-align: middle;
}
}
}
.save-btn {
position: absolute;

25
escheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue

@ -29,6 +29,8 @@
icon="fa fa-code">
</x-button>
<span class="name">{{name}}</span>
&nbsp;
<span v-if="name" class="copy-name" @click="_copyName" :data-clipboard-text="name"><i class="iconfont" data-container="body" data-toggle="tooltip" title="复制名称" >&#xe61e;</i></span>
</div>
<div class="save-btn">
<div class="operation" style="vertical-align: middle;">
@ -88,6 +90,7 @@
import mUdp from './udp/udp'
import i18n from '@/module/i18n'
import { jsPlumb } from 'jsplumb'
import Clipboard from 'clipboard'
import { allNodesId } from './plugIn/util'
import { toolOper, tasksType } from './config'
import mFormModel from './formModel/formModel'
@ -139,6 +142,23 @@
Dag.create()
}
},
/**
* copy name
*/
_copyName(){
let clipboard = new Clipboard(`.copy-name`)
clipboard.on('success', e => {
this.$message.success(`${i18n.$t('Copy success')}`)
// Free memory
clipboard.destroy()
})
clipboard.on('error', e => {
// Copy is not supported
this.$message.warning(`${i18n.$t('The browser does not support automatic copying')}`)
// Free memory
clipboard.destroy()
})
},
/**
* Get state interface
* @param isReset Whether to manually refresh
@ -154,6 +174,10 @@
let $item = _.filter(taskList, v => v.name === item.name)[0]
return `<div style="text-align: left">${i18n.$t('Name')}${$item.name}</br>${i18n.$t('State')}${desc}</br>${i18n.$t('type')}${$item.taskType}</br>${i18n.$t('host')}${$item.host || '-'}</br>${i18n.$t('Retry Count')}${$item.retryTimes}</br>${i18n.$t('Submit Time')}${formatDate($item.submitTime)}</br>${i18n.$t('Start Time')}${formatDate($item.startTime)}</br>${i18n.$t('End Time')}${$item.endTime ? formatDate($item.endTime) : '-'}</br></div>`
}
// remove tip state dom
$('.w').find('.state-p').html('')
data.forEach(v1 => {
idArr.forEach(v2 => {
if (v2.name === v1.name) {
@ -161,7 +185,6 @@
let state = dom.find('.state-p')
dom.attr('data-state-id', v1.stateId)
dom.attr('data-dependent-result', v1.dependentResult || '')
state.html('')
state.append(`<b class="iconfont ${v1.isSpin ? 'fa fa-spin' : ''}" style="color:${v1.color}" data-toggle="tooltip" data-html="true" data-container="body">${v1.icoUnicode}</b>`)
state.find('b').attr('title', titleTpl(v2, v1.desc))
}

17
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/sql.vue

@ -28,6 +28,17 @@
</div>
</m-list-box>
<template v-if="!sqlType && showType.length">
<m-list-box>
<div slot="text">{{$t('Title')}}</div>
<div slot="content">
<x-input
type="input"
v-model="title"
:placeholder="$t('Please enter the title of email')"
autocomplete="off">
</x-input>
</div>
</m-list-box>
<m-list-box>
<div slot="text">{{$t('Recipient')}}</div>
<div slot="content">
@ -141,6 +152,8 @@
udfs: '',
// Sql type
sqlType: 0,
// Email title
title: '',
// Form/attachment
showType: ['TABLE'],
// Sql parameter
@ -241,6 +254,7 @@
sql: editor.getValue(),
udfs: this.udfs,
sqlType: this.sqlType,
title: this.title,
receivers: this.receivers.join(','),
receiversCc: this.receiversCc.join(','),
showType: (() => {
@ -308,6 +322,7 @@
this.showType = []
}
if (val !== 0) {
this.title = ''
this.receivers = []
this.receiversCc = []
}
@ -321,6 +336,7 @@
//
showType (val) {
if (!val.length) {
this.title = ''
this.receivers = []
this.receiversCc = []
}
@ -342,6 +358,7 @@
this.showType = o.params.showType.split(',') || []
this.preStatements = o.params.preStatements || []
this.postStatements = o.params.postStatements || []
this.title = o.params.title || ''
this.receivers = o.params.receivers && o.params.receivers.split(',') || []
this.receiversCc = o.params.receiversCc && o.params.receiversCc.split(',') || []
}

20
escheduler-ui/src/js/conf/home/pages/dag/_source/udp/udp.vue

@ -110,6 +110,13 @@
}
return true
},
_accuStore(){
this.store.commit('dag/setGlobalParams', _.cloneDeep(this.udpList))
this.store.commit('dag/setName', _.cloneDeep(this.name))
this.store.commit('dag/setTimeout', _.cloneDeep(this.timeout))
this.store.commit('dag/setDesc', _.cloneDeep(this.desc))
this.store.commit('dag/setSyncDefine', this.syncDefine)
},
/**
* submit
*/
@ -130,11 +137,8 @@
}
// Storage global globalParams
this.store.commit('dag/setGlobalParams', _.cloneDeep(this.udpList))
this.store.commit('dag/setName', _.cloneDeep(this.name))
this.store.commit('dag/setTimeout', _.cloneDeep(this.timeout))
this.store.commit('dag/setDesc', _.cloneDeep(this.desc))
this.store.commit('dag/setSyncDefine', this.syncDefine)
this._accuStore()
Affirm.setIsPop(false)
this.$emit('onUdp')
}
@ -155,7 +159,11 @@
* Close the popup
*/
close () {
this.$emit('close')
// Storage global globalParams
this._accuStore()
setTimeout(() => {
this.$emit('close')
})
}
},
watch: {

16
escheduler-ui/src/js/conf/home/pages/dag/_source/variable/index.vue

@ -1,6 +1,6 @@
<template>
<div class="assist-dag-model">
<template v-if="isView">
<template v-if="isView && isActive">
<m-variables-view></m-variables-view>
</template>
</div>
@ -11,7 +11,8 @@
name: 'assist-dag-index',
data () {
return {
isView: false
isView: false,
isActive: true
}
},
methods: {
@ -19,6 +20,15 @@
this.isView = !this.isView
}
},
watch: {
'$route': {
deep: true,
handler () {
this.isActive = false
this.$nextTick(() => (this.isActive = true))
}
}
},
components: { mVariablesView }
}
</script>
</script>

117
escheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/list.vue

@ -1,9 +1,12 @@
<template>
<div class="list-model">
<div class="list-model" style="position: relative;">
<div class="table-box">
<table class="fixed">
<tr>
<th>
<th width="50">
<x-checkbox @on-change="_topCheckBoxClick" v-model="checkAll"></x-checkbox>
</th>
<th width="40">
<span>{{$t('#')}}</span>
</th>
<th>
@ -29,7 +32,8 @@
</th>
</tr>
<tr v-for="(item, $index) in list" :key="item.id">
<td>
<td width="50"><x-checkbox v-model="item.isCheck" @on-change="_arrDelChange"></x-checkbox></td>
<td width="50">
<span>{{parseInt(pageNo === 1 ? ($index + 1) : (($index + 1) + (pageSize * (pageNo - 1))))}}</span>
</td>
<td>
@ -60,11 +64,33 @@
<x-button type="error" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('offline')" @click="_downline(item)" v-if="item.releaseState === 'ONLINE'" v-ps="['GENERAL_USER']" icon="iconfont icon-erji-xiaxianjilu"><!--{{$t('下线')}}--></x-button>
<x-button type="warning" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('online')" @click="_poponline(item)" v-if="item.releaseState === 'OFFLINE'" v-ps="['GENERAL_USER']" icon="iconfont icon-erji-xiaxianjilu-copy"><!--{{$t('上线')}}--></x-button>
<x-button type="info" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('Cron Manage')" @click="_timingManage(item)" :disabled="item.releaseState !== 'ONLINE'" v-ps="['GENERAL_USER']" icon="iconfont icon-paibanguanli"><!--{{$t('定时管理')}}--></x-button>
<x-poptip
:ref="'poptip-delete-' + $index"
placement="bottom-end"
width="90">
<p>{{$t('Delete?')}}</p>
<div style="text-align: right; margin: 0;padding-top: 4px;">
<x-button type="text" size="xsmall" shape="circle" @click="_closeDelete($index)">{{$t('Cancel')}}</x-button>
<x-button type="primary" size="xsmall" shape="circle" @click="_delete(item,$index)">{{$t('Confirm')}}</x-button>
</div>
<template slot="reference">
<x-button
icon="iconfont icon-shanchu"
type="error"
shape="circle"
size="xsmall"
data-toggle="tooltip"
:title="$t('delete')"
v-ps="['GENERAL_USER']">
</x-button>
</template>
</x-poptip>
<x-button type="info" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('TreeView')" @click="_treeView(item)" icon="iconfont icon-juxingkaobei"><!--{{$t('树形图')}}--></x-button>
</td>
</tr>
</table>
</div>
<x-button size="xsmall" style="position: absolute; bottom: -48px; left: 22px;" v-if="strDelete !== ''" @click="_batchDelete">删除</x-button>
</div>
</template>
<script>
@ -78,7 +104,9 @@
name: 'definition-list',
data () {
return {
list: []
list: [],
strDelete: '',
checkAll: false
}
},
props: {
@ -87,7 +115,7 @@
pageSize: Number
},
methods: {
...mapActions('dag', ['editProcessState', 'getStartCheck', 'getReceiver']),
...mapActions('dag', ['editProcessState', 'getStartCheck', 'getReceiver', 'deleteDefinition', 'batchDeleteDefinition']),
_rtPublishStatus (code) {
return _.filter(publishStatus, v => v.code === code)[0].desc
},
@ -179,6 +207,27 @@
_timingManage (item) {
this.$router.push({ path: `/projects/definition/list/timing/${item.id}` })
},
/**
* Close the delete layer
*/
_closeDelete (i) {
this.$refs[`poptip-delete-${i}`][0].doClose()
},
/**
* delete
*/
_delete (item, i) {
this.deleteDefinition({
processDefinitionId: item.id
}).then(res => {
this.$refs[`poptip-delete-${i}`][0].doClose()
this._onUpdate()
this.$message.success(res.msg)
}).catch(e => {
this.$refs[`poptip-delete-${i}`][0].doClose()
this.$message.error(e.msg || '')
})
},
/**
* edit
*/
@ -217,20 +266,66 @@
},
_onUpdate () {
this.$emit('on-update')
},
/**
* click the select-all checkbox
*/
_topCheckBoxClick (v) {
this.list.forEach((item, i) => {
this.$set(this.list[i], 'isCheck', v)
})
this._arrDelChange()
},
/**
* the array that to be delete
*/
_arrDelChange (v) {
let arr = []
this.list.forEach((item)=>{
if (item.isCheck) {
arr.push(item.id)
}
})
this.strDelete = _.join(arr, ',')
if (v === false) {
this.checkAll = false
}
},
/**
* batch delete
*/
_batchDelete () {
this.batchDeleteDefinition({
processDefinitionIds: this.strDelete
}).then(res => {
this._onUpdate()
this.checkAll = false
this.$message.success(res.msg)
}).catch(e => {
this.checkAll = false
this.$message.error(e.msg || '')
})
}
},
watch: {
processList (a) {
this.list = []
setTimeout(() => {
this.list = a
})
processList: {
handler (a) {
this.checkAll = false
this.list = []
setTimeout(() => {
this.list = _.cloneDeep(a)
})
},
immediate: true,
deep: true
},
pageNo () {
this.strDelete = ''
}
},
created () {
},
mounted () {
this.list = this.processList
},
components: { }
}

2
escheduler-ui/src/js/conf/home/pages/projects/pages/index/index.vue

@ -1,5 +1,5 @@
<template>
<m-list-construction :title="$t('Project Home')">
<m-list-construction :title="searchParams.projectId ? $t('Project Home') : $t('Home')">
<template slot="content">
<div class="perject-home-content">
<div class="time-model">

7
escheduler-ui/src/js/conf/home/pages/projects/pages/instance/pages/gantt/_source/gantt.js

@ -107,11 +107,11 @@ Gantt.prototype.drawChart = function () {
.append('svg')
.attr('class', 'chart')
.attr('width', this.width + this.margin.left + this.margin.right)
.attr('height', this.height + this.margin.top + this.margin.bottom)
.attr('height', this.height + this.margin.top + this.margin.bottom + 150)
.append('g')
.attr('class', 'gantt-chart')
.attr('width', this.width + this.margin.left + this.margin.right)
.attr('height', this.height + this.margin.top + this.margin.bottom)
.attr('height', this.height + this.margin.top + this.margin.bottom + 150)
.attr('transform', 'translate(' + this.margin.left + ', ' + this.margin.top + ')')
svg.selectAll('.chart')
@ -132,6 +132,9 @@ Gantt.prototype.drawChart = function () {
.attr('transform', 'translate(0, ' + (this.height - this.margin.top - this.margin.bottom) + ')')
.transition()
.call(this.xAxis)
.selectAll("text")
.attr("transform", `rotate(-${this.width / ($('.tick').length - 1) > 50 ? 0 : Math.acos(this.width / ($('.tick').length - 1) / 50) * 57 })`)
.style("text-anchor", `${this.width / ($('.tick').length - 1) > 50 ? 'middle' : 'end'}`)
svg.append('g')
.attr('class', 'y axis')

80
escheduler-ui/src/js/conf/home/pages/projects/pages/instance/pages/list/_source/list.vue

@ -1,15 +1,18 @@
<template>
<div class="list-model">
<div class="list-model" style="position: relative;">
<div class="table-box">
<table class="fixed">
<tr>
<th>
<th width="50">
<x-checkbox @on-change="_topCheckBoxClick" v-model="checkAll"></x-checkbox>
</th>
<th width="40">
<span>{{$t('#')}}</span>
</th>
<th>
<span>{{$t('Process Name')}}</span>
</th>
<th width="120">
<th>
<span>{{$t('Run Type')}}</span>
</th>
<th width="140">
@ -18,10 +21,10 @@
<th width="140">
<span>{{$t('End Time')}}</span>
</th>
<th width="90">
<th width="70">
<span>{{$t('Duration')}}s</span>
</th>
<th width="72">
<th width="70">
<span>{{$t('Run Times')}}</span>
</th>
<th width="100">
@ -33,12 +36,13 @@
<th width="50">
<span>{{$t('State')}}</span>
</th>
<th width="260">
<th width="220">
<span>{{$t('Operation')}}</span>
</th>
</tr>
<tr v-for="(item, $index) in list" :key="item.id">
<td>
<td width="50"><x-checkbox v-model="item.isCheck" @on-change="_arrDelChange"></x-checkbox></td>
<td width="50">
<span>{{parseInt(pageNo === 1 ? ($index + 1) : (($index + 1) + (pageSize * (pageNo - 1))))}}</span>
</td>
<td>
@ -50,8 +54,8 @@
<span v-if="item.endTime">{{item.endTime | formatDate}}</span>
<span v-if="!item.endTime">-</span>
</td>
<td><span>{{item.duration || '-'}}</span></td>
<td><span>{{item.runTimes}}</span></td>
<td width="70"><span>{{item.duration || '-'}}</span></td>
<td width="70"><span>{{item.runTimes}}</span></td>
<td>
<span v-if="item.host">{{item.host}}</span>
<span v-if="!item.host">-</span>
@ -245,6 +249,7 @@
</tr>
</table>
</div>
<x-button size="xsmall" style="position: absolute; bottom: -48px; left: 22px;" v-if="strDelete !== ''" @click="_batchDelete">删除</x-button>
</div>
</template>
<script>
@ -259,7 +264,9 @@
//
list: [],
//
buttonType: ''
buttonType: '',
strDelete: '',
checkAll: false
}
},
props: {
@ -268,7 +275,7 @@
pageSize: Number
},
methods: {
...mapActions('dag', ['editExecutorsState', 'deleteInstance']),
...mapActions('dag', ['editExecutorsState', 'deleteInstance', 'batchDeleteInstance']),
/**
* Return run type
*/
@ -440,21 +447,58 @@
},
_gantt (item) {
this.$router.push({ path: `/projects/instance/gantt/${item.id}` })
},
_topCheckBoxClick (v) {
this.list.forEach((item, i) => {
this.$set(this.list[i], 'isCheck', v)
})
this._arrDelChange()
},
_arrDelChange (v) {
let arr = []
this.list.forEach((item)=>{
if (item.isCheck) {
arr.push(item.id)
}
})
this.strDelete = _.join(arr, ',')
if (v === false) {
this.checkAll = false
}
},
_batchDelete () {
this.batchDeleteInstance({
processInstanceIds: this.strDelete
}).then(res => {
this._onUpdate()
this.checkAll = false
this.$message.success(res.msg)
}).catch(e => {
this.checkAll = false
this.$message.error(e.msg || '')
})
}
},
watch: {
processInstanceList (a) {
this.list = []
setTimeout(() => {
this.list = this._listDataHandle(a)
})
processInstanceList: {
handler (a) {
this.checkAll = false
this.list = []
setTimeout(() => {
this.list = _.cloneDeep(this._listDataHandle(a))
})
},
immediate: true,
deep: true
},
pageNo () {
this.strDelete = ''
}
},
created () {
},
mounted () {
this.list = this._listDataHandle(this.processInstanceList)
},
components: { }
}
</script>
</script>

12
escheduler-ui/src/js/conf/home/pages/projects/pages/taskInstance/_source/list.vue

@ -45,10 +45,9 @@
<span>{{parseInt(pageNo === 1 ? ($index + 1) : (($index + 1) + (pageSize * (pageNo - 1))))}}</span>
</td>
<td>
<span v-if="isAuth" class="ellipsis"><a href="javascript:" class="links">{{item.name}}</a></span>
<span v-if="!isAuth" class="ellipsis"><a href="javascript:" class="links">{{item.name}}</a></span>
<span class="ellipsis"><a href="javascript:" class="links">{{item.name}}</a></span>
</td>
<td><span class="ellipsis">{{item.processInstanceName}}</span></td>
<td><a href="javascript:" class="links" @click="_go(item)"><span class="ellipsis">{{item.processInstanceName}}</span></a></td>
<td><span>{{item.taskType}}</span></td>
<td><span v-html="_rtState(item.state)" style="cursor: pointer;"></span></td>
<td><span>{{item.submitTime | formatDate}}</span></td>
@ -125,7 +124,10 @@
})
}
})
}
},
_go (item) {
this.$router.push({ path: `/projects/instance/list/${item.processInstanceId}` })
},
},
watch: {
taskInstanceList (a) {
@ -142,4 +144,4 @@
},
components: { }
}
</script>
</script>

2
escheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/details/index.vue

@ -79,7 +79,7 @@
this.isData = false
} else {
this.isData = true
this._handlerEditor().setValue(res.data.content)
this._handlerEditor().setValue(res.data.content + '\n')
// Initialize the plugin to prevent repeated calls
if (editor.lineCount() < 1000) {

3
escheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue

@ -92,7 +92,8 @@
this.isData = false
} else {
this.isData = true
this._handlerEditor().setValue(res.data.content || '')
let content = res.data.content ? res.data.content + '\n' : ''
this._handlerEditor().setValue(content)
setTimeout(() => {
$('.code-mirror-model').scrollTop(12).scrollLeft(0)
}, 200)

15
escheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/rename.vue

@ -49,10 +49,16 @@
methods: {
_ok (fn) {
this._verification().then(res => {
return this.store.dispatch('resource/resourceVerifyName', {
name: this.name,
type: 'FILE'
})
if (this.name === this.item.alias) {
return new Promise((resolve,reject) => {
this.desc === this.item.desc ? reject({msg:'内容未修改'}) : resolve()
})
}else{
return this.store.dispatch('resource/resourceVerifyName', {
name: this.name,
type: 'FILE'
})
}
}).then(res => {
return this.store.dispatch('resource/resourceRename', {
name: this.name,
@ -78,6 +84,7 @@
} else {
resolve()
}
})
}
},

14
escheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/rename.vue

@ -49,10 +49,16 @@
methods: {
_ok (fn) {
this._verification().then(res => {
return this.store.dispatch('resource/resourceVerifyName', {
name: this.name,
type: 'UDF'
})
if (this.name === this.item.alias) {
return new Promise((resolve,reject) => {
this.desc === this.item.desc ? reject({msg:'内容未修改'}) : resolve()
})
}else{
return this.store.dispatch('resource/resourceVerifyName', {
name: this.name,
type: 'UDF'
})
}
}).then(res => {
return this.store.dispatch('resource/resourceRename', {
name: this.name,

19
escheduler-ui/src/js/conf/home/pages/security/pages/tenement/_source/list.vue

@ -64,19 +64,26 @@
@click="_edit(item)"
icon="iconfont icon-bianjixiugai">
</x-button>
<!--<x-poptip
:ref="'poptip-' + $index"
placement="bottom-end"
width="90">
<x-poptip
:ref="'poptip-' + $index"
placement="bottom-end"
width="90">
<p>{{$t('Delete?')}}</p>
<div style="text-align: right; margin: 0;padding-top: 4px;">
<x-button type="text" size="xsmall" shape="circle" @click="_closeDelete($index)">{{$t('Cancel')}}</x-button>
<x-button type="primary" size="xsmall" shape="circle" @click="_delete(item,$index)">{{$t('Confirm')}}</x-button>
</div>
<template slot="reference">
<x-button type="error" shape="circle" size="xsmall" data-toggle="tooltip" :title="$t('delete')">{{$t('delete')}}</x-button>
<x-button
icon="iconfont icon-shanchu"
type="error"
shape="circle"
size="xsmall"
data-toggle="tooltip"
:title="$t('delete')">
</x-button>
</template>
</x-poptip>-->
</x-poptip>
</td>
</tr>
</table>

36
escheduler-ui/src/js/conf/home/store/dag/actions.js

@ -437,6 +437,42 @@ export default {
})
})
},
/**
* Batch delete process instance
*/
batchDeleteInstance ({ state }, payload) {
return new Promise((resolve, reject) => {
io.get(`projects/${state.projectName}/instance/batch-delete`, payload, res => {
resolve(res)
}).catch(e => {
reject(e)
})
})
},
/**
* Delete definition
*/
deleteDefinition ({ state }, payload) {
return new Promise((resolve, reject) => {
io.get(`projects/${state.projectName}/process/delete`, payload, res => {
resolve(res)
}).catch(e => {
reject(e)
})
})
},
/**
* Batch delete definition
*/
batchDeleteDefinition ({ state }, payload) {
return new Promise((resolve, reject) => {
io.get(`projects/${state.projectName}/process/batch-delete`, payload, res => {
resolve(res)
}).catch(e => {
reject(e)
})
})
},
/**
* Process instance get variable
*/

6
escheduler-ui/src/js/module/i18n/locale/en_US.js

@ -111,6 +111,8 @@ export default {
'Please enter ExecutorPlease enter Executor core number': 'Please enter ExecutorPlease enter Executor core number',
'Core number should be positive integer': 'Core number should be positive integer',
'SQL Type': 'SQL Type',
'Title': 'Title',
'Please enter the title of email': 'Please enter the title of email',
'Table': 'Table',
'Attachment': 'Attachment',
'SQL Parameter': 'SQL Parameter',
@ -452,6 +454,6 @@ export default {
'Pre Statement': 'Pre Statement',
'Post Statement': 'Post Statement',
'Statement cannot be empty': 'Statement cannot be empty',
'Process Define Count':'Process Define Count',
'Process Instance Running Count':'Process Instance Running Count',
'Process Define Count': 'Process Define Count',
'Process Instance Running Count': 'Process Instance Running Count'
}

6
escheduler-ui/src/js/module/i18n/locale/zh_CN.js

@ -111,6 +111,8 @@ export default {
'Please enter ExecutorPlease enter Executor core number': '请填写Executor内核数',
'Core number should be positive integer': '内核数为正整数',
'SQL Type': 'sql类型',
'Title': '主题',
'Please enter the title of email': '请输入邮件主题',
'Table': '表格',
'Attachment': '附件',
'SQL Parameter': 'sql参数',
@ -452,6 +454,6 @@ export default {
'Pre Statement': '前置sql',
'Post Statement': '后置sql',
'Statement cannot be empty': '语句不能为空',
'Process Define Count':'流程定义个数',
'Process Instance Running Count':'运行流程实例个数',
'Process Define Count': '流程定义个数',
'Process Instance Running Count': '运行流程实例个数'
}

46
install.sh

@ -45,32 +45,39 @@ mysqlDb="escheduler"
mysqlUserName="xx"
# mysql 密码
# 注意:如果有特殊字符,请用 \ 转移符进行转移
mysqlPassword="xx"
# conf/config/install_config.conf配置
# 安装路径,不要当前路径(pwd)一样
# 注意:安装路径,不要当前路径(pwd)一样
installPath="/data1_1T/escheduler"
# 部署用户
# 注意:部署用户需要有sudo权限及操作hdfs的权限,如果开启hdfs,根目录需要自行创建
deployUser="escheduler"
# zk集群
zkQuorum="192.168.xx.xx:2181,192.168.xx.xx:2181,192.168.xx.xx:2181"
# 安装hosts
# 注意:安装调度的机器hostname列表,如果是伪分布式,则只需写一个伪分布式hostname即可
ips="ark0,ark1,ark2,ark3,ark4"
# conf/config/run_config.conf配置
# 运行Master的机器
# 注意:部署master的机器hostname列表
masters="ark0,ark1"
# 运行Worker的机器
# 注意:部署worker的机器hostname列表
workers="ark2,ark3,ark4"
# 运行Alert的机器
# 注意:部署alert server的机器hostname列表
alertServer="ark3"
# 运行Api的机器
# 注意:部署api server的机器hostname列表
apiServers="ark1"
# alert配置
@ -93,12 +100,16 @@ mailPassword="xxxxxxxxxx"
xlsFilePath="/tmp/xls"
#是否启动监控自启动脚本
monitorServerState="false"
# hadoop 配置
# 是否启动hdfs,如果启动则为true,需要配置以下hadoop相关参数;
# 不启动设置为false,如果为false,以下配置不需要修改
# 特别注意:如果启动hdfs,需要自行创建hdfs根路径,也就是install.sh中的 hdfsPath
hdfsStartupSate="false"
# namenode地址,支持HA,需要将core-site.xml和hdfs-site.xml放到conf目录下
# namenode地址支持HA,需要将core-site.xml和hdfs-site.xml放到conf目录下
namenodeFs="hdfs://mycluster:8020"
# resourcemanager HA配置,如果是单resourcemanager,这里为空即可
@ -154,6 +165,9 @@ mastersFailover="/escheduler/lock/failover/masters"
# zk worker容错分布式锁
workersFailover="/escheduler/lock/failover/masters"
# zk master启动容错分布式锁
mastersStartupFailover="/escheduler/lock/failover/startup-masters"
# zk session 超时
zkSessionTimeout="300"
@ -258,6 +272,7 @@ sed -i ${txt} "s#zookeeper.escheduler.lock.masters.*#zookeeper.escheduler.lock.m
sed -i ${txt} "s#zookeeper.escheduler.lock.workers.*#zookeeper.escheduler.lock.workers=${workersLock}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.lock.failover.masters.*#zookeeper.escheduler.lock.failover.masters=${mastersFailover}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.lock.failover.workers.*#zookeeper.escheduler.lock.failover.workers=${workersFailover}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.escheduler.lock.failover.startup.masters.*#zookeeper.escheduler.lock.failover.startup.masters=${mastersStartupFailover}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.session.timeout.*#zookeeper.session.timeout=${zkSessionTimeout}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.connection.timeout.*#zookeeper.connection.timeout=${zkConnectionTimeout}#g" conf/zookeeper.properties
sed -i ${txt} "s#zookeeper.retry.sleep.*#zookeeper.retry.sleep=${zkRetrySleep}#g" conf/zookeeper.properties
@ -364,3 +379,30 @@ fi
# 6,启动
echo "6,启动"
sh ${workDir}/script/start_all.sh
# 7,启动监控自启动脚本
monitor_pid=${workDir}/monitor_server.pid
if [ "true" = $monitorServerState ];then
if [ -f $monitor_pid ]; then
TARGET_PID=`cat $monitor_pid`
if kill -0 $TARGET_PID > /dev/null 2>&1; then
echo "monitor server running as process ${TARGET_PID}.Stopping"
kill $TARGET_PID
sleep 5
if kill -0 $TARGET_PID > /dev/null 2>&1; then
echo "monitor server did not stop gracefully after 5 seconds: killing with kill -9"
kill -9 $TARGET_PID
fi
else
echo "no monitor server to stop"
fi
echo "monitor server running as process ${TARGET_PID}.Stopped success"
rm -f $monitor_pid
fi
nohup python -u ${workDir}/script/monitor_server.py $installPath $zkQuorum $zkMasters $zkWorkers > ${workDir}/monitor_server
.log 2>&1 &
echo $! > $monitor_pid
echo "start monitor server success as process `cat $monitor_pid`"
fi

2
script/env/.escheduler_env.sh vendored

@ -6,4 +6,4 @@ export PYTHON_HOME=/opt/soft/python
export JAVA_HOME=/opt/soft/java
export HIVE_HOME=/opt/soft/hive
export PATH=$HADOOP_HOME/bin:$SPARK_HOME1/bin:$SPARK_HOME2/bin:$PYTHON_HOME/bin:$JAVA_HOME/bin:$HIVE_HOME/bin:$PATH
export PATH=$HADOOP_HOME/bin:$SPARK_HOME1/bin:$SPARK_HOME2/bin:$PYTHON_HOME:$JAVA_HOME/bin:$HIVE_HOME/bin:$PATH

40
script/monitor_server.py

@ -9,10 +9,15 @@ yum -y install python-pip
pip install kazoo 安装
conda install -c conda-forge kazoo 安装
运行脚本
nohup python -u monitor_server.py > nohup.out 2>&1 &
运行脚本及参数说明
nohup python -u monitor_server.py /data1_1T/escheduler 192.168.xx.xx:2181,192.168.xx.xx:2181,192.168.xx.xx:2181 /escheduler/masters /escheduler/workers> monitor_server.log 2>&1 &
参数说明如下:
/data1_1T/escheduler的值来自install.sh中的installPath
192.168.xx.xx:2181,192.168.xx.xx:2181,192.168.xx.xx:2181的值来自install.sh中的zkQuorum
/escheduler/masters的值来自install.sh中的zkMasters
/escheduler/workers的值来自install.sh中的zkWorkers
'''
import sys
import socket
import os
import sched
@ -20,14 +25,13 @@ import time
from datetime import datetime
from kazoo.client import KazooClient
schedule = sched.scheduler(time.time, time.sleep)
class ZkClient:
def __init__(self):
# hosts配置zk地址集群
self.zk = KazooClient(hosts='ark0:2181,ark1:2181,ark2:2181')
self.zk.start()
self.zk = KazooClient(hosts=zookeepers)
self.zk.start()
# 读取配置文件,组装成字典
def read_file(self,path):
@ -45,35 +49,37 @@ class ZkClient:
# 重启服务
def restart_server(self,inc):
config_dict = self.read_file('/data1_1T/escheduler/conf/config/run_config.conf')
config_dict = self.read_file(install_path + '/conf/config/run_config.conf')
master_list = config_dict.get('masters').split(',')
print master_list
master_list = list(map(lambda item : self.get_ip_by_hostname(item),master_list))
worker_list = config_dict.get('workers').split(',')
print worker_list
worker_list = list(map(lambda item: self.get_ip_by_hostname(item), worker_list))
if (self.zk.exists('/escheduler/masters')):
if (self.zk.exists(masters_zk_path)):
zk_master_list = []
zk_master_nodes = self.zk.get_children('/escheduler/masters')
zk_master_nodes = self.zk.get_children(masters_zk_path)
for zk_master_node in zk_master_nodes:
zk_master_list.append(zk_master_node.split('_')[0])
restart_master_list = list(set(master_list) - set(zk_master_list))
if (len(restart_master_list) != 0):
for master in restart_master_list:
print("master " + self.get_ip_by_hostname(master) + " 服务已经掉了")
os.system('ssh ' + self.get_ip_by_hostname(master) + ' sh /data1_1T/escheduler/bin/escheduler-daemon.sh start master-server')
os.system('ssh ' + self.get_ip_by_hostname(master) + ' sh ' + install_path + '/bin/escheduler-daemon.sh start master-server')
if (self.zk.exists('/escheduler/workers')):
if (self.zk.exists(workers_zk_path)):
zk_worker_list = []
zk_worker_nodes = self.zk.get_children('/escheduler/workers')
zk_worker_nodes = self.zk.get_children(workers_zk_path)
for zk_worker_node in zk_worker_nodes:
zk_worker_list.append(zk_worker_node.split('_')[0])
restart_worker_list = list(set(worker_list) - set(zk_worker_list))
if (len(restart_worker_list) != 0):
for worker in restart_worker_list:
print("worker " + self.get_ip_by_hostname(worker) + " 服务已经掉了")
os.system('ssh ' + self.get_ip_by_hostname(worker) + ' sh /data1_1T/escheduler/bin/escheduler-daemon.sh start worker-server')
os.system('ssh ' + self.get_ip_by_hostname(worker) + ' sh ' + install_path + '/bin/escheduler-daemon.sh start worker-server')
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
schedule.enter(inc, 0, self.restart_server, (inc,))
@ -84,5 +90,11 @@ class ZkClient:
schedule.enter(0, 0, self.restart_server, (inc,))
schedule.run()
if __name__ == '__main__':
if (len(sys.argv) < 4):
print('please input install_path,zookeepers,masters_zk_path and worker_zk_path')
install_path = sys.argv[1]
zookeepers = sys.argv[2]
masters_zk_path = sys.argv[3]
workers_zk_path = sys.argv[4]
zkClient = ZkClient()
zkClient.main(300)
zkClient.main(300)

Loading…
Cancel
Save