最近工作上有需要,写了一个shell脚本请求kylin刷新模型的,用于配置到调度平台。
需求是:传入模型名称,脚本实现请求kylin开始重构模型,并且要监控模型构建过程,完成构建以后才可以结束。
shell一门很古老的语言,功能很强大,但是可读性不高,不如python好用。这里之所以用shell脚本,是因为前期的调度认为都是通过shell脚本实现的,我这边没必要标新立异。(从后面的工作看,深入实现kylin的增量模型构建,用shell的难度进一步加大,所以最开始的选择也许就是错误的)。shell的好处在于和操作系统集成,不需要额外的安装插件(本次脚本用到来解析json的jq包,属于扩展软件需要安装),也不涉及版本问题,脚本命令可以直接在命令行调试。
废话不多说,直接上代码吧。
#!/bin/bash##########################################################脚本名称:scm_kylin_main.sh#创建日期:2020-12-28#功能说明:用于调用kylin的模型,#格 式:sh scm_kylin_main.sh kylin模型名 业务日期yyyy-mm-dd#修改记录#日期 操作 操作人员 描述###########################################################脚本名称V_SHELL_NAME=`basename $0`#项目V_PROJECT=xx#用户密码加密V_USER_PASSWD=YWRtaW46a3lsaW5AMjAyMA==#kylin的IP和端口V_IP_PORT=192.168.xx.xx:7070#业务日期V_BIZ_DATE=$2#kylin模型名V_MODEL=$1#脚本名V_KYLIN_NAME="${V_SHELL_NAME%.*}_${V_MODEL}"#日志名V_LOG_NAME="${V_KYLIN_NAME}_$V_BIZ_DATE.log"#日志路径V_LOG_DIR="/home/admin/ETL/log/"#判断输入的参数格式if [ $# -ne 2 ] then echo "输入参数格式有误,请按格式输入 sh ${V_SHELL_NAME} kylin模型名 业务日期yyyy-mm-dd" exit 98fimkdir -p ${V_LOG_DIR}${V_BIZ_DATE}#日志函数func_log(){ V_LOG_INFO=$1 V_DATE=`date +%F" "%T` echo "${V_DATE}:${V_KYLIN_NAME}:${V_LOG_INFO}" echo "${V_DATE}:${V_KYLIN_NAME}:${V_LOG_INFO}">>${V_LOG_DIR}${V_BIZ_DATE}/${V_LOG_NAME} }run_cmd="curl -X POST \ 'http://${V_IP_PORT}/kylin/api/models/${V_MODEL}/segments' \ -H 'Accept: application/vnd.apache.kylin-v4-public+json' \ -H 'Accept-Language: en' \ -H 'Authorization: Basic ${V_USER_PASSWD}' \ -H 'Content-Type: application/json;charset=utf-8' \ -d '{\"project\":\"${V_PROJECT}\"}' " #记录执行的日志func_log "${run_cmd}"#执行调用模型代码v_return_code=`eval ${run_cmd} `#输出响应串func_log "${v_return_code}"#判断返回值是否成功v_return_num=`echo ${v_return_code}|grep '"code":"000"'|wc -l`if [ $v_return_num -eq 1 ] then v_flag=0 func_log "kylin模型成功调起,休眠一分钟后检查状态"else v_flag=1 func_log "kylin模型调起失败" exit ${v_flag} fiV_JOB_ID=`echo ${v_return_code}|jq -r '.data.jobs[0].job_id' `func_log "获取到job_id:${V_JOB_ID}"sleep 1mstatus_cmd="curl -X GET \ 'http://${V_IP_PORT}/kylin/api/jobs?project=${V_PROJECT}&time_filter=4&key=${V_JOB_ID}' \ -H 'Accept: application/vnd.apache.kylin-v4-public+json ' \ -H 'Accept-Language: en' \ -H 'Authorization: Basic ${V_USER_PASSWD}' \ -H 'Content-Type: application/json;charset=utf-8' "func_log "${status_cmd}"#每一分钟循环一次,查询任务状态while truedo #执行调用模型代码 v_return_code=`eval ${status_cmd} ` #输出响应串 func_log "${v_return_code}" #解析任务状态 job_status=`echo ${v_return_code}| jq -r '.data.value[0].job_status' ` func_log "${job_status}" if [ "$job_status" == "FINISHED" ]; then v_flag=0 func_log "kylin模型成刷新完成" exit ${v_flag} else v_flag=1 func_log "kylin模型还在刷新中,一分钟后再检查状态" sleep 1m fidoneexit ${v_flag}
这个代码是在已有项目代码的基础上修改而来,下面具体说一下其中的亮点:
日志函数func_log比较规范,适合在其他地方推广使用。日志函数不仅想日志内容写到文件,同时也完成了输出,方便调度平台监控;
执行拼装的命令用到了eval 函数,这个也是我最近现学现写的,这样可以保证执行的命令和写入日志的命令一致,大幅提升排查问题的效率;
jq这个命令的使用,我也是现学的。直接用jq输出结果会有引号,用jq -r则不会;'.data.jobs[0].job_id' 这个解析取值方式有点类似于python,虽然shell数据结构弱一点,但是简单取一个值还是很容易的;
由于查询模型状态需要轮询,这里用到了while循环,也是在很多地方可以参考的。
最后补几个今天研究出来的代码总结吧。
将字符串转换成大写:$(echo $sss | tr '[a-z]' '[A-Z]')
将日期字符串转换成毫秒(核心点在%3N):
V_END_DATE=`date -d "${V_BIZ_DATE} 23:59:59" +%s%3N`
3.一个很无聊,搞了好久但是最后可能用不上的加工处理,初始变量有V_BIZ_DATE标识业务日期,V_REFRESH_PERIOD标识刷新频率(例如3m、4D、1Y等),以3M为例,就是把V_BIZ_DATE往前推3个月。我费了老大劲才把这个成正确的结果。代码分享如下:
#根据传入的期间加工期间的数值部分v_rp_int=$[${V_REFRESH_PERIOD:0:$[${#V_REFRESH_PERIOD} -1]}*-1]#根据传入的期间加工期间的单位部分case ${V_REFRESH_PERIOD:0-1:1} in 'D') v_rp_unit='day';; 'M') v_rp_unit='month';; 'Y') v_rp_unit='year';;*) echo "传入的刷新区间解析错误";exit 1;; esac#生成开始日期对应的时间戳(毫秒)V_START_DATE=`date -d "${V_BIZ_DATE} ${v_rp_int} ${v_rp_unit} " +%s%3N`
4.jq取多个值并且拼接成一个字符串。(在此处的用处是:请求时间范围内的模型的segment代码,通过jq拆分取到拼接到一起的字符串,用于下一个刷新请求,作为请求的参数)。
v_ids_str=`echo ${v_return_code}| jq '.data.value[]|.id' |tr '\n' ',' `
总之,踩了不少坑,最后还是实现了最初的目标。但是整体式说还是不灵活,后期有时间会修改python代码,毕竟curl请求、json解析、循环遍历这些shell实现起来很费劲的需求对python来说都是基础功能。
《数据中台研习社》微信群,请添加微信:laowang5244,备注【进群】
?分享、点赞、在看,给个三连击呗!?