[[RFC PATCH] v2 13/14] utils: Add obmc-update
Samuel Mendoza-Jonas
sam at mendozajonas.com
Thu Jan 18 16:05:16 AEDT 2018
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 at 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
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
--
2.15.1
More information about the Petitboot
mailing list