[[RFC] v2 13/14] utils: Add obmc-update

Message ID 20180118050517.2442-14-sam@mendozajonas.com
State RFC
Headers show
Series
  • [[RFC] v2 13/14] utils: Add obmc-update
Related show

Commit Message

Samuel Mendoza-Jonas Jan. 18, 2018, 5:05 a.m.
obmc-update is a helper to interact with the OpenBMC REST API, allowing
the user to check for VPNOR support, upload new images, and update the
host firmware on VPNOR-enabled systems.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 configure.ac        |   1 +
 lib/system/system.c |   1 +
 lib/system/system.h |   1 +
 utils/Makefile.am   |   3 +-
 utils/obmc-update   | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 214 insertions(+), 1 deletion(-)
 create mode 100755 utils/obmc-update

Patch

diff --git a/configure.ac b/configure.ac
index a9e5747..8ba7134 100644
--- a/configure.ac
+++ b/configure.ac
@@ -348,6 +348,7 @@  DEFINE_HOST_PROG(PB_PLUGIN, pb-plugin, [/usr/sbin/pb-plugin])
 DEFINE_HOST_PROG(PB_EXEC, pb-exec, [/usr/sbin/pb-exec])
 DEFINE_HOST_PROG(SH, sh, [/bin/sh])
 DEFINE_HOST_PROG(PFLASH, pflash, [/usr/sbin/pflash])
