From 66df02497c900dd1a74fdc218f9a81b690a40d47 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Mon, 9 Jul 2018 12:46:14 -0700 Subject: ZTS: clean_mirror and scrub_mirror cleanup Remove the dependency on partitionable devices for the clean_mirror and scrub_mirror test cases. This allows for the setup and cleanup of the test cases to be simplified by removing the need for complex partitioning. This change also resolves a issue where the clean_mirror devices were not being properly damaged since the device name was not a full path. The result being loopX files were being left in the top level test_results directory. Signed-off-by: Brian Behlendorf Closes #7434 Closes #7690 --- tests/test-runner/bin/zts-report.py | 2 - .../clean_mirror/clean_mirror_common.kshlib | 13 ++-- .../tests/functional/clean_mirror/cleanup.ksh | 18 +---- .../tests/functional/clean_mirror/default.cfg | 78 ++-------------------- .../tests/functional/clean_mirror/setup.ksh | 15 +---- .../tests/functional/scrub_mirror/cleanup.ksh | 17 +---- .../tests/functional/scrub_mirror/default.cfg | 78 ++-------------------- .../scrub_mirror/scrub_mirror_001_pos.ksh | 2 +- .../scrub_mirror/scrub_mirror_002_pos.ksh | 2 +- .../scrub_mirror/scrub_mirror_003_pos.ksh | 2 +- .../scrub_mirror/scrub_mirror_004_pos.ksh | 2 +- .../scrub_mirror/scrub_mirror_common.kshlib | 16 ++--- .../tests/functional/scrub_mirror/setup.ksh | 15 +---- 13 files changed, 32 insertions(+), 228 deletions(-) diff --git a/tests/test-runner/bin/zts-report.py b/tests/test-runner/bin/zts-report.py index fef9b53ec..20afad5d7 100755 --- a/tests/test-runner/bin/zts-report.py +++ b/tests/test-runner/bin/zts-report.py @@ -202,7 +202,6 @@ maybe = { 'cache/setup': ['SKIP', disk_reason], 'cache/cache_010_neg': ['FAIL', known_reason], 'chattr/setup': ['SKIP', exec_reason], - 'clean_mirror/setup': ['SKIP', disk_reason], 'cli_root/zdb/zdb_006_pos': ['FAIL', known_reason], 'cli_root/zfs_get/zfs_get_004_pos': ['FAIL', known_reason], 'cli_root/zfs_get/zfs_get_009_pos': ['SKIP', '5479'], @@ -251,7 +250,6 @@ maybe = { 'rsend/rsend_021_pos': ['FAIL', '6446'], 'rsend/rsend_024_pos': ['FAIL', '5665'], 'rsend/send-c_volume': ['FAIL', '6087'], - 'scrub_mirror/setup': ['SKIP', disk_reason], 'snapshot/clone_001_pos': ['FAIL', known_reason], 'snapused/snapused_004_pos': ['FAIL', '5513'], 'tmpfile/setup': ['SKIP', tmpfile_reason], diff --git a/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib b/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib index 3d371e614..cf1d77d9c 100644 --- a/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib +++ b/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib @@ -32,12 +32,6 @@ . $STF_SUITE/include/libtest.shlib . $STF_SUITE/tests/functional/clean_mirror/default.cfg -# Most of the code related to the clearing of mirrors is duplicated in all -# the test cases below this directory, barring a few minor changes -# involving the device to be affected and the 'object' to use to mangle -# the contents of the mirror. -# This code is sourced into each of these test cases. - function overwrite_verify_mirror { typeset AFFECTED_DEVICE=$1 @@ -56,7 +50,7 @@ function overwrite_verify_mirror (( atfile = atfile + 1 )) done - # dd the primary side of the mirror + # dd the affected side of the mirror log_must dd if=$OVERWRITING_DEVICE of=$AFFECTED_DEVICE \ seek=8 bs=$DD_BLOCK count=$(( DD_COUNT - 128 )) conv=notrunc @@ -66,7 +60,7 @@ function overwrite_verify_mirror # Flush out the cache so that we ensure we're reading from disk. # log_must zpool export $TESTPOOL - log_must zpool import $TESTPOOL + log_must zpool import -d $SIDE_DIR $TESTPOOL typeset -i failedcount=0 while (( atfile < FILE_COUNT )); do @@ -84,5 +78,6 @@ function overwrite_verify_mirror "have the same checksum before and after." fi - sync_pool $TESTPOOL + log_must zpool scrub $TESTPOOL + log_must wait_scrubbed $TESTPOOL } diff --git a/tests/zfs-tests/tests/functional/clean_mirror/cleanup.ksh b/tests/zfs-tests/tests/functional/clean_mirror/cleanup.ksh index fb0db312e..d5614bef0 100755 --- a/tests/zfs-tests/tests/functional/clean_mirror/cleanup.ksh +++ b/tests/zfs-tests/tests/functional/clean_mirror/cleanup.ksh @@ -34,22 +34,8 @@ verify_runnable "global" -df -F zfs -h | grep "$TESTFS " >/dev/null -[[ $? == 0 ]] && log_must zfs umount -f $TESTDIR destroy_pool $TESTPOOL - -if ( is_mpath_device $MIRROR_PRIMARY || is_loop_device $MIRROR_SECONDARY); then - parted $DEV_DSKDIR/$MIRROR_PRIMARY -s rm 1 -fi -if ( is_mpath_device $MIRROR_SECONDARY || is_loop_device $MIRROR_SECONDARY); then - parted $DEV_DSKDIR/$MIRROR_SECONDARY -s rm 1 -fi -# recreate and destroy a zpool over the disks to restore the partitions to -# normal -if [[ -n $SINGLE_DISK ]]; then - log_must cleanup_devices $MIRROR_PRIMARY -else - log_must cleanup_devices $MIRROR_PRIMARY $MIRROR_SECONDARY -fi +log_must rm -f $SIDE_PRIMARY $SIDE_SECONDARY +log_must rmdir $SIDE_DIR log_pass diff --git a/tests/zfs-tests/tests/functional/clean_mirror/default.cfg b/tests/zfs-tests/tests/functional/clean_mirror/default.cfg index d02d2b8bd..dfe7f1d0b 100644 --- a/tests/zfs-tests/tests/functional/clean_mirror/default.cfg +++ b/tests/zfs-tests/tests/functional/clean_mirror/default.cfg @@ -28,80 +28,10 @@ # Copyright (c) 2013 by Delphix. All rights reserved. # -. $STF_SUITE/include/libtest.shlib - -typeset -i NUMBER_OF_DISKS=0 -for i in $DISKS; do - [[ -n $MIRROR_PRIMARY ]] && MIRROR_SECONDARY=$i - [[ -z $MIRROR_PRIMARY ]] && MIRROR_PRIMARY=$i -done - -if [[ -z $MIRROR_SECONDARY ]]; then - # We need to repartition the single disk to two slices - SINGLE_DISK=$MIRROR_PRIMARY - MIRROR_SECONDARY=$MIRROR_PRIMARY - SIDE_PRIMARY_PART=0 - SIDE_SECONDARY_PART=1 - - if is_linux; then - if is_mpath_device $SINGLE_DISK; then - export DEV_DSKDIR=$DEV_MPATHDIR - else - export DEV_DSKDIR=$DEV_RDSKDIR - fi - if ( is_mpath_device $SINGLE_DISK ) && [[ -z $(echo $SINGLE_DISK | awk 'substr($1,18,1)\ - ~ /^[[:digit:]]+$/') ]] || ( is_real_device $SINGLE_DISK ); then - SIDE_PRIMARY=${SINGLE_DISK}1 - SIDE_SECONDARY=${SINGLE_DISK}2 - elif ( is_mpath_device $SINGLE_DISK || is_loop_device $SINGLE_DISK ); then - SIDE_PRIMARY=${SINGLE_DISK}p1 - SIDE_SECONDARY=${SINGLE_DISK}p2 - else - log_fail "$SINGLE_DISK not supported for partitioning." - fi - else - export DEV_DSKDIR="/dev" - SIDE_PRIMARY=${SINGLE_DISK}s${SIDE_PRIMARY_PART} - SIDE_SECONDARY=${SINGLE_DISK}s${SIDE_SECONDARY_PART} - fi -else - SIDE_PRIMARY_PART=0 - SIDE_SECONDARY_PART=0 - if is_linux; then - if is_mpath_device $MIRROR_PRIMARY; then - export DEV_DSKDIR=$DEV_MPATHDIR - else - export DEV_DSKDIR=$DEV_RDSKDIR - fi - if ( is_mpath_device $MIRROR_PRIMARY ) && [[ -z $(echo $MIRROR_PRIMARY | awk 'substr($1,18,1)\ - ~ /^[[:digit:]]+$/') ]] || ( is_real_device $MIRROR_PRIMARY ); then - SIDE_PRIMARY=${MIRROR_PRIMARY}1 - elif ( is_mpath_device $MIRROR_PRIMARY || is_loop_device $MIRROR_PRIMARY ); then - SIDE_PRIMARY=${MIRROR_PRIMARY}p1 - else - log_fail "$MIRROR_PRIMARY not supported for partitioning." - fi - if ( is_mpath_device $MIRROR_SECONDARY ) && [[ -z $(echo $MIRROR_SECONDARY | awk 'substr($1,18,1)\ - ~ /^[[:digit:]]+$/') ]] || ( is_real_device $MIRROR_SECONDARY ); then - SIDE_SECONDARY=${MIRROR_SECONDARY}1 - elif ( is_mpath_device $MIRROR_SECONDARY || is_loop_device $MIRROR_SECONDARY ); then - SIDE_SECONDARY=${MIRROR_SECONDARY}p1 - else - log_fail "$MIRROR_SECONDARY not supported for partitioning." - fi - - else - export DEV_DSKDIR="/dev" - SIDE_PRIMARY=${MIRROR_PRIMARY}s${SIDE_PRIMARY_PART} - SIDE_SECONDARY=${MIRROR_SECONDARY}s${SIDE_SECONDARY_PART} - fi -fi - -export MIRROR_PRIMARY MIRROR_SECONDARY SINGLE_DISK SIDE_PRIMARY SIDE_SECONDARY - +export SIDE_DIR="${TEST_BASE_DIR}/clean_mirror" +export SIDE_PRIMARY="${SIDE_DIR}/dev1" +export SIDE_SECONDARY="${SIDE_DIR}/dev2" export FILE_COUNT=10 export FILE_SIZE=$(( 1024 * 1024 )) -export MIRROR_MEGS=100 -export MIRROR_SIZE=${MIRROR_MEGS}m # default mirror size export DD_BLOCK=$(( 64 * 1024 )) -export DD_COUNT=$(( MIRROR_MEGS * 1024 * 1024 / DD_BLOCK )) +export DD_COUNT=$(( MINVDEVSIZE / DD_BLOCK )) diff --git a/tests/zfs-tests/tests/functional/clean_mirror/setup.ksh b/tests/zfs-tests/tests/functional/clean_mirror/setup.ksh index 2d17bf9cb..0024f284d 100755 --- a/tests/zfs-tests/tests/functional/clean_mirror/setup.ksh +++ b/tests/zfs-tests/tests/functional/clean_mirror/setup.ksh @@ -34,19 +34,8 @@ verify_runnable "global" -if ! is_physical_device $DISKS; then - log_unsupported "This directory cannot be run on raw files." -fi - -if [[ -n $SINGLE_DISK ]]; then - log_note "Partitioning a single disk ($SINGLE_DISK)" -else - log_note "Partitioning disks ($MIRROR_PRIMARY $MIRROR_SECONDARY)" -fi - -log_must set_partition $SIDE_PRIMARY_PART "" $MIRROR_SIZE $MIRROR_PRIMARY -log_must set_partition $SIDE_SECONDARY_PART "" $MIRROR_SIZE $MIRROR_SECONDARY - +log_must mkdir -p $SIDE_DIR +log_must truncate -s $MINVDEVSIZE $SIDE_PRIMARY $SIDE_SECONDARY default_mirror_setup $SIDE_PRIMARY $SIDE_SECONDARY log_pass diff --git a/tests/zfs-tests/tests/functional/scrub_mirror/cleanup.ksh b/tests/zfs-tests/tests/functional/scrub_mirror/cleanup.ksh index 562de7de1..92e58996a 100755 --- a/tests/zfs-tests/tests/functional/scrub_mirror/cleanup.ksh +++ b/tests/zfs-tests/tests/functional/scrub_mirror/cleanup.ksh @@ -35,21 +35,8 @@ verify_runnable "global" -df -F zfs -h | grep "$TESTFS " >/dev/null -[[ $? == 0 ]] && log_must zfs umount -f $TESTDIR destroy_pool $TESTPOOL - -DISK=${DISKS%% *} -if is_mpath_device $DISK; then - delete_partitions -fi - -# recreate and destroy a zpool over the disks to restore the partitions to -# normal -if [[ -n $SINGLE_DISK ]]; then - log_must cleanup_devices $MIRROR_PRIMARY -else - log_must cleanup_devices $MIRROR_PRIMARY $MIRROR_SECONDARY -fi +log_must rm -f $SIDE_PRIMARY $SIDE_SECONDARY +log_must rmdir $SIDE_DIR log_pass diff --git a/tests/zfs-tests/tests/functional/scrub_mirror/default.cfg b/tests/zfs-tests/tests/functional/scrub_mirror/default.cfg index 15de76296..01c90e58f 100644 --- a/tests/zfs-tests/tests/functional/scrub_mirror/default.cfg +++ b/tests/zfs-tests/tests/functional/scrub_mirror/default.cfg @@ -28,80 +28,10 @@ # Copyright (c) 2013 by Delphix. All rights reserved. # -export DISKSARRAY=$DISKS -export DISK_ARRAY_NUM=$(echo ${DISKS} | nawk '{print NF}') - -typeset -i NUMBER_OF_DISKS=0 -for i in $DISKS; do - [[ -n $MIRROR_PRIMARY ]] && MIRROR_SECONDARY=$i - [[ -z $MIRROR_PRIMARY ]] && MIRROR_PRIMARY=$i -done - -if [[ -z $MIRROR_SECONDARY ]]; then - # We need to repartition the single disk to two slices - SINGLE_DISK=$MIRROR_PRIMARY - MIRROR_SECONDARY=$MIRROR_PRIMARY - SIDE_PRIMARY_PART=0 - SIDE_SECONDARY_PART=1 - if is_linux; then - if is_mpath_device $MIRROR_PRIMARY; then - export DEV_DSKDIR=$DEV_MPATHDIR - else - export DEV_DSKDIR=$DEV_RDSKDIR - fi - if ( is_mpath_device $SINGLE_DISK ) && [[ -z $(echo $SINGLE_DISK | awk 'substr($1,18,1)\ - ~ /^[[:digit:]]+$/') ]] || ( is_real_device $SINGLE_DISK ); then - SIDE_PRIMARY=${SINGLE_DISK}1 - SIDE_SECONDARY=${SINGLE_DISK}2 - elif ( is_mpath_device $SINGLE_DISK || is_loop_device $SINGLE_DISK ); then - SIDE_PRIMARY=${SINGLE_DISK}p1 - SIDE_SECONDARY=${SINGLE_DISK}p2 - else - log_fail "$SINGLE_DISK not supported for partitioning." - fi - else - export DEV_DSKDIR="/dev" - SIDE_PRIMARY=${SINGLE_DISK}s${SIDE_PRIMARY_PART} - SIDE_SECONDARY=${SINGLE_DISK}s${SIDE_SECONDARY_PART} - fi -else - SIDE_PRIMARY_PART=0 - SIDE_SECONDARY_PART=0 - if is_linux; then - if is_mpath_device $MIRROR_PRIMARY; then - export DEV_DSKDIR=$DEV_MPATHDIR - else - export DEV_DSKDIR=$DEV_RDSKDIR - fi - if ( is_mpath_device $MIRROR_PRIMARY ) && [[ -z $(echo $MIRROR_PRIMARY | awk 'substr($1,18,1)\ - ~ /^[[:digit:]]+$/') ]] || ( is_real_device $MIRROR_PRIMARY ); then - SIDE_PRIMARY=${MIRROR_PRIMARY}1 - elif ( is_mpath_device $MIRROR_PRIMARY || is_loop_device $MIRROR_PRIMARY ); then - SIDE_PRIMARY=${MIRROR_PRIMARY}p1 - else - log_fail "$MIRROR_PRIMARY not supported for partitioning." - fi - if ( is_mpath_device $MIRROR_SECONDARY ) && [[ -z $(echo $MIRROR_SECONDARY | awk 'substr($1,18,1)\ - ~ /^[[:digit:]]+$/') ]] || ( is_real_device $MIRROR_SECONDARY ); then - SIDE_SECONDARY=${MIRROR_SECONDARY}1 - elif ( is_mpath_device $MIRROR_SECONDARY || is_loop_device $MIRROR_SECONDARY ); then - SIDE_SECONDARY=${MIRROR_SECONDARY}p1 - else - log_fail "$MIRROR_SECONDARY not supported for partitioning." - fi - else - export DEV_DSKDIR="/dev" - SIDE_PRIMARY=${MIRROR_PRIMARY}s${SIDE_PRIMARY_PART} - SIDE_SECONDARY=${MIRROR_SECONDARY}s${SIDE_SECONDARY_PART} - fi -fi - - -export MIRROR_PRIMARY MIRROR_SECONDARY SINGLE_DISK SIDE_PRIMARY SIDE_SECONDARY - +export SIDE_DIR="${TEST_BASE_DIR}/scrub_mirror" +export SIDE_PRIMARY="${SIDE_DIR}/dev1" +export SIDE_SECONDARY="${SIDE_DIR}/dev2" export FILE_COUNT=10 export FILE_SIZE=$(( 1024 * 1024 )) -export MIRROR_MEGS=100 -export MIRROR_SIZE=${MIRROR_MEGS}m # default mirror size export DD_BLOCK=$(( 64 * 1024 )) -export DD_COUNT=$(( MIRROR_MEGS * 1024 * 1024 / DD_BLOCK )) +export DD_COUNT=$(( MINVDEVSIZE / DD_BLOCK )) diff --git a/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_001_pos.ksh b/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_001_pos.ksh index 841d8ab2e..cce597372 100755 --- a/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_001_pos.ksh +++ b/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_001_pos.ksh @@ -48,6 +48,6 @@ verify_runnable "global" log_assert "The primary side of a zpool mirror may be completely wiped" \ "without affecting the content of the pool" -overwrite_verify_mirror $TESTPOOL $SIDE_PRIMARY /dev/zero +overwrite_verify_mirror $SIDE_PRIMARY /dev/zero log_pass "The overwrite had no effect on the data" diff --git a/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_002_pos.ksh b/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_002_pos.ksh index 92cabd66c..d1fb9d2f1 100755 --- a/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_002_pos.ksh +++ b/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_002_pos.ksh @@ -48,6 +48,6 @@ verify_runnable "global" log_assert "The primary side of a zpool mirror may be completely wiped" \ "without affecting the content of the pool" -overwrite_verify_mirror $TESTPOOL $SIDE_SECONDARY /dev/zero +overwrite_verify_mirror $SIDE_SECONDARY /dev/zero log_pass "The overwrite had no effect on the data" diff --git a/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_003_pos.ksh b/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_003_pos.ksh index ecb422977..fa6c3c2f5 100755 --- a/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_003_pos.ksh +++ b/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_003_pos.ksh @@ -48,6 +48,6 @@ verify_runnable "global" log_assert "The primary side of a zpool mirror may be completely mangled" \ "without affecting the content of the pool" -overwrite_verify_mirror $TESTPOOL $SIDE_PRIMARY /dev/urandom +overwrite_verify_mirror $SIDE_PRIMARY /dev/urandom log_pass "The overwrite did not have any effect on the data" diff --git a/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_004_pos.ksh b/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_004_pos.ksh index b86338095..3139b047b 100755 --- a/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_004_pos.ksh +++ b/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_004_pos.ksh @@ -48,6 +48,6 @@ verify_runnable "global" log_assert "The primary side of a zpool mirror may be completely mangled" \ "without affecting the content of the pool" -overwrite_verify_mirror $TESTPOOL $SIDE_SECONDARY /dev/urandom +overwrite_verify_mirror $SIDE_SECONDARY /dev/urandom log_pass "The overwrite had no effect on the data" diff --git a/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_common.kshlib b/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_common.kshlib index 75c9c5840..4e434ae0b 100644 --- a/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_common.kshlib +++ b/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_common.kshlib @@ -27,13 +27,14 @@ # # Copyright (c) 2013, 2016 by Delphix. All rights reserved. # + +. $STF_SUITE/include/libtest.shlib . $STF_SUITE/tests/functional/scrub_mirror/default.cfg function overwrite_verify_mirror { - typeset POOL=$1 - typeset AFFECTED_DEVICE=$2 - typeset OVERWRITING_DEVICE=$3 + typeset AFFECTED_DEVICE=$1 + typeset OVERWRITING_DEVICE=$2 typeset atfile=0 set -A files @@ -49,14 +50,11 @@ function overwrite_verify_mirror done # dd the affected side of the mirror - log_must dd if=$OVERWRITING_DEVICE of=${DEV_DSKDIR}/$AFFECTED_DEVICE \ + log_must dd if=$OVERWRITING_DEVICE of=$AFFECTED_DEVICE \ seek=8 bs=$DD_BLOCK count=$(( DD_COUNT - 128 )) conv=notrunc - log_must zpool scrub $POOL - - while is_pool_scrubbing $POOL; do - sleep 2 - done + log_must zpool scrub $TESTPOOL + log_must wait_scrubbed $TESTPOOL atfile=0 diff --git a/tests/zfs-tests/tests/functional/scrub_mirror/setup.ksh b/tests/zfs-tests/tests/functional/scrub_mirror/setup.ksh index 97a70d815..94b995db5 100755 --- a/tests/zfs-tests/tests/functional/scrub_mirror/setup.ksh +++ b/tests/zfs-tests/tests/functional/scrub_mirror/setup.ksh @@ -29,22 +29,13 @@ # Copyright (c) 2013 by Delphix. All rights reserved. # -. $STF_SUITE/include/libtest.shlib . $STF_SUITE/tests/functional/scrub_mirror/default.cfg +. $STF_SUITE/include/libtest.shlib verify_runnable "global" -if ! $(is_physical_device $DISKS) ; then - log_unsupported "This directory cannot be run on raw files." -fi - -if [[ -n $SINGLE_DISK ]]; then - log_note "Partitioning a single disk ($SINGLE_DISK)" -else - log_note "Partitioning disks ($MIRROR_PRIMARY $MIRROR_SECONDARY)" -fi -log_must set_partition $SIDE_PRIMARY_PART "" $MIRROR_SIZE $MIRROR_PRIMARY -log_must set_partition $SIDE_SECONDARY_PART "" $MIRROR_SIZE $MIRROR_SECONDARY +log_must mkdir -p $SIDE_DIR +log_must truncate -s $MINVDEVSIZE $SIDE_PRIMARY $SIDE_SECONDARY default_mirror_setup $SIDE_PRIMARY $SIDE_SECONDARY -- cgit v1.2.3