Skip to content

Commit

Permalink
Fix BMC FW image flash test according to OpenBMC Implementation.
Browse files Browse the repository at this point in the history
OpenBMC just does a no operation when updating a code level of 'X'
on a system which is having already code level 'X'.

So we need to follow below procedure to have all scenarios.

1. User requested for flashing image ID 'X'
2. Upload the BMC image.
3. Get the list of BMC image ID's.
4. If 'X' is found in the list
   ---> check if it is Active or Ready
	if it is Ready ---> Activate the image and do a BMC reboot
	if it is already Active
	---> Check whether it is functional(BMC boot side is 'X') or not.
	     if it is functional ---> return
	     if it is non functional ---> Set it's priority to 0, do a BMC reboot
					  and make it functional
5. At the end verify whether BMC boots in right code which we requested for flash.

The idea is to do a no op when updating code 'X' on having system which also has
level of 'X'

Signed-off-by: Pridhiviraj Paidipeddi <ppaidipe@linux.vnet.ibm.com>
  • Loading branch information
pridhiviraj committed Dec 15, 2017
1 parent 7ddc7cc commit 58e5ef5
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 6 deletions.
37 changes: 37 additions & 0 deletions common/OpTestOpenBMC.py
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,18 @@ def get_image_priority(self, id):
print repr(output)
return output['data']['Priority']

"""
Set the image priority
curl -b cjar -k -H "Content-Type: application/json" -X PUT -d '{"data":0}'
https://$BMC_IP/xyz/openbmc_project/software/061c4bdb/attr/Priority
"""
def set_image_priority(self, id, level):
obj = "/xyz/openbmc_project/software/%s/attr/Priority" % id
data = '\'{\"data\":%s}\'' % level
self.curl.feed_data(dbus_object=obj, operation='rw', command="PUT", data=data)
self.curl.run()


def image_ready_for_activation(self, id, timeout=10):
timeout = time.time() + 60*timeout
while True:
Expand Down Expand Up @@ -874,6 +886,31 @@ def set_field_mode(self, mode):
self.curl.feed_data(dbus_object=obj, operation='rw', command="PUT", data=data)
return json.loads(self.curl.run())

"""
1. functional boot side validation for both BMC and PNOR.
$ curl -c cjar -b cjar -k -H "Content-Type: application/json" https://$BMC_IP/xyz/openbmc_project/software/functional
{
"data": {
"endpoints": [
"/xyz/openbmc_project/software/061c4bdb",
"/xyz/openbmc_project/software/608e9ebe"
]
}
"""
def validate_functional_bootside(self, id):
obj = "/xyz/openbmc_project/software/functional"
self.curl.feed_data(dbus_object=obj, operation='rw', command="GET")
output = self.curl.run()
print output
if id in output:
return True
return False

def is_image_already_active(self, id):
output = self.image_data(id)
if output['data']['Activation'] == 'xyz.openbmc_project.Software.Activation.Activations.Active':
return True
return False

class OpTestOpenBMC():
def __init__(self, ip=None, username=None, password=None, ipmi=None, rest_api=None, logfile=sys.stdout):
Expand Down
64 changes: 58 additions & 6 deletions testcases/OpTestFlash.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,29 @@ def get_image_version(self, path):
output = self.cv_BMC.run_command("cat %s | grep \"version=\"" % path)
return output[0].split("=")[-1]

def delete_images_dir(self):
try:
self.cv_BMC.run_command("rm -rf /tmp/images/*")
except CommandFailed:
pass

def get_image_path(self, image_version):
image_list = self.cv_BMC.run_command("ls -d /tmp/images/*/ --color=never")
retry = 0
while (retry < 10):
for i in range(0, len(image_list)):
version = self.get_image_version(image_list[i] + "MANIFEST")
if (version == image_version):
return image_list[i]
time.sleep(10)
retry += 1

def get_image_id(self, version):
img_path = self.get_image_path(version)
img_id = img_path.split("/")[-2]
print "Image id for Host image is : %s" % img_id
return img_id

def wait_for_bmc_runtime(self):
self.util.PingFunc(self.bmc_ip, BMC_CONST.PING_RETRY_FOR_STABILITY)
if "SMC" in self.bmc_type:
Expand Down Expand Up @@ -139,25 +162,51 @@ def runTest(self):
except CommandFailed as cf:
# Ok to just keep giong, may not have patched firmware
pass
# OpenBMC implementation for updating code level 'X' to 'X' is really a no-operation
# it only updates the code from 'X' to 'Y' or 'Y' to 'X' to avoid duplicates
self.delete_images_dir()
self.cv_REST.upload_image(self.bmc_image)
version = self.get_version_tar(self.bmc_image)
id = self.get_image_id(version)
img_ids = self.cv_REST.bmc_image_ids()

if self.cv_REST.is_image_already_active(id):
print "# The given BMC image %s is already active on the system" % id
if self.cv_REST.validate_functional_bootside(id):
print "# And the given BMC image is already functional"
return True
# If non functional set the priority and reboot the BMC
self.cv_REST.set_image_priority(id, "0")
self.cv_BMC.reboot()
self.wait_for_bmc_runtime()
return True

retries = 60
while len(img_ids) == 0 and retries > 0:
while retries > 0:
time.sleep(1)
img_ids = self.cv_REST.bmc_image_ids()
retries = retries - 1
self.assertTrue(retries > 0, "Uploaded image but it never showed up")
for img_id in img_ids:
d = self.cv_REST.image_data(img_id)
if d['data']['Activation'] == "xyz.openbmc_project.Software.Activation.Activations.Ready":
break
for img_id in img_ids:
d = self.cv_REST.image_data(img_id)
if d['data']['Activation'] == "xyz.openbmc_project.Software.Activation.Activations.Ready":
print "BMC image %s is ready to activate" % img_id
break
else:
continue
break
self.assertTrue(retries > 0, "Uploaded image but it never is ready to activate it")
print "Going to activate image id: %s" % img_id
self.assertIsNotNone(img_id, "Could not find Image ID")
self.cv_REST.activate_image(img_id)
self.assertTrue(self.cv_REST.wait_for_image_active_complete(img_id), "Failed to activate image")
# On SMC reboot will happen automatically, but on OpenBMC needs manual reboot to upgrade the BMC FW.
self.cv_BMC.reboot()
self.wait_for_bmc_runtime()
# Once BMC comes up, verify whether BMC really booted from the code which we flashed.
# As BMC maintains two levels of code, so there may be possibilities/bugs which causes
# the boot from alternate side or other code.
self.assertTrue(self.cv_REST.validate_functional_bootside(img_id), "BMC failed to boot from the right code")
print "# BMC booting from the right code with image ID: %s" % img_id
c = 0
while True:
time.sleep(5)
Expand Down Expand Up @@ -237,6 +286,9 @@ def runTest(self):
self.assertIsNotNone(img_id, "Could not find Image ID")
self.cv_REST.activate_image(img_id)
self.assertTrue(self.cv_REST.wait_for_image_active_complete(img_id), "Failed to activate image")
# We need to have below check after power on of the host.
#self.assertTrue(self.cv_REST.validate_functional_bootside(img_id), "PNOR failed to boot from the right code")
print "# PNOR boots from the right code with image ID: %s" % img_id
else:
print "Fallback to old code update method using pflash tool"
self.cv_BMC.image_transfer(self.pnor)
Expand Down

0 comments on commit 58e5ef5

Please sign in to comment.