diff --git a/create-arista-veos-image/create-arista-veos-image.sh b/create-arista-veos-image/create-arista-veos-image.sh index ae692ab..cf798c0 100644 --- a/create-arista-veos-image/create-arista-veos-image.sh +++ b/create-arista-veos-image/create-arista-veos-image.sh @@ -13,6 +13,7 @@ # V1.3.2 changed the extension of the bootloader iso to match the size of the partitions to be injected # V1.4 support for variable VEOS image sizes (as requested by @Jade_Deane to use custom VEOS images) # V1.4.1 fixed check for existing images +# V1.5 fixed detection of missing loop files for Ubuntu 16.04 in VIRL >=1.3, added default subtype creation # usage if [ ! $# -eq 3 ] ; then @@ -77,6 +78,7 @@ echo "Creating vEOS image..." echo "===========================================================" # create a copy of Aboot bootloader and extend it to 3G +echo "Creating a copy of Aboot bootloader in $TMP_NAME.raw..." cp $1 $TMP_NAME.raw echo @@ -84,13 +86,43 @@ echo "Extracting partitions from vEOS vmdk..." echo "===========================================================" # convert vmdk to raw and extract two partitions in it +echo "Converting vmdk image to raw..." qemu-img convert -O raw $2 $VEOS_VMDK_BASENAME.raw LOOPDEV=$(kpartx -av $VEOS_VMDK_BASENAME.raw) LOOPDEV_PART1=$(echo "$LOOPDEV" | sed '1q;d' | cut -d " " -f 3) LOOPDEV_PART2=$(echo "$LOOPDEV" | sed '2q;d' | cut -d " " -f 3) +echo "Output from kpartx: $LOOPDEV" +echo "PART1: $LOOPDEV_PART1" +echo "PART2: $LOOPDEV_PART2" +echo -n "waiting for loop devs from kpartx" +LOOP_DEV_RETRIES=0 +until dd if=/dev/mapper/$LOOPDEV_PART1 of=/dev/null bs=1k count=1 &>/dev/null && dd if=/dev/mapper/$LOOPDEV_PART2 of=/dev/null bs=1k count=1 &>/dev/null ; do + echo -n "." + LOOP_DEV_RETRIES=$(expr $LOOP_DEV_RETRIES + 1) + if [ $LOOP_DEV_RETRIES -eq 10 ]; then + echo + echo "ERROR: timeout waiting for loop devs from kaprtx" + exit + fi + sleep 1 +done +echo +echo "using dd to extract partitions..." dd if=/dev/mapper/$LOOPDEV_PART1 of=$VEOS_VMDK_BASENAME-p1.raw dd if=/dev/mapper/$LOOPDEV_PART2 of=$VEOS_VMDK_BASENAME-p2.raw -kpartx -d $VEOS_VMDK_BASENAME.raw +LOOP_DEV_DEL_RETRIES=0 +echo "removing loop devs from kpartx" +until kpartx -vd $VEOS_VMDK_BASENAME.raw ; do + echo -n "." + LOOP_DEV_DEL_RETRIES=$(expr $LOOP_DEV_DEL_RETRIES + 1) + if [ $LOOP_DEV_DEL_RETRIES -eq 10 ]; then + echo + echo "ERROR: timeout waiting for loop dev removal from kaprtx" + exit + fi + sleep 1 +done +echo echo echo "Injecting rc.eos startup script to get switch config..." @@ -98,8 +130,10 @@ echo "===========================================================" # inject rc.eos script in first partition of the image, to get switch config defined in VM Maestro (config-drive) mkdir swi-$TIMESTAMP +echo "loop mounting image..." mount -o loop $VEOS_VMDK_BASENAME-p1.raw swi-$TIMESTAMP cd swi-$TIMESTAMP +echo "injecting rc.eos..." cat << EOF > rc.eos #!/bin/sh # @@ -134,6 +168,7 @@ EOF chmod 755 rc.eos cd .. +echo "unmounting image..." safe_unmount swi-$TIMESTAMP rm -rf swi-$TIMESTAMP @@ -142,19 +177,31 @@ echo echo "Injecting new partitions from vEOS vmdk in Aboot image..." echo "===========================================================" +echo "$VEOS_VMDK_BASENAME.raw (original vEOS vmdk layout):" +fdisk -l $VEOS_VMDK_BASENAME.raw + +echo "$TMP_NAME.raw (original ABoot bootloader layout):" +fdisk -l $TMP_NAME.raw + # calulate size of the two partitions PART1_START=$(fdisk -l $VEOS_VMDK_BASENAME.raw | grep "\.raw1" | tr -s " " | cut -d ' ' -f 3) PART1_END=$(fdisk -l $VEOS_VMDK_BASENAME.raw | grep "\.raw1" | tr -s " " | cut -d ' ' -f 4) PART1_LENGTH=$(expr $PART1_END - $PART1_START) +echo "raw1 start=$PART1_START,end=$PART1_END,length=$PART1_LENGTH" + PART2_START=$(fdisk -l $VEOS_VMDK_BASENAME.raw | grep "\.raw2" | tr -s " " | cut -d ' ' -f 2) PART2_END=$(fdisk -l $VEOS_VMDK_BASENAME.raw | grep "\.raw2" | tr -s " " | cut -d ' ' -f 3) PART2_LENGTH=$(expr $PART2_END - $PART2_START) +echo "raw2 start=$PART2_START,end=$PART2_END,length=$PART2_LENGTH" + # extend the bootloader iso to be able to append the two partitions EXTENSION_SIZE=$(ls -lk $VEOS_VMDK_BASENAME.raw | tr -s " " | cut -d " " -f 5) +echo "extending image $TMP_NAME.raw to +$EXTENSION_SIZE" truncate -s +$EXTENSION_SIZE $TMP_NAME.raw +echo "appending partitions from vmdk in the bootloader iso in $TMP_NAME.raw..." # append the two partitions from vmdk in the bootloader iso echo -e "n p @@ -174,15 +221,47 @@ p t 3 12 -w" | fdisk $TMP_NAME.raw >/dev/null +w" | fdisk $TMP_NAME.raw + +echo "$TMP_NAME.raw (new combined image layout):" +fdisk -l $TMP_NAME.raw # copy the partitions from vEOS vmdk to new image LOOPDEV=$(kpartx -av $TMP_NAME.raw) LOOPDEV_PART2=$(echo "$LOOPDEV" | sed '2q;d' | cut -d " " -f 3) LOOPDEV_PART3=$(echo "$LOOPDEV" | sed '3q;d' | cut -d " " -f 3) +echo "Output from kpartx: $LOOPDEV" +echo "PART1: $LOOPDEV_PART1" +echo "PART2: $LOOPDEV_PART2" +echo -n "waiting for loop devs from kpartx" +LOOP_DEV_RETRIES=0 +until dd if=/dev/mapper/$LOOPDEV_PART2 of=/dev/null bs=1k count=1 &>/dev/null && dd if=/dev/mapper/$LOOPDEV_PART3 of=/dev/null bs=1k count=1 &>/dev/null ; do + echo -n "." + LOOP_DEV_RETRIES=$(expr $LOOP_DEV_RETRIES + 1) + if [ $LOOP_DEV_RETRIES -eq 10 ]; then + echo + echo "ERROR: timeout waiting for loop devs from kaprtx" + exit + fi + sleep 1 +done +echo +echo "copying the partitions from vEOS vmdk to new image..." dd if=$VEOS_VMDK_BASENAME-p1.raw of=/dev/mapper/$LOOPDEV_PART2 dd if=$VEOS_VMDK_BASENAME-p2.raw of=/dev/mapper/$LOOPDEV_PART3 -kpartx -d $TMP_NAME.raw +LOOP_DEV_DEL_RETRIES=0 +echo "removing loop devs from kpartx" +until kpartx -vd $TMP_NAME.raw ; do + echo -n "." + LOOP_DEV_DEL_RETRIES=$(expr $LOOP_DEV_DEL_RETRIES + 1) + if [ $LOOP_DEV_DEL_RETRIES -eq 10 ]; then + echo + echo "ERROR: timeout waiting for loop dev removal from kaprtx" + exit + fi + sleep 1 +done +echo echo echo "Convert new image to qcow2..." @@ -209,21 +288,68 @@ glance image-create --container-format bare --disk-format qcow2 --visibility pub --property hw_vif_model=e1000 --property hw_cdrom_type=ide --property release="$GLANCE_IMAGE_RELEASE" --property subtype=IOSv --property config_disk_type=disk # create default flavor -CHECKING_FOR_EXISTING_FLAVOR=$(nova flavor-show vEOS.small 2>&1) +CHECKING_FOR_EXISTING_FLAVOR=$(nova flavor-show $GLANCE_IMAGE_NAME.small 2>&1) if [ $? == 1 ]; then - echo "Creating default flavor vEOS.small..." + echo "Creating default flavor $GLANCE_IMAGE_NAME.small..." echo "===========================================================" - nova flavor-create --is-public true vEOS.small auto 1024 0 1 + nova flavor-create --is-public true $GLANCE_IMAGE_NAME.small auto 1024 0 1 +else + echo "Default flavor $GLANCE_IMAGE_NAME.small already exists..." fi -CHECKING_FOR_EXISTING_FLAVOR=$(nova flavor-show vEOS.medium 2>&1) +CHECKING_FOR_EXISTING_FLAVOR=$(nova flavor-show $GLANCE_IMAGE_NAME.medium 2>&1) if [ $? == 1 ]; then - echo "Creating default flavor vEOS.medium..." + echo "Creating default flavor $GLANCE_IMAGE_NAME.medium..." echo "===========================================================" - nova flavor-create --is-public true vEOS.medium auto 2048 0 1 + nova flavor-create --is-public true $GLANCE_IMAGE_NAME.medium auto 2048 0 1 +else + echo "Default flavor $GLANCE_IMAGE_NAME.medium already exists..." fi +# create deault subtype +cat << EOF > dynamic-subtype-$GLANCE_IMAGE_NAME.json.default +{ + "dynamic-subtypes": [ + { + "plugin_name": "$GLANCE_IMAGE_NAME", + "cli_serial": 1, + "plugin_desc": "Arista vEOS", + "baseline_image": "$GLANCE_IMAGE_NAME", + "hw_ram": 1024, + "hw_vm_extra": "", + "interface_wrap": 7, + "config_disk_type": "disk", + "interface_pattern": "Ethernet{0}", + "gui_visible": true, + "config_file": "/veos_config.txt", + "interface_first": 1, + "gui_icon": "iosvl2", + "plugin_base": "generic", + "vnc_available": false, + "interface_management": "Management1", + "interface_range": 7, + "baseline_flavor": "$GLANCE_IMAGE_NAME.medium" + } + ] +} +EOF +CHECKING_FOR_EXISTING_SUBTYPE=$(virl_uwm_client subtype-info 2>&1 | grep $GLANCE_IMAGE_NAME) +if [ $? == 1 ]; then + echo "Creating default subtype $GLANCE_IMAGE_NAME..." + echo "===========================================================" + + virl_uwm_client subtype-import --dynamic-subtypes @dynamic-subtype-$GLANCE_IMAGE_NAME.json.default +else + echo "Default subtype $GLANCE_IMAGE_NAME already exists..." +fi +rm dynamic-subtype-$GLANCE_IMAGE_NAME.json.default + +echo +echo "Image creation successful." +echo "===========================================================" +echo +echo "You can import and use the subtype $GLANCE_IMAGE_NAME in VM Maestro..." #testing: #