diff --git a/LSF-Script/collection/job b/LSF-Script/collection/job
new file mode 100644
index 0000000000000000000000000000000000000000..af9e88d3d14c364dfc83ab9390f06a673cf301ac
--- /dev/null
+++ b/LSF-Script/collection/job
@@ -0,0 +1,162 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+import copy
+import json
+import os
+
+# expected output format:
+# [{"jobId":"2035","jobIndex":"1","jobName":"new[1]","user":"admin","sourceCluster":"cluster1","stat":"DONE",
+# "queue":"normal01","fromHost":"host2","submitTime":"Jun 16 17:43:11 2021","startTime":"Jun 16 17:43:12 2021",
+# "finishTime":"Jun 16 17:44:54 2021","execHome":"/home/admin","outputFile":"","errorFile":"","jobPriority":"","
+# execHost":"host2","CPU_USED":"00:00:02","jobDescription":"","exitCode":"","pendReason":"","jobRunTime":"00:01:42"}]
+JOB_INFOS_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 bjobs -a -u all -hms -o \"jobid jobindex job_name user source_cluster stat ' \
+ 'queue from_host submit_time start_time finish_time exec_home output_dir output_file error_file job_priority ' \
+ 'exec_host job_description exit_code exit_reason pend_reason run_time delimiter=\'^\'\"'
+
+ARRAY_JOB_INFO_CMD = 'source @SCHEDULER_PROFILE_PATH@; timeout 10 bjobs -A -w '
+
+# jobstatemap for ccp
+statMap = {'UNKWN': -1, 'RUN': 4, 'PSUSP': 2, 'USUSP': 2, 'SSUSP': 10, 'PEND': 1, 'DONE': 9, 'EXIT': 5, 'WAIT': 3, 'ZOMBI': -1}
+
+# 作业查询字段数组
+jobFields = ['JOBID','JOBINDEX','JOB_NAME','USER','SOURCE_CLUSTER','STAT','QUEUE','FROM_HOST','SUBMIT_TIME','START_TIME','FINISH_TIME','EXEC_HOME','OUTPUT_DIR','OUTPUT_FILE','ERROR_FILE','JOB_PRIORITY','EXEC_HOST','JOB_DESCRIPTION','EXIT_CODE','EXIT_REASON','PEND_REASON','RUN_TIME']
+
+# 聚合数组作业父作业状态
+# arrayJobInfoValue 格式样例:[0, 0, 5, 0, 0, 0] 状态依次为PEND DONE RUN EXIT (USUSP+PSUSP)SSUSP
+def aggJobState(parentJobinfo, arrayJobStatArr):
+ if len(arrayJobStatArr) < 7:
+ parentJobinfo['stat'] = 'UNKWN'
+ return
+ runNum = int(arrayJobStatArr[2])
+ if runNum > 0:
+ parentJobinfo['stat'] = 'RUN'
+ return
+ usupNum = int(arrayJobStatArr[4])
+ if usupNum > 0:
+ parentJobinfo['stat'] = 'USUSP'
+ return
+ ssuspNum = int(arrayJobStatArr[5])
+ if ssuspNum > 0:
+ parentJobinfo['stat'] = 'SSUSP'
+ return
+ pendNum = int(arrayJobStatArr[0])
+ if pendNum > 0:
+ parentJobinfo['stat'] = 'PEND'
+ return
+ exitNum = int(arrayJobStatArr[3])
+ if exitNum > 0:
+ parentJobinfo['stat'] = 'EXIT'
+ return
+ doneNum = int(arrayJobStatArr[1])
+ if doneNum > 0:
+ parentJobinfo['stat'] = 'DONE'
+ return
+ doneNum = int(arrayJobStatArr[6])
+ if doneNum > 0:
+ parentJobinfo['stat'] = 'ZOMBI'
+ return
+ parentJobinfo['stat'] = 'UNKWN'
+ return
+
+# 转换作业数据为json格式
+def strToJson(jobInfoStr):
+ jobInfoArr = jobInfoStr.split("^")
+ jobInfo = {}
+ for index in range(len(jobFields)):
+ field = jobInfoArr[index]
+ if field == '-':
+ field = ''
+ jobInfo[jobFields[index]] = field
+ return jobInfo
+
+jobInfos = os.popen(JOB_INFOS_CMD).read()
+jobInfosArr = jobInfos.strip().split("\n")
+
+# 数组作业状态表 {'jobId':'PEND,DONE,RUN,EXIT,SSUSP,USUSP,PSUSP'}
+arrayJobStatDict = {}
+# 构造非数组作业及数组作业子作业信息 及数组作业状态表
+nonArrayJobList = []
+for index in range(len(jobInfosArr)):
+ if index == 0:
+ continue
+ jobInfo = strToJson(jobInfosArr[index])
+ jobInfo['OUTPUT_DIR'] = jobInfo['OUTPUT_DIR'].rstrip('/')
+ if not statMap.has_key(jobInfo['STAT']):
+ statMap[jobInfo['STAT']]=-1
+ # 替换key值为期望解析值
+ outputJob = {'jobId': jobInfo['JOBID'], 'jobIndex': jobInfo['JOBINDEX'], 'jobName': jobInfo['JOB_NAME'],
+ 'user': jobInfo['USER'], 'sourceCluster': jobInfo['SOURCE_CLUSTER'],
+ 'stat': str(statMap[jobInfo['STAT']]),
+ 'queue': jobInfo['QUEUE'], 'fromHost': jobInfo['FROM_HOST'], 'submitTime': jobInfo['SUBMIT_TIME'],
+ 'startTime': jobInfo['START_TIME'], 'finishTime': jobInfo['FINISH_TIME'],
+ 'execHome': jobInfo['OUTPUT_DIR'], 'outputFile': jobInfo['OUTPUT_FILE'],
+ 'errorFile': jobInfo['ERROR_FILE'], 'jobPriority': jobInfo['JOB_PRIORITY'],
+ 'execHost': jobInfo['EXEC_HOST'], 'jobDescription': jobInfo['JOB_DESCRIPTION'],
+ 'exitCode': jobInfo['EXIT_CODE'], 'pendReason': jobInfo['PEND_REASON'],
+ 'jobRunTime': jobInfo['RUN_TIME'], 'originState': jobInfo['STAT'], 'exitMsg': jobInfo['EXIT_REASON']}
+ if outputJob['execHome'] == '':
+ outputJob['execHome'] = jobInfo['EXEC_HOME']
+ nonArrayJobList.append(outputJob)
+
+ # 存储子作业状态到状态表中
+ subJobStat = jobInfo['STAT']
+ subJobId = jobInfo['JOBID']
+ statValArr = [0] * 7
+ if not arrayJobStatDict.has_key(subJobId):
+ arrayJobStatDict[subJobId] = statValArr
+ else:
+ statValArr = arrayJobStatDict[subJobId]
+ subJobStat = jobInfo['STAT']
+ if subJobStat == 'PEND':
+ statValArr[0] = statValArr[0] + 1
+ if subJobStat == 'DONE':
+ statValArr[1] = statValArr[1] + 1
+ if subJobStat == 'RUN':
+ statValArr[2] = statValArr[2] + 1
+ if subJobStat == 'EXIT':
+ statValArr[3] = statValArr[3] + 1
+ if (subJobStat == 'PSUSP') | (subJobStat == 'USUSP'):
+ statValArr[4] = statValArr[4] + 1
+ if subJobStat == 'SSUSP':
+ statValArr[5] = statValArr[5] + 1
+ if subJobStat == 'ZOMBI':
+ statValArr[6] = statValArr[6] + 1
+ arrayJobStatDict[subJobId] = statValArr
+
+jobIdSet = set()
+outputJobList = nonArrayJobList
+# 构造数组作业父作业信息
+for jobInfo in nonArrayJobList:
+ if int(jobInfo['jobIndex']) > 0:
+ jobId = jobInfo['jobId']
+ # 构造数组作业父作业信息
+ if jobId not in jobIdSet:
+ jobIdSet.add(jobId)
+ arrayJobInfo = os.popen(ARRAY_JOB_INFO_CMD + jobId).read().splitlines()
+ if len(arrayJobInfo) == 2:
+ arrayJobInfoValue = arrayJobInfo[1].split()
+ parentJobInfo = copy.deepcopy(jobInfo)
+ if len(arrayJobInfoValue) > 2:
+ parentJobName = arrayJobInfoValue[1]
+ parentJobInfo['jobName'] = parentJobName
+ arrayJobStatArr = arrayJobStatDict[jobId]
+ aggJobState(parentJobInfo, arrayJobStatArr)
+ parentJobInfo['originState'] = parentJobInfo['stat']
+ parentJobInfo['stat'] = str(statMap[parentJobInfo['stat']])
+ parentJobInfo['jobIndex'] = 0
+ # 调度器父作业runtime等信息默认不聚合,用户根据需要聚合
+ parentJobInfo['jobRunTime'] = None
+ parentJobInfo['startTime'] = None
+ parentJobInfo['finishTime'] = None
+ parentJobInfo['queue'] = None
+ parentJobInfo['execHost'] = None
+ parentJobInfo['outputFile'] = None
+ parentJobInfo['errorFile'] = None
+ parentJobInfo['execHome'] = None
+ parentJobInfo['jobPriority'] = None
+ parentJobInfo['exitCode'] = None
+ parentJobInfo['pendReason'] = None
+ outputJobList.append(parentJobInfo)
+outputStr = json.dumps(outputJobList)
+print(outputStr)
diff --git a/LSF-Script/collection/jobSample b/LSF-Script/collection/jobSample
new file mode 100644
index 0000000000000000000000000000000000000000..39b8811797dcc15bec610505cbf6a04370595f8a
--- /dev/null
+++ b/LSF-Script/collection/jobSample
@@ -0,0 +1,211 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+import copy
+import json
+import os
+import time
+
+JOB_INFOS_CMD_ARM = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 bjobs -a -u all -hms -o \"jobid jobindex job_name user source_cluster stat ' \
+ 'queue from_host submit_time start_time finish_time exec_home output_dir output_file error_file job_priority ' \
+ 'exec_host job_description exit_code pend_reason run_time cpu_used mem avg_mem max_mem swap cpu_used gpu_num gpu_alloc slots nreq_slot nalloc_slot alloc_slot delimiter=\'^\'\"'
+
+JOB_INFOS_CMD_X86 = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 bjobs -a -u all -hms -o \"jobid jobindex job_name user source_cluster stat ' \
+ 'queue from_host submit_time start_time finish_time exec_home output_dir output_file error_file job_priority ' \
+ 'exec_host job_description exit_code pend_reason run_time cpu_used mem avg_mem max_mem swap cpu_used slots nalloc_slot alloc_slot delimiter=\'^\'\"'
+
+ARRAY_JOB_INFO_CMD = 'source @SCHEDULER_PROFILE_PATH@; timeout 10 bjobs -A -w '
+
+statMap = {'UNKWN': -1, 'RUN': 4, 'PSUSP': 2, 'USUSP': 2, 'SSUSP': 10, 'PEND': 1, 'DONE': 9, 'EXIT': 5, 'WAIT': 3, 'ZOMBI': -1}
+
+jobFields_arm = ['JOBID', 'JOBINDEX', 'JOB_NAME', 'USER', 'SOURCE_CLUSTER', 'STAT', 'QUEUE', 'FROM_HOST', 'SUBMIT_TIME',
+ 'START_TIME', 'FINISH_TIME', 'EXEC_HOME', 'OUTPUT_DIR', 'OUTPUT_FILE', 'ERROR_FILE', 'JOB_PRIORITY',
+ 'EXEC_HOST', 'JOB_DESCRIPTION', 'EXIT_CODE', 'PEND_REASON', 'RUN_TIME', 'CPU_USED', 'MEM', 'AVG_MEM',
+ 'MAX_MEM', 'SWAP', 'CPU_USED', 'GPU_NUM', 'GPU_ALLOC', 'SLOTS', 'NREQ_SLOT', 'NALLOC_SLOT', 'ALLOC_SLOT']
+
+jobFields_x86 = ['JOBID', 'JOBINDEX', 'JOB_NAME', 'USER', 'SOURCE_CLUSTER', 'STAT', 'QUEUE', 'FROM_HOST', 'SUBMIT_TIME',
+ 'START_TIME', 'FINISH_TIME', 'EXEC_HOME', 'OUTPUT_DIR', 'OUTPUT_FILE', 'ERROR_FILE', 'JOB_PRIORITY',
+ 'EXEC_HOST', 'JOB_DESCRIPTION', 'EXIT_CODE', 'PEND_REASON', 'RUN_TIME', 'CPU_USED', 'MEM', 'AVG_MEM',
+ 'MAX_MEM', 'SWAP', 'CPU_USED', 'SLOTS', 'NALLOC_SLOT', 'ALLOC_SLOT']
+
+def aggJobState(parentJobinfo, arrayJobStatArr):
+ if len(arrayJobStatArr) < 7:
+ parentJobinfo['stat'] = 'UNKWN'
+ return
+ runNum = int(arrayJobStatArr[2])
+ if runNum > 0:
+ parentJobinfo['stat'] = 'RUN'
+ return
+ usupNum = int(arrayJobStatArr[4])
+ if usupNum > 0:
+ parentJobinfo['stat'] = 'USUSP'
+ return
+ ssuspNum = int(arrayJobStatArr[5])
+ if ssuspNum > 0:
+ parentJobinfo['stat'] = 'SSUSP'
+ return
+ pendNum = int(arrayJobStatArr[0])
+ if pendNum > 0:
+ parentJobinfo['stat'] = 'PEND'
+ return
+ exitNum = int(arrayJobStatArr[3])
+ if exitNum > 0:
+ parentJobinfo['stat'] = 'EXIT'
+ return
+ doneNum = int(arrayJobStatArr[1])
+ if doneNum > 0:
+ parentJobinfo['stat'] = 'DONE'
+ return
+ doneNum = int(arrayJobStatArr[6])
+ if doneNum > 0:
+ parentJobinfo['stat'] = 'ZOMBI'
+ return
+ parentJobinfo['stat'] = 'UNKWN'
+ return
+
+def getOrder():
+ if(os.popen('uname -a').read().__contains__('x86')):
+ return JOB_INFOS_CMD_X86
+ return JOB_INFOS_CMD_ARM
+
+def strToJson(jobInfoStr):
+ jobInfoArr = jobInfoStr.split("^")
+ jobInfo = {}
+ if len(jobInfoArr) == len(jobFields_arm):
+ for index in range(len(jobFields_arm)):
+ field = jobInfoArr[index]
+ if field == '-':
+ field = ''
+ jobInfo[jobFields_arm[index]] = field
+ return jobInfo
+ if len(jobInfoArr) == len(jobFields_x86):
+ for index in range(len(jobFields_x86)):
+ field = jobInfoArr[index]
+ if field == '-':
+ field = ''
+ jobInfo[jobFields_x86[index]] = field
+ jobInfo['NREQ_SLOT'] = ''
+ jobInfo['GPU_NUM'] = ''
+ jobInfo['GPU_ALLOC'] = ''
+ return jobInfo
+
+jobInfos = os.popen(getOrder()).read()
+jobInfosArr = jobInfos.strip().split("\n")
+
+arrayJobStatDict = {}
+# 构造非数组作业及数组作业子作业信息 及数组作业状态表
+nonArrayJobList = []
+
+timeresult = time.localtime(time.time())
+timelist = list(timeresult)
+timelist[4] = int(timeresult.tm_min/5)*5
+timelist[5] = 0
+timeresult = tuple(timelist)
+result = time.localtime(time.mktime(timeresult))
+sampletime = time.strftime('%Y/%m/%d %H:%M:%S',result)
+
+for index in range(len(jobInfosArr)):
+ if index == 0:
+ continue
+ jobInfo = strToJson(jobInfosArr[index])
+ jobInfo['OUTPUT_DIR'] = jobInfo['OUTPUT_DIR'].rstrip('/')
+ if not statMap.has_key(jobInfo['STAT']):
+ statMap[jobInfo['STAT']]=-1
+ # 替换key值为期望解析值
+ outputJob = {'jobId': jobInfo['JOBID'], 'jobIndex': int(jobInfo['JOBINDEX']), 'jobName': jobInfo['JOB_NAME'],
+ 'user': jobInfo['USER'], 'cluster': jobInfo['SOURCE_CLUSTER'],
+ 'stat': str(statMap[jobInfo['STAT']]),
+ 'queue': jobInfo['QUEUE'], 'fromHost': jobInfo['FROM_HOST'], 'submitTime': jobInfo['SUBMIT_TIME'],
+ 'startTime': jobInfo['START_TIME'], 'finishTime': jobInfo['FINISH_TIME'],
+ 'execHome': jobInfo['OUTPUT_DIR'], 'outputFile': jobInfo['OUTPUT_FILE'],
+ 'errorFile': jobInfo['ERROR_FILE'], 'jobPriority': jobInfo['JOB_PRIORITY'],
+ 'execHost': jobInfo['EXEC_HOST'], 'jobDescription': jobInfo['JOB_DESCRIPTION'],
+ 'exitCode': jobInfo['EXIT_CODE'], 'pendReason': jobInfo['PEND_REASON'],
+ 'jobRunTime': jobInfo['RUN_TIME'], 'originState': jobInfo['STAT'],
+ 'resReq': {
+ 'cpu': jobInfo['NREQ_SLOT'] if jobInfo['NREQ_SLOT'] != '' else None,
+ 'mem': None,
+ 'gpu': None
+ },
+ 'resAlloc': {
+ 'cpu': jobInfo['NALLOC_SLOT'] if jobInfo['NALLOC_SLOT'] != '' else None,
+ 'mem': None,
+ 'gpu': jobInfo['GPU_ALLOC'] if jobInfo['GPU_ALLOC'] != '' else None
+ },
+ 'rusage': {
+ 'memAvg': jobInfo['AVG_MEM'] if jobInfo['AVG_MEM'] != '' else None,
+ 'memMax': jobInfo['MAX_MEM'] if jobInfo['MAX_MEM'] != '' else None,
+ 'memReal': jobInfo['MEM'] if jobInfo['MEM'] != '' else None,
+ 'swap': jobInfo['SWAP'],
+ 'swapMax': None,
+ 'rss': None,
+ 'cache': None
+ },
+ 'timeStampL': sampletime}
+
+ if outputJob['execHome'] == '':
+ outputJob['execHome'] = jobInfo['EXEC_HOME']
+ nonArrayJobList.append(outputJob)
+
+ # 存储子作业状态到状态表中
+ subJobStat = jobInfo['STAT']
+ subJobId = jobInfo['JOBID']
+ statValArr = [0] * 7
+ if not arrayJobStatDict.has_key(subJobId):
+ arrayJobStatDict[subJobId] = statValArr
+ else:
+ statValArr = arrayJobStatDict[subJobId]
+ subJobStat = jobInfo['STAT']
+ if subJobStat == 'PEND':
+ statValArr[0] = statValArr[0] + 1
+ if subJobStat == 'DONE':
+ statValArr[1] = statValArr[1] + 1
+ if subJobStat == 'RUN':
+ statValArr[2] = statValArr[2] + 1
+ if subJobStat == 'EXIT':
+ statValArr[3] = statValArr[3] + 1
+ if (subJobStat == 'PSUSP') | (subJobStat == 'USUSP'):
+ statValArr[4] = statValArr[4] + 1
+ if subJobStat == 'SSUSP':
+ statValArr[5] = statValArr[5] + 1
+ if subJobStat == 'ZOMBI':
+ statValArr[6] = statValArr[6] + 1
+ arrayJobStatDict[subJobId] = statValArr
+
+jobIdSet = set()
+outputJobList = nonArrayJobList
+# 构造数组作业父作业信息
+for jobInfo in nonArrayJobList:
+ if int(jobInfo['jobIndex']) > 0:
+ jobId = jobInfo['jobId']
+ # 构造数组作业父作业信息
+ if jobId not in jobIdSet:
+ jobIdSet.add(jobId)
+ arrayJobInfo = os.popen(ARRAY_JOB_INFO_CMD + jobId).read().splitlines()
+ if len(arrayJobInfo) == 2:
+ arrayJobInfoValue = arrayJobInfo[1].split()
+ parentJobInfo = copy.deepcopy(jobInfo)
+ if len(arrayJobInfoValue) > 2:
+ parentJobName = arrayJobInfoValue[1]
+ parentJobInfo['jobName'] = parentJobName
+ arrayJobStatArr = arrayJobStatDict[jobId]
+ aggJobState(parentJobInfo, arrayJobStatArr)
+ parentJobInfo['originState'] = parentJobInfo['stat']
+ parentJobInfo['stat'] = str(statMap[parentJobInfo['stat']])
+ parentJobInfo['jobIndex'] = 0
+ # 调度器父作业runtime等信息默认不聚合,用户根据需要聚合
+ parentJobInfo['jobRunTime'] = None
+ parentJobInfo['startTime'] = None
+ parentJobInfo['finishTime'] = None
+ parentJobInfo['queue'] = None
+ parentJobInfo['execHost'] = None
+ parentJobInfo['outputFile'] = None
+ parentJobInfo['errorFile'] = None
+ parentJobInfo['execHome'] = None
+ parentJobInfo['jobPriority'] = None
+ parentJobInfo['exitCode'] = None
+ parentJobInfo['pendReason'] = None
+ outputJobList.append(parentJobInfo)
+outputStr = json.dumps(outputJobList)
+print(outputStr)
diff --git a/LSF-Script/job/rerun b/LSF-Script/job/rerun
new file mode 100644
index 0000000000000000000000000000000000000000..6fd7fc2da43cb8733e1c736b5e5877ea00d07bf2
--- /dev/null
+++ b/LSF-Script/job/rerun
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# Copyright (c) Huawei Technologies Co., Ltd. 2018-2022. All rights reserved.
+#
+# An example script for rerunning a job in a LSF cluster.
+#
+# To enable this script, rename this file to "rerun".
+
+# PROFILE_PATH: Profile file path of the scheduler.
+PROFILE_PATH=@SCHEDULER_PROFILE_PATH@
+if [ -f "$PROFILE_PATH" ]; then
+ source "$PROFILE_PATH"
+else
+ echo "Failed to run the command. Failed to set up the environment." >&2
+ exit 2
+fi
+
+if [ "$#" -gt 0 ]; then
+ out=`timeout 10 brequeue -e -d "$@" 2>&1`
+else
+ echo "Failed to run the command. The job ID list is not found." >&2
+ exit 2
+fi
+
+exit_code=$?
+if [ "${exit_code}" -eq 0 ]; then
+ echo ${out}
+else
+ echo ${out} >&2
+ exit ${exit_code}
+fi
\ No newline at end of file
diff --git a/LSF-Script/job/resume b/LSF-Script/job/resume
new file mode 100644
index 0000000000000000000000000000000000000000..32138d018db61124d3dbc8ab14c8a578f65215b8
--- /dev/null
+++ b/LSF-Script/job/resume
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# Copyright (c) Huawei Technologies Co., Ltd. 2018-2022. All rights reserved.
+#
+# An example script for resuming a job in a LSF cluster.
+#
+# To enable this script, rename this file to "resume".
+
+# PROFILE_PATH: Profile file path of the scheduler.
+PROFILE_PATH=@SCHEDULER_PROFILE_PATH@
+if [ -f "$PROFILE_PATH" ]; then
+ source "$PROFILE_PATH"
+else
+ echo "Failed to run the command. Failed to set up the environment." >&2
+ exit 2
+fi
+
+if [ "$#" -gt 0 ]; then
+ out=`timeout 10 bresume "$@" 2>&1`
+else
+ echo "Failed to run the command. The job ID list is not found." >&2
+ exit 2
+fi
+
+exit_code=$?
+if [ "${exit_code}" -eq 0 ]; then
+ echo ${out}
+else
+ echo ${out} >&2
+ exit ${exit_code}
+fi
\ No newline at end of file
diff --git a/LSF-Script/job/stop b/LSF-Script/job/stop
new file mode 100644
index 0000000000000000000000000000000000000000..5ed1b7847e816b10daa7800e2dcb4b28a84a7029
--- /dev/null
+++ b/LSF-Script/job/stop
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# Copyright (c) Huawei Technologies Co., Ltd. 2018-2022. All rights reserved.
+#
+# An example script for stopping a job in a LSF cluster.
+#
+# To enable this script, rename this file to "stop".
+
+# PROFILE_PATH: Profile file path of the scheduler.
+PROFILE_PATH=@SCHEDULER_PROFILE_PATH@
+if [ -f "$PROFILE_PATH" ]; then
+ source "$PROFILE_PATH"
+else
+ echo "Failed to run the command. Failed to set up the environment." >&2
+ exit 2
+fi
+
+if [ "$#" -gt 0 ]; then
+ out=`timeout 10 bkill "$@" 2>&1`
+else
+ echo "Failed to run the command. The job ID list is not found." >&2
+ exit 2
+fi
+
+exit_code=$?
+if [ "${exit_code}" -eq 0 ]; then
+ echo ${out}
+else
+ echo ${out} >&2
+ exit ${exit_code}
+fi
\ No newline at end of file
diff --git a/LSF-Script/job/submit b/LSF-Script/job/submit
new file mode 100644
index 0000000000000000000000000000000000000000..0b62dee9b1f07f0ccef58bc87b17504638557bca
--- /dev/null
+++ b/LSF-Script/job/submit
@@ -0,0 +1,70 @@
+#!/bin/bash
+#
+# Copyright (c) Huawei Technologies Co., Ltd. 2018-2022. All rights reserved.
+#
+# An example script for submitting a job to a LSF cluster.
+# Method "submit_job" needs to be declared in this script for job submission.
+#
+# To enable this script, rename this file to "submit".
+#
+# Available environment variables for the script:
+# _TEMPLATE_NAME: Name of the job template.
+# VNC_DISPLAY_FLAG: Identifier for submitting an interactive job.
+# _SECURITY_LEVEL: Security level of the job.
+# _PRE_EXEC_SCRIPT_PATH: Pre-execution script for remote data file transfer.
+# _POST_EXEC_SCRIPT_PATH: Pre-execution script for job data file transfer.
+# JOB_DIR: Submit job dir.
+#
+# Requires for method "submit_job":
+# Input Parameters: Command parameters that are combined with user scripts and commit parameters.
+# Output format: The Job ID returned by the scheduler.
+# Error format: Error code and error information returned by the scheduler.
+# Exit Code: If the job is submitted successfully, the exit code is 0. Otherwise, the exit code is 2.
+#
+# Requires for method "submit_preview":
+# Input Parameters: Command parameters that are combined with user scripts and commit parameters.
+# Output format: Command for the scheduler to submit a job.
+
+# PROFILE_PATH: Profile file path of the scheduler.
+if [ -z "${_JOB_PATH}" ]; then
+ JOB_DIR=$(echo "$OUT_DIR" | awk -F / -v OFS="/" '{$NF=""}1')
+else
+ JOB_DIR=${_JOB_PATH}
+fi
+PROFILE_PATH=@SCHEDULER_PROFILE_PATH@
+if [ "X${_PREVIEW_COMMAND}" != "Xtrue" ]; then
+ if [ -f "$PROFILE_PATH" ]; then
+ source "$PROFILE_PATH"
+ else
+ echo "Failed to run the command. Failed to set up the environment." >&2
+ exit 2
+ fi
+fi
+
+submit_job() {
+ if [ "$_IS_DATA_TRANSFER" == "false" ]; then
+ submit_result=$(echo timeout 10 bsub -outdir ${JOB_DIR} -o ${JOB_DIR}out.log -e ${JOB_DIR}error.log -Jd "TEMPLATE=${_TEMPLATE_NAME},DISPLAY_FLAG=${VNC_DISPLAY_FLAG},SECURITY_LEVEL=${_SECURITY_LEVEL}" "$@" | bash)
+ else
+ submit_result=$(echo timeout 10 bsub -E ${_PRE_EXEC_SCRIPT_PATH} -Ep ${_POST_EXEC_SCRIPT_PATH} -outdir ${JOB_DIR} -o ${JOB_DIR}out.log -e ${JOB_DIR}error.log -Jd "TEMPLATE=${_TEMPLATE_NAME},DISPLAY_FLAG=${VNC_DISPLAY_FLAG},SECURITY_LEVEL=${_SECURITY_LEVEL}" "$@" | bash)
+ fi
+ ret_value=$?
+
+ if [ $ret_value -eq 0 ]; then
+ job_result=$(echo "$submit_result" | awk -F'[<|>]' '{print $2}')
+ else
+ job_result=$submit_result
+ fi
+
+ if [ "$ret_value" -eq 0 ]; then
+ echo "The job has been submitted successfully. Job ID is: [$job_result]."
+ elif [ "$ret_value" -eq 124 ]; then
+ echo "$ret_value" 1>&2
+ exit "$ret_value"
+ else
+ echo "$job_result" 1>&2
+ fi
+}
+
+submit_preview() {
+ echo "bsub -outdir ${JOB_DIR} -o ${JOB_DIR}out.log -e ${JOB_DIR}error.log -Jd TEMPLATE=${_TEMPLATE_NAME},DISPLAY_FLAG=${VNC_DISPLAY_FLAG},SECURITY_LEVEL=${_SECURITY_LEVEL}" "$@"
+}
\ No newline at end of file
diff --git a/LSF-Script/job/suspend b/LSF-Script/job/suspend
new file mode 100644
index 0000000000000000000000000000000000000000..8cdbab48d2c772a94af3787441117ec7644dedcf
--- /dev/null
+++ b/LSF-Script/job/suspend
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# Copyright (c) Huawei Technologies Co., Ltd. 2018-2022. All rights reserved.
+#
+# An example script for suspending a job in a LSF cluster.
+#
+# To enable this script, rename this file to "suspend".
+
+# PROFILE_PATH: Profile file path of the scheduler.
+PROFILE_PATH=@SCHEDULER_PROFILE_PATH@
+if [ -f "$PROFILE_PATH" ]; then
+ source "$PROFILE_PATH"
+else
+ echo "Failed to run the command. Failed to set up the environment." >&2
+ exit 2
+fi
+
+if [ "$#" -gt 0 ]; then
+ out=`timeout 10 bstop "$@" 2>&1`
+else
+ echo "Failed to run the command. The job ID list is not found." >&2
+ exit 2
+fi
+
+exit_code=$?
+if [ "${exit_code}" -eq 0 ]; then
+ echo ${out}
+else
+ echo ${out} >&2
+ exit ${exit_code}
+fi
\ No newline at end of file
diff --git a/LSF-Script/node/node b/LSF-Script/node/node
new file mode 100644
index 0000000000000000000000000000000000000000..c06ecf0e9a2b4060ada9707f47889769053d40b3
--- /dev/null
+++ b/LSF-Script/node/node
@@ -0,0 +1,123 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+import copy
+import json
+import os
+import re
+
+#输出示例.
+# [{
+# "nativeResources": {
+# "loadResources": {
+# "cpuFree": "",
+# "gpuFree": "",
+# "memFree": "135508.0M"
+# },`
+# "mCpu": "40",
+# "mGpu": "",
+# "mem": "187.2G"
+# },
+# "nodeName": "hpc61",
+# "numaInfo": {
+# "architecture": "X86_64"
+# },
+# "powerSavingStatus": "",
+# "status": "",
+# "originStatus": "ok"
+# }, {
+# "nativeResources": {
+# "loadResources": {
+# "cpuFree": "",
+# "gpuFree": "",
+# "memFree": "500000M"
+# },
+# "mCpu": "80",
+# "mGpu": "",
+# "mem": "500g"
+# },
+# "nodeName": "hpc62",
+# "numaInfo": {
+# "architecture": "ios"
+# },
+# "powerSavingStatus": "",
+# "status": "",
+# "originStatus": ""
+# }]
+
+LSLOAD_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 lsload -w'
+
+nodeloads = os.popen(LSLOAD_CMD).read()
+nodeloadstr = nodeloads.split("\n")
+nodes = []
+for index in range(1, len(nodeloadstr) - 1):
+ temp=dict(zip(nodeloadstr[0].split(),nodeloadstr[index].split()))
+ nodes.append(temp)
+
+
+#lshosts客户不支持-json -o形式,需要另外处理
+LSHOSTS_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 lshosts -w'
+
+#执行lshosts获取返回结果 返回cpu总数+内存总大小+架构类型
+nodehost = os.popen(LSHOSTS_CMD).read()
+#通过换行符分割,但是去掉首尾,只对中间进行遍历
+nodehosts = nodehost.split("\n")
+#执行lshosts 获取lshost的结果集
+hosts=[]
+for i in range(1,len(nodehosts)-1):
+ host=dict(zip(nodehosts[0].split(),nodehosts[i].split()))
+ hosts.append(host)
+
+#通过bslots 获取可用cpu数
+BSLOTS_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 bslots -l'
+slotsinfo = os.popen(BSLOTS_CMD).read()
+slotsinfostr = slotsinfo.split("\n")
+slotstr = []
+if len(slotsinfostr) > 2:
+ tmpslotinfostr = slotsinfostr[2].split(" ")
+ slotstr = tmpslotinfostr[4:len(tmpslotinfostr)-1]
+
+slots = {}
+for index in range(0, len(slotstr)):
+ tmp=slotstr[index].split("*")
+ slots[tmp[1]] = tmp[0]
+
+nodeArrayList = []
+for nodearry in nodes:
+ output = {"nativeResources": {"loadResources": {"cpuFree": slots[nodearry['HOST_NAME']] if slots.keys().__contains__(nodearry['HOST_NAME']) else 0,"gpuFree": "","memFree": nodearry['mem'] if nodearry.keys().__contains__('mem') else None},"mCpu": "","mGpu": "","mem": ""},
+ "nodeName": nodearry['HOST_NAME'],"numaInfo": {"architecture": ""},"powerSavingStatus": "",
+ "status": "","originStatus": ""}
+ nodeArrayList.append(output)
+
+
+#执行bhosts
+BHOSTS_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 bhosts -o "HOST_NAME STATUS NGPUS"'
+bhosts = os.popen(BHOSTS_CMD).read()
+bhoststr = bhosts.split("\n")
+bhosts = []
+for index in range(1, len(bhoststr) - 1):
+ temp=dict(zip(bhoststr[0].split(),bhoststr[index].split()))
+ bhosts.append(temp)
+
+#基于第三方调度器向DONAU调度器状态映射Map
+statusMap = {'ok': 'OKAY', 'closed': 'CLOSED', 'closed_Adm': 'CLOSED','closed_Busy': 'CLOSED','closed_EGO': 'CLOSED','closed_Excl': 'CLOSED','closed_LIM': 'CLOSED',
+'closed_Lock': 'CLOSED','closed_Wind': 'CLOSED','closed_RC': 'CLOSED','closed_CU_excl': 'CLOSED','unavail': 'UNAVAILABLE', 'unreach': 'UNAVAILABLE', 'closed_Full': 'CLOSED'}
+
+for hostinfo in nodeArrayList:
+ for bhost in bhosts:
+ if bhost['HOST_NAME'] == hostinfo['nodeName']:
+ hostinfo['originStatus'] = bhost['STATUS']
+ hostinfo['status'] = str(statusMap[bhost['STATUS']] if statusMap.keys().__contains__(bhost['STATUS']) else unknow)
+ hostinfo['nativeResources']['mGpu'] = bhost['NGPUS']
+ for host in hosts:
+ if host['HOST_NAME'] == hostinfo['nodeName']:
+ hostinfo['nativeResources']['mCpu'] = host['ncpus']
+ hostinfo['nativeResources']['mem'] = host['maxmem']
+ hostinfo['numaInfo']['architecture'] = host['type']
+ if (hostinfo['status'] == 'CLOSED' and hostinfo['nativeResources']['loadResources']['cpuFree'] == 0):
+ hostinfo['nativeResources']['loadResources']['cpuFree'] = host['ncpus']
+outputStr = json.dumps(nodeArrayList)
+print(outputStr)
\ No newline at end of file
diff --git a/LSF-Script/node/nodeSample b/LSF-Script/node/nodeSample
new file mode 100644
index 0000000000000000000000000000000000000000..26ce1cc0385b7bc2f8748c1b6eb322d41a7ec57f
--- /dev/null
+++ b/LSF-Script/node/nodeSample
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+import copy
+import json
+import os
+import time
+
+LSLOAD_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 lsload -w'
+
+nodeloads = os.popen(LSLOAD_CMD).read()
+nodeloadstr = nodeloads.split("\n")
+nodes = []
+for index in range(1, len(nodeloadstr) - 1):
+ temp=dict(zip(nodeloadstr[0].split(),nodeloadstr[index].split()))
+ nodes.append(temp)
+
+LSLOAD_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 lsload -o "HOST_NAME io"'
+
+nodeioloads = os.popen(LSLOAD_CMD).read()
+nodeioloadstr = nodeioloads.split("\n")
+nodesio = {}
+for index in range(1, len(nodeloadstr) - 1):
+ nodesio[nodeioloadstr[index].split(" ")[0]] = nodeioloadstr[index].split(" ")[1]
+
+BHOSTS_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 bhosts -o "HOST_NAME STATUS NGPUS"'
+bhosts = os.popen(BHOSTS_CMD).read()
+bhoststr = bhosts.split("\n")
+bhosts = []
+for index in range(1, len(bhoststr) - 1):
+ temp=dict(zip(bhoststr[0].split(),bhoststr[index].split()))
+ bhosts.append(temp)
+
+#lshosts客户不支持-json -o形式,需要另外处理
+LSHOSTS_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 lshosts -w'
+
+#执行lshosts获取返回结果 返回cpu总数+内存总大小+架构类型
+nodehost = os.popen(LSHOSTS_CMD).read()
+nodehoststr = nodehost.split("\n")
+hosts = []
+for index in range(1, len(nodehoststr) - 1):
+ temp=dict(zip(nodehoststr[0].split(),nodehoststr[index].split()))
+ hosts.append(temp)
+
+#通过lsclusters获取集群名称+主机名称
+LSCLUSTERS_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 lsclusters -w'
+clusterinfo = os.popen(LSCLUSTERS_CMD).read()
+clusterinfostr = clusterinfo.split("\n")
+bclusterinfo = []
+for index in range(1, len(clusterinfostr) - 1):
+ temp=dict(zip(clusterinfostr[0].split(),clusterinfostr[index].split()))
+ bclusterinfo.append(temp)
+
+#通过bslots 获取可用cpu数
+BSLOTS_CMD = 'source @SCHEDULER_PROFILE_PATH@;' \
+ 'timeout 10 bslots -l'
+slotsinfo = os.popen(BSLOTS_CMD).read()
+slotsinfostr = slotsinfo.split("\n")
+slotstr = []
+if len(slotsinfostr) > 2:
+ tmpslotinfostr = slotsinfostr[2].split(" ")
+ slotstr = tmpslotinfostr[4:len(tmpslotinfostr)-1]
+
+slots = {}
+for index in range(0, len(slotstr)):
+ tmp=slotstr[index].split("*")
+ slots[tmp[1]] = tmp[0]
+
+nodeArrayList = []
+
+timeresult = time.localtime(time.time())
+timelist = list(timeresult)
+timelist[4] = int(timeresult.tm_min/5)*5
+timelist[5] = 0
+timeresult = tuple(timelist)
+result = time.localtime(time.mktime(timeresult))
+sampletime = time.strftime('%Y/%m/%d %H:%M:%S',result)
+
+nodeinfoTmp = {'status': None, 'tmp': None, 'mem': None, 'r15m': None, 'r15s': None, 'ls': None, 'it': None,
+ 'HOST_NAME': None, 'ut': None, 'swp': None, 'r1m': None, 'pg': None}
+for nodeinfo in nodes:
+ for key in nodeinfo.keys():
+ nodeinfoTmp[key] = nodeinfo[key]
+ memFreeTmp = None
+ if nodeinfoTmp['mem'] != None:
+ memFreeTmp = int(float(nodeinfoTmp['mem'][:-1]) * 1024) if nodeinfoTmp['mem'][-1:] == 'G' else int(
+ float(nodeinfoTmp['mem'][:-1]))
+ output = {
+ "cluster": "",
+ "timeStampL": sampletime,
+ "sampleInterval": "300",
+ "hostName": nodeinfoTmp['HOST_NAME'],
+ "state": "",
+ "core": "",
+ "coreFree": int(slots[nodeinfoTmp['HOST_NAME']]) if slots.keys().__contains__(nodeinfoTmp['HOST_NAME']) else 0,
+ "mem": "",
+ "memFree": memFreeTmp,
+ "gpu": "",
+ "gpuFree": None,
+ "swap": "",
+ "swapFree": int(float(nodeinfoTmp['swp'][:-1]) * 1024) if nodeinfoTmp['swp'] != None else None,
+ "tmp": None,
+ "tmpFree": int(float(nodeinfoTmp['tmp'][:-1])) if nodeinfoTmp['tmp'] != None else None,
+ "cpuUtil": float(nodeinfoTmp['ut'][:-1]) / 100 if nodeinfoTmp['ut'] != None else None,
+ "loadAverage": None,
+ "ioRate": nodesio[nodeinfoTmp['HOST_NAME']] if nodesio[nodeinfoTmp['HOST_NAME']] != '-' else None,
+ "pageRate": nodeinfoTmp['pg'] if nodeinfoTmp['pg'] != None else None,
+ "idleTime": None,
+ "belongResourcePool": None,
+ "numaNum": None,
+ "coreNum": None,
+ "threadNum": None,
+ "socketNum": None,
+ "cpuBuildType": "",
+ "cpuModel": "",
+ "cpuBasic": None
+ }
+ nodeArrayList.append(output)
+
+# 基于第三方调度器向DONAU调度器状态映射Map
+statusMap = {'ok': 'OKAY', 'closed': 'CLOSED', 'closed_Adm': 'CLOSED', 'closed_Busy': 'CLOSED', 'closed_EGO': 'CLOSED',
+ 'closed_Excl': 'CLOSED', 'closed_LIM': 'CLOSED',
+ 'closed_Lock': 'CLOSED', 'closed_Wind': 'CLOSED', 'closed_RC': 'CLOSED', 'closed_CU_excl': 'CLOSED',
+ 'unavail': 'UNAVAILABLE', 'unreach': 'UNAVAILABLE', 'closed_Full': 'CLOSED'}
+
+for hostinfo in nodeArrayList:
+ for host in hosts:
+ if host['HOST_NAME'] == hostinfo['hostName']:
+ hostinfo['core'] = None if host['ncpus'] == '-' else host['ncpus']
+ hostinfo['mem'] = None if host['maxmem'] == '-' else int(float(host['maxmem'][:-1])*1024)
+ hostinfo['swap'] = None if host['maxswp'] == '-' else int(float(host['maxswp'][:-1])*1024)
+ hostinfo['cpuModel'] = host['model']
+ hostinfo['cpuBuildType'] = 'x86_64' if host['type'] == 'X86_64' else host['type']
+ for bhost in bhosts:
+ if bhost['HOST_NAME'] == hostinfo['hostName']:
+ hostinfo['state'] = str(
+ statusMap[bhost['STATUS']] if statusMap.keys().__contains__(bhost['STATUS']) else unknow)
+ hostinfo['gpu'] = bhost['NGPUS']
+ for cluster in bclusterinfo:
+ hostinfo['cluster'] = cluster['CLUSTER_NAME']
+ if hostinfo['core'] == None:
+ hostinfo['coreFree'] = None
+ hostinfo['cpuUtil'] = None
+ if hostinfo['gpu'] == None:
+ hostinfo['gpuFree'] = None
+ if hostinfo['mem'] == None:
+ hostinfo['memFree'] = None
+ if hostinfo['swap'] == None:
+ hostinfo['swapFree'] = None
+ if hostinfo['tmp'] == None:
+ hostinfo['tmpFree'] = None
+
+outputStr = json.dumps(nodeArrayList)
+print(outputStr)
diff --git a/LSF-Script/queue/query-active b/LSF-Script/queue/query-active
new file mode 100644
index 0000000000000000000000000000000000000000..5b286a8f0f7ebf00ecaa7ed8c60096b171c077d6
--- /dev/null
+++ b/LSF-Script/queue/query-active
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (c) Huawei Technologies Co., Ltd. 2018-2022. All rights reserved.
+#
+# An example script for querying the active queue in a LSF cluster.
+#
+# To enable this script, rename this file to "query-active".
+
+# PROFILE_PATH: Profile file path of the scheduler.
+PROFILE_PATH=@SCHEDULER_PROFILE_PATH@
+if [ -f "$PROFILE_PATH" ]; then
+ source "$PROFILE_PATH"
+else
+ echo "Failed to run the command. Failed to set up the environment." >&2
+ exit 2
+fi
+
+timeout 10 bqueues -o "QUEUE_NAME"
\ No newline at end of file
diff --git a/README.en.md b/README.en.md
index 5e2cf3822a9c7273546f4a9fbd156fb0696c7255..d1ced6c092c1721749e249440469128c6ca51b9c 100644
--- a/README.en.md
+++ b/README.en.md
@@ -1,22 +1,73 @@
# portal-mulit-cluster-script
#### Description
-portal-mulit-cluster-script provide some scripts for other Scheduler Users to submit and manage jobs in Donau cluster environment
+The Donau Portal enables the Donau Portal to connect to and manage multiple computing clusters of different types. For non-Donau scheduler clusters, third-party scripts need to be adapted based on the Donau rule output. portal-mulit-cluster-script provides the best script for connecting the Donau Portal to an LSF cluster. Currently, the following scripts are supported:
+
+```
+LSF Node Information Collection Script: node, nodeSample
+LSF Job Information Collection Script : job, jobSample
+LSF Job Submission Script : submit
+LSF Job Operation Script : stop, resume, rerun, suspend
+LSF Queue Query Script : query-active
+```
#### Software Architecture
-Software architecture description
+Python2/Python3
+
+#### Operation
+
+1. Download the compressed package from https://gitee.com/openeuler/portal-mulit-cluster-script and decompress it to the {INSTALL_PATH}/huawei/portal/ac/scripts/scheduler/{SCHEDULER_TYPE}/ directory.
+
+ Note: INSTALL_PATH is the client installation directory and SCHEDULER_TYPE is the scheduler type.
+
+2. Change the owner of the script to the client installation user with permission 644.
+
+3. Execute the following command to modify the environment variable parameters in the script file:
+
+ ```sh
+ sed -i "s#@SCHEDULER_PROFILE_PATH@#/opt/lsf/conf/profile.lsf#g" `grep @SCHEDULER_PROFILE_PATH@ -rl /opt/huawei/portal/ac/scripts/scheduler/LSF`
+ ```
+
+ Note: /opt/lsf/conf/profile.lsf is the environment variable path of the LSF scheduler; /opt/huawei/portal/ac/scripts/scheduler/LSF is the script directory of the current client node caller.
+
+4. Modify the fileformat file format of the script file to unix (if dos2unix is installed, you can use dos2unix filename1 filename2 filename3 to convert multiple files, if dos2unix is not installed, you can follow the steps below to modify the file format.)
+
+ a) vim filename
-#### Installation
+ b) Input:set ff=unix,then press Enter
-1. xxxx
-2. xxxx
-3. xxxx
+ c) :wq!Save the file.
#### Instructions
-1. xxxx
-2. xxxx
-3. xxxx
+1. Use PuTTY to log in to the Donau Portal Client node as user root.
+
+2. Switch to the remote cluster script directory.
+
+ **cd** */opt/huawei*/**portal/ac/scripts/scheduler/**scheduler_type
+
+ >**Description**
+ >
+ >* "/opt/huawei" is the installation path of Donau Portal.
+ >* "scheduler_type" is the third-party scheduler type.
+ >* Script permissions are all 644.
+ >* The script owner and group are Donau Portal operation and maintenance administrators (such as ccp_master) and their user groups.
+
+3. Integrated job scripts.
+
+ For the description of the input and output parameters of the remote cluster script, please refer to the "Multi-cluster User Guide".
+
+ > **Notice**
+ >
+ > * Multiple applications will be integrated in the user's business scenario, and the application integration is complex. Donau Portal cannot predict the command input in the script. Users need to ensure the security of the script to prevent the injection of malicious commands.
+ > * The scripts under the node directory and collection directory provide host and job information sources in "host", "monitoring center" and "job management". If some fields cannot be collected, "host", "monitoring center", "job management" The information corresponding to this field will cannot be displayed.
+
+4. Use the PuTTY tool to log in to the Donau Portal node as the root user (In an HA scenario, log in to the active and standby Donau Portal nodes). Refer to [Step 2](#step2) [Step 3](#step3) to modify the integration script.
+
+#### Precautions
+
+1. The current script adaptation is for versions after HPC_22.0.0;
+2. Strictly follow the operation steps, otherwise the script may fail to execute.
#### Contribution
diff --git a/README.md b/README.md
index 0a2e9974a5199efc2af87fa1bd13bf7cbb85f483..7b50774e5c82b8cce6a8fd6cbe0c9918fba8f2d1 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,76 @@
# portal-mulit-cluster-script
#### 介绍
-portal-mulit-cluster-script provide some scripts for other Scheduler Users to submit and manage jobs in Donau cluster environment
+多瑙管理平台(Donau Portal)实现了Donau Portal对接和管理多个不同类型计算集群的能力,针对非Donau类型的调度器集群,需要根据Donau的规则输出进行对应的第三方脚本脚本适配。portal-mulit-cluster-script提供了Donau Portal对接LSF类型集群的最佳实际脚本,方便用户参考集成。目前支持的脚本有:
+
+LSF节点信息采集脚本: node,nodeSample
+
+LSF作业信息采集脚本: job,jobSample
+
+LSF作业提交脚本: submit
+
+LSF作业操作脚本: stop, resume,rerun,suspend
+
+LSF队列查询脚本: query-active
#### 软件架构
-软件架构说明
+Python2/Python3
+
+
+#### 操作教程
+
+1. 从网址 https://gitee.com/openeuler/portal-mulit-cluster-script下载压缩包, 解压至{INSTALL_PATH}/huawei/portal/ac/scripts/scheduler/{SCHEDULER_TYPE}/目录下;
+
+ 注:INSTALL_PATH为client安装目录,SCHEDULER_TYPE为调度器类型
+
+2. 更改脚本的属主为client安装用户,权限为644
+
+3. 执行以下命令,修改脚本文件中的环境变量参数
+
+ ```sh
+ sed -i "s#@SCHEDULER_PROFILE_PATH@#/opt/lsf/conf/profile.lsf#g" `grep @SCHEDULER_PROFILE_PATH@ -rl /opt/huawei/portal/ac/scripts/scheduler/LSF`
+ ```
+ 注:/opt/lsf/conf/profile.lsf为LSF调度器环境变量路径;/opt/huawei/portal/ac/scripts/scheduler/LSF为当前client节点调取器脚本目录
-#### 安装教程
+4. 修改脚本文件的fileformat文件格式为unix(如果安装了dos2unix,可以使用dos2unix filename1 filename2 filename3转换多个文件,若未安装dos2unix,可按照下面步骤修改文件格式)
-1. xxxx
-2. xxxx
-3. xxxx
+ a) vim filename
+
+ b) 输入:set ff=unix,然后回车
+
+ c) :wq!保存文件
#### 使用说明
-1. xxxx
-2. xxxx
-3. xxxx
+1. 使用PuTTY工具,以root用户登录Donau Portal Client节点。
+
+2. 切换至远程集群脚本目录。
+
+ **cd** */opt/huawei*/**portal/ac/scripts/scheduler/**scheduler_type
+
+ >**说明**
+ >
+ >* “/opt/huawei”为Donau Portal安装路径。
+ >* “scheduler_type”为第三方调度器类型。
+ >* 脚本权限均为644。
+ >* 脚本属主和属组均为Donau Portal运维管理员(如ccp_master)及其用户组。
+
+3. 集成作业脚本。
+
+ 远程集群脚本输入输出参数说明请参见《多集群使用指导说明书》。
+
+ >**须知**
+ >
+ >* 用户业务场景中会集成多种应用,且应用集成较复杂,Donau Portal无法预测脚本中的命令输入,用户需确保脚本的安全性,防止恶意命令的注入。
+ >* node目录和collection目录下脚本提供“主机”、“监控中心”、“作业管理”中主机和作业信息来源,若某些字段采集不到,则“主机”、“监控中心”、“作业管理”中该字段对应信息将无法显示。
+
+4. 使用PuTTY工具,以root用户登录Donau Portal节点(若为HA场景,需登录主备Donau Portal节点)。参考[步骤2](#step2)[步骤3](#step3)修改集成脚本。
+
+#### 注意事项
+
+1. 当前脚本适配是针对HPC_22.0.0之后的版本;
+2. 严格按照操作步骤执行,否则可能会导致脚本执行失败
#### 参与贡献