+DEFINE_HOST_PROG(OBMC_UPDATE, obmc_update, [/usr/sbin/obmc_update])
 
 AC_ARG_WITH(
     [tftp],
diff --git a/lib/system/system.c b/lib/system/system.c
index 97654d8..5de029e 100644
--- a/lib/system/system.c
+++ b/lib/system/system.c
@@ -34,6 +34,7 @@  const struct pb_system_apps pb_system_apps = {
 	.pb_exec	= HOST_PROG_PB_EXEC,
 	.sh		= HOST_PROG_SH,
 	.pflash		= HOST_PROG_PFLASH,
+	.obmc_update	= HOST_PROG_OBMC_UPDATE,
 };
 
 #ifndef TFTP_TYPE
diff --git a/lib/system/system.h b/lib/system/system.h
index 6e1e257..562be15 100644
--- a/lib/system/system.h
+++ b/lib/system/system.h
@@ -19,6 +19,7 @@  struct pb_system_apps {
 	const char *pb_exec;
 	const char *sh;
 	const char *pflash;
+	const char *obmc_update;
 };
 
 extern const struct pb_system_apps pb_system_apps;
diff --git a/utils/Makefile.am b/utils/Makefile.am
index c9015a0..a0d649b 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -12,7 +12,8 @@ 
 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
-dist_sbin_SCRIPTS += utils/pb-udhcpc utils/pb-plugin utils/pb-sos utils/pb-exec
+dist_sbin_SCRIPTS += utils/pb-udhcpc utils/pb-plugin utils/pb-sos \
+		     utils/pb-exec utils/obmc-update
 dist_pkglibexec_SCRIPTS = utils/pb-console
 sbin_PROGRAMS += utils/pb-event utils/pb-config
 
diff --git a/utils/obmc-update b/utils/obmc-update
new file mode 100755
index 0000000..cb7404d
--- /dev/null
+++ b/utils/obmc-update
@@ -0,0 +1,209 @@ 
+#!/bin/sh
+
+usage()
+{
+	cat <<EOF
+Hi!
+EOF
+}
+
+check_response()
+{
+	response=$(echo $1 | jq -r '.status')
+
+	if [ "$response" != "ok" ]; then
+		echo "REST request for $2 returned '$response'"
+		echo "Message: $(echo $1 | jq '.message')"
+		exit 1
+	fi
+}
+
+login()
+{
+	ret=$(curl -s -c /tmp/cjar -b /tmp/cjar -k -H "Content-Type: application/json" -X POST -d '{"data": [ "root", "0penBmc" ] }' \
+		https://$1/login)
+
+	if [ $? != 0 ]; then
+		echo "Failed to login to $1"
+		exit 1
+	fi
+
+	check_response "$ret" "login"
+}
+
+check_bmc()
+{
+	if ! ping -c 1 "$1"; then
+		echo "Can not ping $1!"
+		exit 1
+	fi
+
+	login $@
+
+	# Check each active item on the BMC to see if an item with a "Host"
+	# purpose exists. This implies the use of VPNOR on the BMC
+	ret=$(curl -s -c /tmp/cjar -b /tmp/cjar -k -H "Content-Type: application/json" \
+		https://$1/xyz/openbmc_project/software/active)
+	check_response "$ret" "active images"
+
+	active=$(echo $ret | jq '.data | .endpoints')
+
+	vpnor=false
+	n=$(echo $active | jq 'length')
+	n=$((n-1))
+
+	for i in `seq 0 $n`;
+	do
+		item=$(echo $active | jq -r --argjson ITEM $i '.[$ITEM]')
+		ret=$(curl -s -c /tmp/cjar -b /tmp/cjar -k -H "Content-Type: application/json" \
+			https://${1}${item})
+		check_response "$ret" "image purpose"
+		purpose=$(echo $ret | jq -r '.data | .Purpose')
+		if [ "${purpose##*.}" == "Host" ]; then
+			vpnor=true
+			continue
+		fi
+	done
+
+	if [ "$vpnor" != true ]; then
+		echo "No VPNOR"
+		exit 1
+	fi
+}
+
+find_ready_item()
+{
+
+	ret=$(curl -s -c /tmp/cjar -k -H "Content-Type: application/json" \
+		https://$1/xyz/openbmc_project/software/)
+	check_response "$ret" "software info"
+	software=$(echo $ret | jq '.data')
+
+	n=$(echo $software | jq 'length')
+	n=$((n-1))
+	for i in `seq 0 $n`;
+	do
+		# Ignore groupings
+		item=$(echo $software | jq -r --argjson ITEM $i '.[$ITEM]')
+		if [ "$(basename $item)" == "active" -o \
+			"$(basename $item)" == "functional" ]; then
+			continue
+		fi
+
+		# Is this a host update?
+		ret=$(curl -s -c /tmp/cjar -k -H "Content-Type: application/json" \
+			https://${1}${item})
+		check_response "$ret" "image purpose"
+		purpose=$(echo $ret | jq -r '.data | .Purpose')
+		if [ "${purpose##*.}" != "Host" ]; then
+			continue
+		fi
+
+		# Check the update status
+		ret=$(curl -s -c /tmp/cjar -k -H "Content-Type: application/json"} \
+			https://${1}${item})
+		check_response "$ret" "update status"
+		status=$(echo $ret | jq -r '.data | .Activation')
+
+		# Cool parameter expansion
+		if [ "${status##*.}" == "Ready" ]; then
+			hash=$(basename $item)
+		fi
+	done
+
+	echo $hash
+}
+
+upload()
+{
+	login $1
+
+	# if [ -n $strict ]; then
+	hash=$(find_ready_item $@)
+
+	if [ -n "$hash" ]; then
+		echo "Existing item ready for update! Aborting"
+		exit 1
+	fi
+
+	echo "Uploading $2"
+
+	ret=$(curl -s -c /tmp/cjar -b /tmp/cjar -k -H "Content-Type: application/octet-stream" \
+		-X POST -T $2 https://$1/upload/image)
+	check_response "$ret" "image upload"
+
+	# Wait a moment for the BMC to catch up
+	sleep 2
+
+	hash=$(find_ready_item $@)
+
+	if [ -n "$hash" ]; then
+		echo "$hash"
+	else
+		echo "Could not find new image version"
+		exit 1
+	fi
+}
+
+update()
+{
+	echo "Update"
+	login $1
+
+	if [ -z "$2" ]; then
+		echo "No image version specified"
+		exit 1
+	fi
+
+	ret=$(curl -c /tmp/cjar -k -H "Content-Type: application/json" -X PUT -d '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}' \
+		https://$1/xyz/openbmc_project/software/$2/attr/RequestedActivation)
+	check_response "$ret" "activate image"
+
+	# Track status
+	activated=0
+	while [ $activated -eq 0 ]; do
+		# Check the update status
+		status=$(curl -s -c /tmp/cjar -b /tmp/cjar -k \
+			-H "Content-Type: application/json" \
+			https://$1/xyz/openbmc_project/software/$2 \
+			| jq -r '.data | .Activation')
+		# Cool parameter expansion
+		if [ "${status##*.}" == "Activating" ]; then
+			sleep 1
+			echo "Activating.."
+			continue
+		else
+			echo "Activation finished with status ${status##*.}"
+			activated=1
+		fi
+	done
+}
+
+if [ "`which curl`" == "" ]; then
+	echo "Unable to find the curl utility"
+	exit 1
+fi
+
+case "$1" in
+check)
+	shift
+	check_bmc $@
+	;;
+upload)
+	shift
+	upload $@
+	;;
+update)
+	shift
+	update $@
+	;;
+"")
+	echo "error: Missing command" >&2
+	usage
+	exit 1
+	;;
+*)
+	echo "Invalid command: $1" >&2
+	usage
+	exit 1
+esac