Add channel update script
parent
d624e64b10
commit
cbe0f0010e
|
@ -0,0 +1,335 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
# Fetch a config block and update it. The new channel cfg section will be generated by $CAL_NEW_CFG_PY
|
||||||
|
|
||||||
|
# Usage: ./script channelListFile ordererURL mspId mspPath
|
||||||
|
# For testing a single channel, can use as: ./script channel ordererURL mspId mspPath
|
||||||
|
|
||||||
|
SYS_CHANNEL_NAME="testchainid" # default system channel name
|
||||||
|
CAL_NEW_CFG_PY="calc-new-channel-cfg.py" # script to calculate the new channel cfg section
|
||||||
|
|
||||||
|
# use configtxlator to decode pb to json
|
||||||
|
# Usage: configtxlatorDecode msgType input output
|
||||||
|
configtxlatorDecode() {
|
||||||
|
msgType=$1
|
||||||
|
input=$2
|
||||||
|
output=$3
|
||||||
|
|
||||||
|
if [ ! -f "$input" ]; then
|
||||||
|
echo "configDecode: input file not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v configtxlator >/dev/null 2>&1; then
|
||||||
|
echo "configtxlator could not be found, please install it first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Decode $input --> $output using type $msgType"
|
||||||
|
configtxlator proto_decode \
|
||||||
|
--type="${msgType}" \
|
||||||
|
--input="${input}" \
|
||||||
|
--output="${output}"
|
||||||
|
|
||||||
|
[ $? -ne 0 ] && echo "Failed to decode config section from pb"
|
||||||
|
}
|
||||||
|
|
||||||
|
# use configtxlator to encode json to pb
|
||||||
|
# Usage: configtxlatorEncode msgType input output
|
||||||
|
configtxlatorEncode() {
|
||||||
|
msgType=$1
|
||||||
|
input=$2
|
||||||
|
output=$3
|
||||||
|
|
||||||
|
if [ ! -f "$input" ]; then
|
||||||
|
echo "configEncode: input file not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v configtxlator >/dev/null 2>&1; then
|
||||||
|
echo "configtxlator could not be found, please install it first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Config Encode $input --> $output using type $msgType"
|
||||||
|
configtxlator proto_encode \
|
||||||
|
--type="${msgType}" \
|
||||||
|
--input="${input}" \
|
||||||
|
--output="${output}"
|
||||||
|
|
||||||
|
[ $? -eq 0 ] || echo "Failed to encode config section to pb"
|
||||||
|
}
|
||||||
|
|
||||||
|
# compute diff between two pb
|
||||||
|
# Usage: configtxlatorCompare channel origin_pb updated_pb output_pb
|
||||||
|
configtxlatorCompare() {
|
||||||
|
channel=$1
|
||||||
|
origin=$2
|
||||||
|
updated=$3
|
||||||
|
output=$4
|
||||||
|
|
||||||
|
echo "Config Compare $origin vs $updated > ${output} in channel $channel"
|
||||||
|
if [ ! -f "$origin" ] || [ ! -f "$updated" ]; then
|
||||||
|
echo "input file not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
configtxlator compute_update \
|
||||||
|
--original="${origin}" \
|
||||||
|
--updated="${updated}" \
|
||||||
|
--channel_id="${channel}" \
|
||||||
|
--output="${output}"
|
||||||
|
|
||||||
|
[ $? -eq 0 ] || echo "Failed to compute config update"
|
||||||
|
}
|
||||||
|
|
||||||
|
# fetchConfigBlock fetch the latest config block, and parse the config section into channelCfgJson
|
||||||
|
# Usage: fetchConfigBlock channel mspId mspPath ordererURL ordererTLSRoot channelCfgJson
|
||||||
|
fetchConfigBlock() {
|
||||||
|
if [ $# -lt 6 ]; then
|
||||||
|
echo "Not enough argument supplied"
|
||||||
|
echo "$(basename $0) channel channel_config_block_cfg.json update_tx.pb"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
channel=$1
|
||||||
|
mspId=$2
|
||||||
|
mspPath=$3
|
||||||
|
ordererURL=$4
|
||||||
|
ordererTLSRoot=$5
|
||||||
|
channelCfgJson=$6
|
||||||
|
config_block=${channel}_config.block
|
||||||
|
PAYLOAD_CFG_PATH=".data.data[0].payload.data.config"
|
||||||
|
|
||||||
|
export CORE_PEER_LOCALMSPID=${mspId}
|
||||||
|
export CORE_PEER_MSPCONFIGPATH=${mspPath}
|
||||||
|
export CORE_PEER_TLS_ROOTCERT_FILE=${ordererTLSRoot}
|
||||||
|
|
||||||
|
peer channel fetch config "${config_block}" \
|
||||||
|
-c "${channel}" \
|
||||||
|
-o "${ordererURL}" \
|
||||||
|
--tls \
|
||||||
|
--cafile "${ordererTLSRoot}"
|
||||||
|
|
||||||
|
echo "[${channel}] Decode config block into ${channel}_config.block.json"
|
||||||
|
configtxlatorDecode "common.Block" "${channel}_config.block" "${channel}_config_block.json"
|
||||||
|
|
||||||
|
echo "[${channel}] Export the config section ${PAYLOAD_CFG_PATH} from ${channel}_config_block.json into ${channelCfgJson}"
|
||||||
|
jq "${PAYLOAD_CFG_PATH}" "${channel}_config_block.json" >"${channelCfgJson}"
|
||||||
|
jq . "${channelCfgJson}" >/dev/null
|
||||||
|
[ $? -ne 0 ] && {
|
||||||
|
echo "${channel}_config_block_cfg.json is invalid"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate a new config section json from old config section, including the channel cfg updates
|
||||||
|
# Usage genNewCfgSection channel old_config_json new_config_json
|
||||||
|
calcNewCfgSection() {
|
||||||
|
if [ $# -lt 3 ]; then
|
||||||
|
echo "Not enough argument supplied"
|
||||||
|
echo "$(basename $0) channel channel_config_block_cfg.json channel_config_block_cfg_new.json"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
channel=$1
|
||||||
|
oldCfgJson=$2 # ${channel}_config_block_cfg.json
|
||||||
|
newCfgJson=$3 # ${channel}_config_block_cfg_new.json
|
||||||
|
|
||||||
|
# TODO: here we calculate the new channel cfg json using python
|
||||||
|
if [ "${channel}" = "${SYS_CHANNEL_NAME}" ]; then
|
||||||
|
python3 $CAL_NEW_CFG_PY --sys --input $oldCfgJson --output $newCfgJson
|
||||||
|
else
|
||||||
|
python3 $CAL_NEW_CFG_PY --input $oldCfgJson --output $newCfgJson
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq . "${newCfgJson}" >/dev/null
|
||||||
|
[ $? -ne 0 ] && {
|
||||||
|
echo "${newCfgJson} is invalid"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate a channel update transaction based on existing config block
|
||||||
|
# Usage genUpdateTx channel old_config_json update_tx_pb
|
||||||
|
genUpdateTx() {
|
||||||
|
if [ $# -lt 3 ]; then
|
||||||
|
echo "Not enough argument supplied"
|
||||||
|
echo "$(basename $0) channel channel_config_block_cfg.json update_tx.pb"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
channel=$1
|
||||||
|
oldCfgJson=$2 # ${channel}_config_block_cfg.json
|
||||||
|
oldCfgPb=${channel}_config_block_cfg.pb
|
||||||
|
newCfgJson=${channel}_config_block_cfg_new.json
|
||||||
|
newCfgPb=${channel}_config_block_cfg_new.pb
|
||||||
|
deltaCfgPb=${channel}_config_block_cfg_delta.pb
|
||||||
|
deltaCfgJson=${channel}_config_block_cfg_delta.json
|
||||||
|
deltaCfgEnvJson=${channel}_config_block_cfg_delta_env.json
|
||||||
|
deltaCfgEnvPb=${3:-${channel}_config_block_cfg_delta_env.pb}
|
||||||
|
|
||||||
|
echo "[$channel] Start generating a channel update tx..."
|
||||||
|
|
||||||
|
echo "[$channel] Modify channel cfg section: ${oldCfgJson}-->${newCfgJson}"
|
||||||
|
calcNewCfgSection "${channel}" "${oldCfgJson}" "${newCfgJson}"
|
||||||
|
|
||||||
|
echo "[$channel] Convert channel cfg section json into pb files ..."
|
||||||
|
configtxlatorEncode "common.Config" "${oldCfgJson}" "${oldCfgPb}"
|
||||||
|
configtxlatorEncode "common.Config" "${newCfgJson}" "${newCfgPb}"
|
||||||
|
|
||||||
|
echo "[$channel] Calculate the config delta between pb files: ${oldCfgPb}+${newCfgPb}-->${deltaCfgPb}"
|
||||||
|
configtxlatorCompare "${channel}" "${oldCfgPb}" "${newCfgPb}" "${deltaCfgPb}"
|
||||||
|
|
||||||
|
echo "[$channel] Decode the config delta pb into json: ${deltaCfgPb}-->${deltaCfgJson}"
|
||||||
|
configtxlatorDecode "common.ConfigUpdate" "${deltaCfgPb}" "${deltaCfgJson}"
|
||||||
|
jq . "${deltaCfgJson}" >/dev/null
|
||||||
|
[ $? -ne 0 ] && {
|
||||||
|
echo "${deltaCfgJson} is invalid"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "[$channel] Wrap the delta config section as an envelope: ${deltaCfgJson}-->${deltaCfgEnvJson}"
|
||||||
|
echo '{"payload":{"header":{"channel_header":{"channel_id":"'"$channel"'", "type":2}},"data":{"config_update":'$(cat ${deltaCfgJson})'}}}' | jq . >"${deltaCfgEnvJson}"
|
||||||
|
|
||||||
|
echo "[$channel] Encode the delta config update envelope into pb: ${deltaCfgEnvJson}-->${deltaCfgPb}"
|
||||||
|
configtxlatorEncode "common.Envelope" "${deltaCfgEnvJson}" "${deltaCfgEnvPb}"
|
||||||
|
|
||||||
|
echo "[$channel] Channel update tx is generated as ${deltaCfgPb}, now ready to sign and send the channel update tx"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sign a channel update transaction
|
||||||
|
# Usage: signUpdateTx mspId mspPath tx
|
||||||
|
signUpdateTx() {
|
||||||
|
if [ $# -lt 3 ]; then
|
||||||
|
echo "Not enough argument supplied"
|
||||||
|
echo "$(basename $0) mspId mspPath tx"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mspId=$1
|
||||||
|
mspPath=$2
|
||||||
|
tx=$3
|
||||||
|
|
||||||
|
echo "Sign channel config tx $tx by $mspId"
|
||||||
|
[ -f "${tx}" ] || {
|
||||||
|
echo "${tx} not exist"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
export CORE_PEER_LOCALMSPID=${mspId}
|
||||||
|
export CORE_PEER_MSPCONFIGPATH=${mspPath}
|
||||||
|
|
||||||
|
peer channel signconfigtx -f "${tx}" >log.txt 2>&1
|
||||||
|
rc=$?
|
||||||
|
[ $rc -ne 0 ] && cat log.txt
|
||||||
|
if [ $rc -ne 0 ]; then
|
||||||
|
echo "Sign channel config tx $tx by $mspId failed"
|
||||||
|
else
|
||||||
|
echo "Sign channel config tx $tx by $mspId is successful"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send a channel update transaction
|
||||||
|
# Usage: sendUpdateTx "${channel}" "${mspId}" "${mspPath}" "${ordererURL}" "${ordererTLSRoot}" "${updateTx}"
|
||||||
|
sendUpdateTx() {
|
||||||
|
if [ $# -lt 6 ]; then
|
||||||
|
echo "Not enough argument supplied"
|
||||||
|
echo "$(basename $0) channel mspId mspPath ordererURL ordererTLSRoot updateTx"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
channel=$1
|
||||||
|
mspId=$2
|
||||||
|
mspPath=$3
|
||||||
|
ordererURL=$4
|
||||||
|
ordererTLSRoot=$5
|
||||||
|
tx=$6
|
||||||
|
|
||||||
|
export CORE_PEER_LOCALMSPID=${mspId}
|
||||||
|
export CORE_PEER_MSPCONFIGPATH=${mspPath}
|
||||||
|
export CORE_PEER_TLS_ROOTCERT_FILE=${ordererTLSRoot}
|
||||||
|
|
||||||
|
echo "[${channel}] Send the channel update tx by $mspId $mspPath to $ordererURL"
|
||||||
|
peer channel update \
|
||||||
|
-c "${channel}" \
|
||||||
|
-o "${ordererURL}" \
|
||||||
|
-f "${tx}" \
|
||||||
|
--tls \
|
||||||
|
--cafile "${ordererTLSRoot}" \
|
||||||
|
>log.txt 2>&1
|
||||||
|
|
||||||
|
[ $? -ne 0 ] && { echo "[${channel}] Failed to send channel update tx to OSN" && cat log.txt; }
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Entrance function, will call other functions
|
||||||
|
# Update a single channel's config, need to be founder's admin
|
||||||
|
# Usage: updateChannel channel, ordererURL, mspId, mspPath
|
||||||
|
UpdateChannel() {
|
||||||
|
if [ $# -lt 3 ]; then
|
||||||
|
echo "Not enough argument supplied"
|
||||||
|
echo "$(basename $0) channel ordererURL mspId mspPath=${PWD}/msp-mspId"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
channel=$1
|
||||||
|
ordererURL=$2
|
||||||
|
mspId=$3
|
||||||
|
mspPath=${4:-${PWD}/msp-${mspId}} # Suppose the msp path named as msp-${msp_id}
|
||||||
|
ordererTLSRoot=${mspPath}/tlscacerts/tlsca.cert
|
||||||
|
channelCfgJson=${channel}_config_block_cfg.json
|
||||||
|
updateTx="${channel}_config_block_cfg_delta_env.pb"
|
||||||
|
|
||||||
|
export FABRIC_LOGGING_SPEC="debug"
|
||||||
|
#export CORE_PEER_LOCALMSPID=${mspId}
|
||||||
|
#export CORE_PEER_MSPCONFIGPATH=${mspPath}
|
||||||
|
#export CORE_PEER_TLS_ROOTCERT_FILE=${ordererTLSRoot}
|
||||||
|
#export CORE_PEER_TLS_ENABLED=true # Let client use TLS connection when connecting to peer
|
||||||
|
|
||||||
|
echo "[${channel}] Fetch config block from ${ordererURL} and decode the cfg section into ${channelCfgJson}"
|
||||||
|
fetchConfigBlock "${channel}" "${mspId}" "${mspPath}" "${ordererURL}" "${ordererTLSRoot}" "$channelCfgJson"
|
||||||
|
[ $? -ne 0 ] && { echo "[${channel}] Failed to fetch latest config from OSN" && exit 1; }
|
||||||
|
|
||||||
|
echo "[${channel}] Generate the channel update tx"
|
||||||
|
genUpdateTx "${channel}" "${channelCfgJson}" "${updateTx}"
|
||||||
|
[ $? -ne 0 ] && { echo "[${channel}] Failed to generate new channel config" && exit 1; }
|
||||||
|
|
||||||
|
# TODO: do we support multiple msps?
|
||||||
|
echo "[${channel}] Sign the channel update tx ${updateTx} by $mspId $mspPath"
|
||||||
|
signUpdateTx "${mspId}" "${mspPath}" "${updateTx}"
|
||||||
|
[ $? -ne 0 ] && { echo "[${channel}] Failed to sign the channel config update tx" && exit 1; }
|
||||||
|
|
||||||
|
echo "[${channel}] Send the channel update tx ${updateTx} by $mspId $mspPath to ${ordererTLSRoot}"
|
||||||
|
sendUpdateTx "${channel}" "${mspId}" "${mspPath}" "${ordererURL}" "${ordererTLSRoot}" "${updateTx}"
|
||||||
|
[ $? -ne 0 ] && { echo "[${channel}] Failed to send the channel update tx to ${ordererURL}" && exit 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $# -lt 4 ]; then
|
||||||
|
echo "Not enough argument supplied"
|
||||||
|
echo "$(basename $0) channelListFile ordererURL mspId mspPath"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
channelListFile=$1
|
||||||
|
ordererURL=$2
|
||||||
|
mspId=$3
|
||||||
|
mspPath=$4 # the msp path
|
||||||
|
|
||||||
|
if [ -f ${channelListFile} ]; then
|
||||||
|
i=0
|
||||||
|
while read channel; do
|
||||||
|
((i++))
|
||||||
|
echo "Will process channel[$i]=$channel"
|
||||||
|
if [[ $channel =~ ^#.* ]]; then
|
||||||
|
echo "channel[$i]=$channel is ignored"
|
||||||
|
else
|
||||||
|
UpdateChannel "$channel" "${@:2}"
|
||||||
|
fi
|
||||||
|
done <${channelListFile}
|
||||||
|
else
|
||||||
|
# for test purpose only
|
||||||
|
UpdateChannel "$@" # channel, ordererURL, mspid, mspPath
|
||||||
|
fi
|
|
@ -61,12 +61,12 @@ fi
|
||||||
main() {
|
main() {
|
||||||
if [ $# -lt 3 ]; then
|
if [ $# -lt 3 ]; then
|
||||||
echo "Not enough argument supplied"
|
echo "Not enough argument supplied"
|
||||||
echo "$(basename $0) mspId channel ordererURL mspPath=${PWD}/msp-mspId"
|
echo "$(basename $0) channel ordererURL mspId mspPath=${PWD}/msp-mspId"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
local mspId=$1
|
local channel=$1
|
||||||
local channel=$2
|
local ordererURL=$2
|
||||||
local ordererURL=$3
|
local mspId=$3
|
||||||
local mspPath=${4:-${PWD}/msp-${mspId}} # Suppose the local msp path named as msp-${msp_id}
|
local mspPath=${4:-${PWD}/msp-${mspId}} # Suppose the local msp path named as msp-${msp_id}
|
||||||
|
|
||||||
export FABRIC_LOGGING_SPEC="debug"
|
export FABRIC_LOGGING_SPEC="debug"
|
||||||
|
|
|
@ -81,7 +81,7 @@ def process(directory):
|
||||||
f_read.close()
|
f_read.close()
|
||||||
f_write.close()
|
f_write.close()
|
||||||
else:
|
else:
|
||||||
print("Ignore non-json file {}".format(f))
|
print("Ignore non .block.json file {}".format(f))
|
||||||
|
|
||||||
|
|
||||||
# Usage python json_flatter.py [path_containing_json_files]
|
# Usage python json_flatter.py [path_containing_json_files]
|
||||||
|
|
|
@ -1044,7 +1044,7 @@ configtxlatorEncode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
# configtxlator decode pb to json
|
# configtxlator decode pb to json
|
||||||
# Usage: configtxlatorEncode msgType input output
|
# Usage: configtxlatorDecode msgType input output
|
||||||
configtxlatorDecode() {
|
configtxlatorDecode() {
|
||||||
local msgType=$1
|
local msgType=$1
|
||||||
local input=$2
|
local input=$2
|
||||||
|
|
|
@ -20,11 +20,11 @@ def decode_if_b64(raw):
|
||||||
except binascii.Error:
|
except binascii.Error:
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
# if success: # result_bytes = b'xxxx\xx'
|
#if success: # result_bytes = b'xxxx\xx'
|
||||||
# print('===================Start==================================')
|
#print('===================Start==================================')
|
||||||
# print(raw)
|
#print(raw)
|
||||||
# print(result)
|
#print(result)
|
||||||
# print('=====================End===================================')
|
#print('=====================End===================================')
|
||||||
return success, result
|
return success, result
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ def check_tree(tree, prefix, f_write):
|
||||||
else: # leaf
|
else: # leaf
|
||||||
result = v
|
result = v
|
||||||
if 'cert' in k or 'id_bytes' in k or 'value' in k and 'hash' not in k:
|
if 'cert' in k or 'id_bytes' in k or 'value' in k and 'hash' not in k:
|
||||||
# print(prefix_path)
|
#print(prefix_path)
|
||||||
success, result = decode_if_b64(v)
|
success, result = decode_if_b64(v)
|
||||||
if success:
|
if success:
|
||||||
result = "b64({})".format(result)
|
result = "b64({})".format(result)
|
||||||
|
@ -76,13 +76,12 @@ def process(directory):
|
||||||
if f.endswith(".block.json"):
|
if f.endswith(".block.json"):
|
||||||
file_name = os.path.join(json_dir, f)
|
file_name = os.path.join(json_dir, f)
|
||||||
f_read = open(file=file_name, mode="r", encoding='utf-8')
|
f_read = open(file=file_name, mode="r", encoding='utf-8')
|
||||||
f_write = open(file=file_name + "-flat.json", mode="w",
|
f_write = open(file=file_name+"-flat.json", mode="w", encoding='utf-8')
|
||||||
encoding='utf-8')
|
|
||||||
check_tree(json.load(f_read), "", f_write)
|
check_tree(json.load(f_read), "", f_write)
|
||||||
f_read.close()
|
f_read.close()
|
||||||
f_write.close()
|
f_write.close()
|
||||||
else:
|
else:
|
||||||
print("Ignore non-json file {}".format(f))
|
print("Ignore non .block.json file {}".format(f))
|
||||||
|
|
||||||
|
|
||||||
# Usage python json_flatter.py [path_containing_json_files]
|
# Usage python json_flatter.py [path_containing_json_files]
|
||||||
|
|
Loading…
Reference in New Issue