diff -pruN 0.8.0-2/AUTHORS 0.12.3-0ubuntu1/AUTHORS
--- 0.8.0-2/AUTHORS	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/AUTHORS	2022-07-29 10:07:36.000000000 +0000
@@ -0,0 +1,31 @@
+98k <18552437190@163.com>
+Andreas Jaeger <aj@suse.com>
+Dao Cong Tien <tiendc@vn.fujitsu.com>
+Doug Hellmann <doug@doughellmann.com>
+Hironori Shiina <shiina.hironori@jp.fujitsu.com>
+Jamie Lennox <jamielennox@gmail.com>
+Janonymous <janonymous.codevulture@gmail.com>
+Jin Hase <hase.jin@fujitsu.com>
+Kobayashi Daisuke <kobayashi.da-06@fujitsu.com>
+Luong Anh Tuan <tuanla@vn.fujitsu.com>
+Naohiro Tamura <naohirot@jp.fujitsu.com>
+Ngo Quoc Cuong <cuongnq@vn.fujitsu.com>
+Nguyen Hung Phuong <phuongnh@vn.fujitsu.com>
+Nguyen Quang Huy <huynq@vn.fujitsu.com>
+Nguyen Van Trung <trungnv@vn.fujitsu.com>
+Riccardo Pittau <elfosardo@gmail.com>
+Shukun Song <song.shukun@jp.fujitsu.com>
+Swapnil Kulkarni (coolsvap) <me@coolsvap.net>
+Thomas Bechtold <tbechtold@suse.com>
+Thomas Goirand <zigo@debian.org>
+Tony Breeds <tony@bakeyournoodle.com>
+Vanou Ishii <ishii.vanou@fujitsu.com>
+Vieri <15050873171@163.com>
+Vu Cong Tuan <tuanvc@vn.fujitsu.com>
+Yushiro FURUKAWA <y.furukawa_2@jp.fujitsu.com>
+qingszhao <zhao.daqing@99cloud.net>
+ricolin <rico.lin@easystack.cn>
+shangxiaobj <shangxiaobj@inspur.com>
+shu-mutou <shu-mutou@rf.jp.nec.com>
+vanou <ishii.vanou@fujitsu.com>
+yatinkarel <ykarel@redhat.com>
diff -pruN 0.8.0-2/ChangeLog 0.12.3-0ubuntu1/ChangeLog
--- 0.8.0-2/ChangeLog	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/ChangeLog	2022-07-29 10:07:36.000000000 +0000
@@ -0,0 +1,196 @@
+CHANGES
+=======
+
+0.12.3
+------
+
+* Modify incompatible default value passed to requests
+
+0.12.2
+------
+
+* Encode parameters passed to pyghmi.ipmi.Command
+* Change the name of keys to mask passwords
+* Add v3 authentication functionality to snmp module
+
+0.12.0
+------
+
+* Add parameter to specify certification file
+* Add function to determine virtual FD support
+* Fix bug of eject virtual CDROM in scciclient
+* Add description of iRMC S5 support
+* Use standard library unittest.mock instead of mock
+* Use defusedxml instead of standard xml
+* Drop Python2.7 support
+* Use only Yoga tests
+
+0.11.0.1
+--------
+
+* Use current openstack tests
+* Bring tests to current openstack release
+* Temporarily comment out the operation of deleting the profile
+* Use assertCountEqual instead of assertItemsEqual
+* Modify some description
+
+0.9.0
+-----
+
+* Update min version required for pyghmi
+* Make CI work
+* Add Python 3.6 classifier to setup.cfg
+* Change openstack-dev to openstack-discuss
+* Adds a sleep(3s) after performing power on/off/reset
+* OpenDev Migration Patch
+
+0.8.1
+-----
+
+* Fix getting RAID configuration for iRMC S5
+* Don't quote {posargs} in tox.ini
+* Use template for lower-constraints
+* Support firmware upgrade for iRMC and BIOS
+* Removed older version of python added 3.5
+* fix tox python3 overrides
+* Fix coverage command for tox
+
+0.8.0
+-----
+
+* Fix async keyword for Python 3.7
+
+0.7.3
+-----
+
+* Fix bug of missing versions when setting secure boot flag
+
+0.7.2
+-----
+
+* Follow-up to BIOS configuration feature
+* Set profile version for VIOM configuration
+
+0.7.1
+-----
+
+* Add APIs support BIOS configuration
+* Switch to stestr
+
+0.7.0
+-----
+
+* Move BGI into FGI mechanism for safe operation
+* Add new cpu\_fpgas capabilities to ironic
+* Support RAID configuration via irmc driver
+* add lower-constraints job
+* Updated from global requirements
+* Updated from global requirements
+
+0.6.1
+-----
+
+* Updated from global requirements
+* Change http links to https according to official website
+* Updated from global requirements
+* Avoid tox\_install.sh for constraints support
+* Updated from global requirements
+
+0.6.0
+-----
+
+* Add capabilities discovery ability to scciclient
+* \*.idea should add to .gitignore
+* Updated from global requirements
+
+0.5.0
+-----
+
+* Add configuration client for VIOM configuration
+* Add eLCM APIs to control VIOM table
+* Add error information to error messages
+* Updated from global requirements
+* Implements get and set for secure boot mode
+* Remove Workaround add sub-profiles IrmcConfig and OSInstallation
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Trivial fix warnings while reading code
+* Trivial Fix typos Trivial fix typos while reading the code
+* Updated from global requirements
+* Updated from global requirements
+* Implement backup/restore bios config functionality using eLCM
+* Implement eLCM functionality for iRMC SCCI
+* Updated from global requirements
+* Updated from global requirements
+* [Fix gate]Update test requirement
+* Updated from global requirements
+* H803 hacking have been deprecated
+* Add Constraints support
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Enables py35 tox unit test
+
+0.4.0
+-----
+
+* Remove discover from test-requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+
+0.3.1
+-----
+
+* Fixed the 'local\_gb' disk size
+* Updated from global requirements
+* Update get\_essential\_properties() for empty CPU socket
+* Updated from global requirements
+* Updated from global requirements
+* Change the number of CD/FD drive to 1 instead of 2
+* Enable to see the result of 'tox -e cover'
+* Change ignore-errors to ignore\_errors
+* Updated from global requirements
+* Put py34 first in the env order of tox
+* Updated from global requirements
+* Drop py33 support
+* Updated from global requirements
+* Use requests\_mock instead of httpretty
+* Updated from global requirements
+
+0.3.0
+-----
+
+* Update the global requirements and fix the scciclient package name
+* Update setup.cfg for openstack/python-scciclient name space
+* Add hardware inspection module for iRMC driver
+
+0.2.0
+-----
+
+* added async param to scci\_cmd(), and debug message
+* Add soft reboot and NMI support
+* Supported Python 3.4
+* reflected the comment iRMC vmedia deploy patch #15
+* added MetaShareType class, get\_share\_type function, and wait param to scci\_cmd function
+
+0.1.0
+-----
+
+* fixed requests timeout and virtual media mount/unmount
+
+0.0.1
+-----
+
+* Upload to PyPI
+* Upload to PyPI Test
+* tox ok, externalization from Ironic has been done
+* scci initial commit
+* Initial Cookiecutter Commit
diff -pruN 0.8.0-2/debian/changelog 0.12.3-0ubuntu1/debian/changelog
--- 0.8.0-2/debian/changelog	2019-07-18 21:52:05.000000000 +0000
+++ 0.12.3-0ubuntu1/debian/changelog	2022-09-09 00:42:26.000000000 +0000
@@ -1,43 +1,94 @@
-python-scciclient (0.8.0-2) unstable; urgency=medium
+python-scciclient (0.12.3-0ubuntu1) kinetic; urgency=medium
 
-  [ Ondřej Nový ]
-  * Use debhelper-compat instead of debian/compat.
+  * New upstream release for OpenStack Zed.
 
-  [ Thomas Goirand ]
-  * Uploading to unstable.
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 08 Sep 2022 20:42:26 -0400
 
- -- Thomas Goirand <zigo@debian.org>  Thu, 18 Jul 2019 23:52:05 +0200
+python-scciclient (0.12.1-0ubuntu1) kinetic; urgency=medium
 
-python-scciclient (0.8.0-1) experimental; urgency=medium
+  * New upstream release for OpenStack Zed.
 
-  [ Ondřej Nový ]
-  * Running wrap-and-sort -bast
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 13 Jul 2022 14:46:14 -0400
 
-  [ Thomas Goirand ]
-  * New upstream release.
-  * Removed versions when satisfied in Buster.
-  * Removed py3.7-fix-async-keyword.patch applied upstream.
+python-scciclient (0.11.2-0ubuntu1) kinetic; urgency=medium
 
- -- Thomas Goirand <zigo@debian.org>  Tue, 26 Mar 2019 11:30:27 +0100
+  * New upstream release for OpenStack Zed.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/control: Switch to debhelper compat 13.
+  * d/control: Update standards version to 4.6.1.
 
-python-scciclient (0.7.2-2) unstable; urgency=medium
+ -- Corey Bryant <corey.bryant@canonical.com>  Tue, 31 May 2022 16:38:36 -0400
 
-  * Uploading to unstable.
+python-scciclient (0.11.1-0ubuntu1) jammy; urgency=medium
 
- -- Thomas Goirand <zigo@debian.org>  Mon, 03 Sep 2018 16:58:29 +0200
+  * New upstream release for OpenStack Yoga.
+  * d/p/drop-oslosphinx.patch, d/control: Dropped python3-oslosphinx. Fixed
+    upstream.
+  * d/control: Align (Build-)Depends with upstream.
 
-python-scciclient (0.7.2-1) experimental; urgency=medium
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 12 Jan 2022 15:10:36 -0500
 
-  [ Ondřej Nový ]
-  * d/control: Use team+openstack@tracker.debian.org as maintainer
+python-scciclient (0.10.0-0ubuntu1) impish; urgency=medium
 
-  [ Thomas Goirand ]
-  * New upstream release.
-  * Fixed (build-)depends for this release.
-  * Removed Python 2 support.
-  * Add py3.7-fix-async-keyword.patch.
+  * New upstream release for OpenStack Xena.
 
- -- Thomas Goirand <zigo@debian.org>  Fri, 24 Aug 2018 13:50:50 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 21 Jul 2021 15:33:49 -0400
+
+python-scciclient (0.9.1-0ubuntu1) hirsute; urgency=medium
+
+  [ Chris MacNaughton ]
+  * d/control: Update VCS paths for move to lp:~ubuntu-openstack-dev.
+
+  [ Corey Bryant ]
+  * New upstream release for OpenStack Wallaby.
+  * d/control: Align (Build-)Depends with upstream.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 17 Mar 2021 11:21:18 -0400
+
+python-scciclient (0.8.1-0ubuntu4) groovy; urgency=medium
+
+  * d/control, d/p/drop-oslosphinx.patch: Drop use of deprecated oslosphinx.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Fri, 02 Oct 2020 13:30:49 -0400
+
+python-scciclient (0.8.1-0ubuntu3) groovy; urgency=medium
+
+  * d/rules: Run sphinx with python3.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 01 Oct 2020 16:16:07 -0400
+
+python-scciclient (0.8.1-0ubuntu2) groovy; urgency=medium
+
+  * d/control: Drop remaining py2 Build-Depends.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Fri, 26 Jun 2020 15:02:09 -0400
+
+python-scciclient (0.8.1-0ubuntu1) groovy; urgency=medium
+
+  * New upstream release for OpenStack Victoria.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/control, d/rules: Switch to debhelper compat 12 and pybuild.
+  * d/control: Update Standards-Version to 4.5.0.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Fri, 12 Jun 2020 13:56:14 -0400
+
+python-scciclient (0.8.0-0ubuntu2) eoan; urgency=medium
+
+  * d/control: Drop BDI's on python-* packages.
+  * d/control: Drop python-scciclient binary package.
+  * d/rules: Tweak to stop build and install of Python 2 parts.
+
+ -- Sahid Orentino Ferdjaoui <sahid.ferdjaoui@canonical.com>  Thu, 11 Jul 2019 14:31:00 +0200
+
+python-scciclient (0.8.0-0ubuntu1) disco; urgency=medium
+
+  * d/gbp.conf: Update gbp configuration file.
+  * d/control: Update Vcs-* links and maintainers.
+  * d/watch: Get release tarballs from tarballs.openstack.org.
+  * New upstream release for OpenStack Stein.
+  * d/control: Align (Build-)Depends with upstream.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Mon, 05 Nov 2018 15:37:24 -0500
 
 python-scciclient (0.6.1-2) unstable; urgency=medium
 
diff -pruN 0.8.0-2/debian/control 0.12.3-0ubuntu1/debian/control
--- 0.8.0-2/debian/control	2019-07-18 21:52:05.000000000 +0000
+++ 0.12.3-0ubuntu1/debian/control	2022-09-09 00:42:26.000000000 +0000
@@ -1,38 +1,42 @@
 Source: python-scciclient
 Section: python
 Priority: optional
-Maintainer: Debian OpenStack <team+openstack@tracker.debian.org>
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-Maintainer: Debian OpenStack <openstack-devel@lists.alioth.debian.org>
 Uploaders:
  Thomas Goirand <zigo@debian.org>,
 Build-Depends:
- debhelper-compat (= 10),
+ debhelper-compat (= 13),
  dh-python,
  openstack-pkg-tools,
  python3-all,
- python3-pbr,
+ python3-pbr (>= 2.0.0),
  python3-setuptools,
- python3-sphinx,
+ python3-sphinx (>= 2.0.0),
 Build-Depends-Indep:
- python3-babel,
- python3-fixtures,
+ python3-babel (>= 2.3.4),
+ python3-coverage (>= 4.0),
+ python3-defusedxml (>= 0.7.0),
+ python3-fixtures (>= 3.0.0),
+ python3-hacking (>= 0.12.0),
  python3-httpretty,
- python3-mock <!nocheck>,
- python3-oslo.serialization,
- python3-oslo.utils,
- python3-oslosphinx,
- python3-oslotest <!nocheck>,
- python3-pyghmi,
- python3-pysnmp4,
- python3-requests,
- python3-requests-mock <!nocheck>,
- python3-stestr,
- python3-testscenarios <!nocheck>,
- python3-testtools <!nocheck>,
- subunit <!nocheck>,
-Standards-Version: 4.3.0
-Vcs-Browser: https://salsa.debian.org/openstack-team/python/python-scciclient
-Vcs-Git: https://salsa.debian.org/openstack-team/python/python-scciclient.git
-Homepage: https://github.com/openstack/python-scciclient
+ python3-mock (>= 2.0.0),
+ python3-openstackdocstheme (>= 2.2.1),
+ python3-oslo.serialization (>= 2.18.0),
+ python3-oslo.utils (>= 3.33.0),
+ python3-oslotest (>= 1:3.2.0),
+ python3-pyghmi (>= 1.0.24),
+ python3-pysnmp4 (>= 4.2.3),
+ python3-requests (>= 2.14.2),
+ python3-requests-mock (>= 1.2.0),
+ python3-subunit (>= 1.0.0),
+ python3-stestr (>= 2.0.0),
+ python3-testscenarios (>= 0.4),
+ python3-testtools (>= 2.2.0),
+ python3-testrepository,
+Standards-Version: 4.6.1
+Vcs-Git: https://git.launchpad.net/~ubuntu-openstack-dev/ubuntu/+source/python-scciclient
+Homepage: https://opendev.org/x/python-scciclient
 
 Package: python-scciclient-doc
 Section: doc
@@ -51,14 +55,15 @@ Description: Python ServerView Common Co
 Package: python3-scciclient
 Architecture: all
 Depends:
- python3-babel,
- python3-oslo.serialization,
- python3-oslo.utils,
- python3-pbr,
- python3-pyghmi,
- python3-pysnmp4,
- python3-requests,
- python3-six,
+ python3-babel (>= 2.3.4),
+ python3-defusedxml (>= 0.7.0),
+ python3-oslo.serialization (>= 2.18.0),
+ python3-oslo.utils (>= 3.33.0),
+ python3-pbr (>= 2.0.0),
+ python3-pyghmi (>= 1.0.24),
+ python3-pysnmp4 (>= 4.2.3),
+ python3-requests (>= 2.14.2),
+ python3-six (>= 1.10.0),
  ${misc:Depends},
  ${python3:Depends},
 Suggests:
diff -pruN 0.8.0-2/debian/gbp.conf 0.12.3-0ubuntu1/debian/gbp.conf
--- 0.8.0-2/debian/gbp.conf	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/debian/gbp.conf	2022-09-09 00:42:26.000000000 +0000
@@ -0,0 +1,7 @@
+[DEFAULT]
+debian-branch = master
+upstream-tag = %(version)s
+pristine-tar = True
+
+[buildpackage]
+export-dir = ../build-area
diff -pruN 0.8.0-2/debian/rules 0.12.3-0ubuntu1/debian/rules
--- 0.8.0-2/debian/rules	2019-07-18 21:52:05.000000000 +0000
+++ 0.12.3-0ubuntu1/debian/rules	2022-09-09 00:42:26.000000000 +0000
@@ -1,16 +1,12 @@
 #!/usr/bin/make -f
 
+export PYBUILD_NAME=scciclient
+
 UPSTREAM_GIT := https://github.com/openstack/python-scciclient.git
 include /usr/share/openstack-pkg-tools/pkgos.make
 
 %:
-	dh $@ --buildsystem=python_distutils --with python3,sphinxdoc
-
-override_dh_auto_clean:
-	echo "Do nothing..."
-
-override_dh_auto_build:
-	echo "Do nothing..."
+	dh $@ --buildsystem=pybuild --with python3,sphinxdoc
 
 override_dh_auto_install:
 	pkgos-dh_auto_install --no-py2
@@ -21,9 +17,20 @@ ifeq (,$(findstring nocheck, $(DEB_BUILD
 endif
 
 override_dh_clean:
-	dh_clean -O--buildsystem=python_distutils
+	dh_clean -O--buildsystem=pybuild
 	rm -rf build
 
 override_dh_sphinxdoc:
-	PYTHONPATH=. python3 -m sphinx -b html doc/source debian/python-scciclient-doc/usr/share/doc/python-scciclient-doc/html
-	dh_sphinxdoc -O--buildsystem=python_distutils
+	PYTHONPATH=. PYTHON=python3 python3 -m sphinx -b html doc/source debian/python-scciclient-doc/usr/share/doc/python-scciclient-doc/html
+	dh_sphinxdoc -O--buildsystem=pybuild
+
+# Commands not to run
+override_dh_installcatalogs:
+override_dh_installemacsen override_dh_installifupdown:
+override_dh_installinfo override_dh_installmenu override_dh_installmime:
+override_dh_installmodules override_dh_installlogcheck:
+override_dh_installpam override_dh_installppp override_dh_installudev override_dh_installwm:
+override_dh_installxfonts override_dh_gconf override_dh_icons override_dh_perl override_dh_usrlocal:
+override_dh_installcron override_dh_installdebconf:
+override_dh_installlogrotate override_dh_installgsettings:
+
diff -pruN 0.8.0-2/debian/watch 0.12.3-0ubuntu1/debian/watch
--- 0.8.0-2/debian/watch	2019-07-18 21:52:05.000000000 +0000
+++ 0.12.3-0ubuntu1/debian/watch	2022-09-09 00:42:26.000000000 +0000
@@ -1,3 +1,3 @@
 version=3
 opts="uversionmangle=s/\.(b|rc)/~$1/" \
-https://github.com/openstack/python-scciclient/tags .*/(\d[\d\.]+)\.tar\.gz
+    http://tarballs.openstack.org/python-scciclient/ python-scciclient-(\d.*)\.tar\.gz
diff -pruN 0.8.0-2/doc/requirements.txt 0.12.3-0ubuntu1/doc/requirements.txt
--- 0.8.0-2/doc/requirements.txt	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/doc/requirements.txt	2022-07-29 10:06:56.000000000 +0000
@@ -0,0 +1,2 @@
+sphinx>=2.0.0,!=2.1.0 # BSD
+openstackdocstheme>=2.2.1 # Apache-2.0
diff -pruN 0.8.0-2/doc/source/conf.py 0.12.3-0ubuntu1/doc/source/conf.py
--- 0.8.0-2/doc/source/conf.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/doc/source/conf.py	2022-07-29 10:06:56.000000000 +0000
@@ -22,8 +22,7 @@ sys.path.insert(0, os.path.abspath('../.
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 extensions = [
     'sphinx.ext.autodoc',
-    #'sphinx.ext.intersphinx',
-    'oslosphinx'
+    'openstackdocstheme'
 ]
 
 # autodoc generation is a bit aggressive and a nuisance when doing heavy
@@ -57,6 +56,7 @@ pygments_style = 'sphinx'
 # html_theme_path = ["."]
 # html_theme = '_theme'
 # html_static_path = ['static']
+html_theme = 'openstackdocs'
 
 # Output file base name for HTML help builder.
 htmlhelp_basename = '%sdoc' % project
@@ -73,3 +73,6 @@ latex_documents = [
 
 # Example configuration for intersphinx: refer to the Python standard library.
 #intersphinx_mapping = {'http://docs.python.org/': None}
+
+# openstackdocstheme options
+openstackdocs_repo_name = 'x/python-scciclient'
diff -pruN 0.8.0-2/.gitignore 0.12.3-0ubuntu1/.gitignore
--- 0.8.0-2/.gitignore	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/.gitignore	1970-01-01 00:00:00.000000000 +0000
@@ -1,57 +0,0 @@
-*.py[cod]
-
-# C extensions
-*.so
-
-# Packages
-*.egg
-*.egg-info
-dist
-build
-eggs
-parts
-bin
-var
-sdist
-develop-eggs
-.installed.cfg
-lib
-lib64
-
-# Installer logs
-pip-log.txt
-
-# Unit test / coverage reports
-.coverage
-.tox
-.stestr/
-.venv
-
-# Translations
-*.mo
-
-# Mr Developer
-.mr.developer.cfg
-.project
-.pydevproject
-
-# Complexity
-output/*.html
-output/*/index.html
-
-# Sphinx
-doc/build
-
-# pbr generates these
-AUTHORS
-ChangeLog
-
-# Editors
-*~
-.*.swp
-.*sw?
-
-# Misc
-
-*.idea
-
diff -pruN 0.8.0-2/.gitreview 0.12.3-0ubuntu1/.gitreview
--- 0.8.0-2/.gitreview	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/.gitreview	1970-01-01 00:00:00.000000000 +0000
@@ -1,4 +0,0 @@
-[gerrit]
-host=review.openstack.org
-port=29418
-project=openstack/python-scciclient.git
diff -pruN 0.8.0-2/lower-constraints.txt 0.12.3-0ubuntu1/lower-constraints.txt
--- 0.8.0-2/lower-constraints.txt	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/lower-constraints.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,56 +0,0 @@
-alabaster==0.7.10
-appdirs==1.3.0
-Babel==2.3.4
-coverage==4.0
-debtcollector==1.2.0
-docutils==0.11
-extras==1.0.0
-fixtures==3.0.0
-flake8==2.5.5
-hacking==0.12.0
-imagesize==0.7.1
-iso8601==0.1.11
-Jinja2==2.10
-keystoneauth1==3.4.0
-linecache2==1.0.0
-MarkupSafe==1.0
-mccabe==0.2.1
-mock==2.0.0
-monotonic==0.6
-mox3==0.20.0
-msgpack-python==0.4.0
-netaddr==0.7.18
-netifaces==0.10.4
-os-client-config==1.28.0
-oslo.i18n==3.15.3
-oslo.serialization==2.18.0
-oslo.utils==3.33.0
-oslosphinx==4.7.0
-oslotest==3.2.0
-pbr==2.0.0
-pep8==1.5.7
-pyasn1==0.1.8
-pycrypto==2.6
-pyflakes==0.8.1
-pyghmi==1.0.22
-Pygments==2.2.0
-pyparsing==2.1.0
-pysnmp==4.2.3
-python-mimeparse==1.6.0
-python-subunit==1.0.0
-pytz==2013.6
-PyYAML==3.12
-requests-mock==1.2.0
-requests==2.14.2
-requestsexceptions==1.2.0
-six==1.10.0
-snowballstemmer==1.2.1
-Sphinx==1.6.2
-sphinxcontrib-websupport==1.0.1
-stevedore==1.20.0
-stestr==2.0.0
-testscenarios==0.4
-testtools==2.2.0
-traceback2==1.4.0
-unittest2==1.1.0
-wrapt==1.7.0
diff -pruN 0.8.0-2/PKG-INFO 0.12.3-0ubuntu1/PKG-INFO
--- 0.8.0-2/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/PKG-INFO	2022-07-29 10:07:36.953071400 +0000
@@ -0,0 +1,33 @@
+Metadata-Version: 1.1
+Name: python-scciclient
+Version: 0.12.3
+Summary: Python ServerView Common Command Interface (SCCI) Client Library
+Home-page: https://opendev.org/x/python-scciclient
+Author: FUJITSU LIMITED
+Author-email: fj-lsoft-scciclient@dl.jp.fujitsu.com
+License: UNKNOWN
+Description: ===============================
+        python-scciclient
+        ===============================
+        
+        Python ServerView Common Command Interface (SCCI) Client Library
+        
+        * Free software: Apache license
+        
+        Features
+        --------
+        
+        * support ServerView Common Command Interface (SCCI) for
+          FUJITSU iRMC S4/S5 -  integrated Remote Management Controller
+        
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Console
+Classifier: Environment :: OpenStack
+Classifier: Intended Audience :: Information Technology
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
diff -pruN 0.8.0-2/python_scciclient.egg-info/dependency_links.txt 0.12.3-0ubuntu1/python_scciclient.egg-info/dependency_links.txt
--- 0.8.0-2/python_scciclient.egg-info/dependency_links.txt	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/python_scciclient.egg-info/dependency_links.txt	2022-07-29 10:07:36.000000000 +0000
@@ -0,0 +1 @@
+
diff -pruN 0.8.0-2/python_scciclient.egg-info/not-zip-safe 0.12.3-0ubuntu1/python_scciclient.egg-info/not-zip-safe
--- 0.8.0-2/python_scciclient.egg-info/not-zip-safe	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/python_scciclient.egg-info/not-zip-safe	2022-07-29 10:07:36.000000000 +0000
@@ -0,0 +1 @@
+
diff -pruN 0.8.0-2/python_scciclient.egg-info/pbr.json 0.12.3-0ubuntu1/python_scciclient.egg-info/pbr.json
--- 0.8.0-2/python_scciclient.egg-info/pbr.json	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/python_scciclient.egg-info/pbr.json	2022-07-29 10:07:36.000000000 +0000
@@ -0,0 +1 @@
+{"git_version": "0940a71", "is_release": true}
\ No newline at end of file
diff -pruN 0.8.0-2/python_scciclient.egg-info/PKG-INFO 0.12.3-0ubuntu1/python_scciclient.egg-info/PKG-INFO
--- 0.8.0-2/python_scciclient.egg-info/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/python_scciclient.egg-info/PKG-INFO	2022-07-29 10:07:36.000000000 +0000
@@ -0,0 +1,33 @@
+Metadata-Version: 1.1
+Name: python-scciclient
+Version: 0.12.3
+Summary: Python ServerView Common Command Interface (SCCI) Client Library
+Home-page: https://opendev.org/x/python-scciclient
+Author: FUJITSU LIMITED
+Author-email: fj-lsoft-scciclient@dl.jp.fujitsu.com
+License: UNKNOWN
+Description: ===============================
+        python-scciclient
+        ===============================
+        
+        Python ServerView Common Command Interface (SCCI) Client Library
+        
+        * Free software: Apache license
+        
+        Features
+        --------
+        
+        * support ServerView Common Command Interface (SCCI) for
+          FUJITSU iRMC S4/S5 -  integrated Remote Management Controller
+        
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Console
+Classifier: Environment :: OpenStack
+Classifier: Intended Audience :: Information Technology
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
diff -pruN 0.8.0-2/python_scciclient.egg-info/requires.txt 0.12.3-0ubuntu1/python_scciclient.egg-info/requires.txt
--- 0.8.0-2/python_scciclient.egg-info/requires.txt	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/python_scciclient.egg-info/requires.txt	2022-07-29 10:07:36.000000000 +0000
@@ -0,0 +1,9 @@
+Babel!=2.4.0,>=2.3.4
+defusedxml>=0.7.0
+oslo.serialization!=2.19.1,>=2.18.0
+oslo.utils>=3.33.0
+pbr!=2.1.0,>=2.0.0
+pyghmi>=1.0.24
+pysnmp>=4.2.3
+requests>=2.14.2
+six>=1.10.0
diff -pruN 0.8.0-2/python_scciclient.egg-info/SOURCES.txt 0.12.3-0ubuntu1/python_scciclient.egg-info/SOURCES.txt
--- 0.8.0-2/python_scciclient.egg-info/SOURCES.txt	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/python_scciclient.egg-info/SOURCES.txt	2022-07-29 10:07:36.000000000 +0000
@@ -0,0 +1,52 @@
+.coveragerc
+.mailmap
+.stestr.conf
+.zuul.yaml
+AUTHORS
+CONTRIBUTING.rst
+ChangeLog
+HACKING.rst
+LICENSE
+MANIFEST.in
+README.rst
+babel.cfg
+openstack-common.conf
+requirements.txt
+setup.cfg
+setup.py
+test-requirements.txt
+tox.ini
+doc/requirements.txt
+doc/source/conf.py
+doc/source/contributing.rst
+doc/source/index.rst
+doc/source/installation.rst
+doc/source/readme.rst
+doc/source/usage.rst
+python_scciclient.egg-info/PKG-INFO
+python_scciclient.egg-info/SOURCES.txt
+python_scciclient.egg-info/dependency_links.txt
+python_scciclient.egg-info/not-zip-safe
+python_scciclient.egg-info/pbr.json
+python_scciclient.egg-info/requires.txt
+python_scciclient.egg-info/top_level.txt
+scciclient/__init__.py
+scciclient/irmc/__init__.py
+scciclient/irmc/elcm.py
+scciclient/irmc/ipmi.py
+scciclient/irmc/scci.py
+scciclient/irmc/snmp.py
+scciclient/irmc/viom/__init__.py
+scciclient/irmc/viom/client.py
+scciclient/irmc/viom/elcm.py
+scciclient/tests/__init__.py
+scciclient/tests/irmc/__init__.py
+scciclient/tests/irmc/test_elcm.py
+scciclient/tests/irmc/test_ipmi.py
+scciclient/tests/irmc/test_scci.py
+scciclient/tests/irmc/test_snmp.py
+scciclient/tests/irmc/fixtures/irmc_report_ng.xml
+scciclient/tests/irmc/fixtures/irmc_report_ok.xml
+scciclient/tests/irmc/viom/__init__.py
+scciclient/tests/irmc/viom/test_client.py
+scciclient/tests/irmc/viom/test_elcm.py
\ No newline at end of file
diff -pruN 0.8.0-2/python_scciclient.egg-info/top_level.txt 0.12.3-0ubuntu1/python_scciclient.egg-info/top_level.txt
--- 0.8.0-2/python_scciclient.egg-info/top_level.txt	1970-01-01 00:00:00.000000000 +0000
+++ 0.12.3-0ubuntu1/python_scciclient.egg-info/top_level.txt	2022-07-29 10:07:36.000000000 +0000
@@ -0,0 +1 @@
+scciclient
diff -pruN 0.8.0-2/README.rst 0.12.3-0ubuntu1/README.rst
--- 0.8.0-2/README.rst	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/README.rst	2022-07-29 10:06:56.000000000 +0000
@@ -10,4 +10,4 @@ Features
 --------
 
 * support ServerView Common Command Interface (SCCI) for
-  FUJITSU iRMC S4 -  integrated Remote Management Controller
+  FUJITSU iRMC S4/S5 -  integrated Remote Management Controller
diff -pruN 0.8.0-2/requirements.txt 0.12.3-0ubuntu1/requirements.txt
--- 0.8.0-2/requirements.txt	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/requirements.txt	2022-07-29 10:06:56.000000000 +0000
@@ -3,9 +3,10 @@
 # process, which may cause wedges in the gate later.
 pbr!=2.1.0,>=2.0.0 # Apache-2.0
 Babel!=2.4.0,>=2.3.4 # BSD
-pyghmi>=1.0.22 # Apache-2.0
+pyghmi>=1.0.24 # Apache-2.0
 pysnmp>=4.2.3 # BSD
 requests>=2.14.2 # Apache-2.0
+defusedxml>=0.7.0 # PSF
 six>=1.10.0 # MIT
 oslo.utils>=3.33.0 # Apache-2.0
 oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
diff -pruN 0.8.0-2/scciclient/irmc/elcm.py 0.12.3-0ubuntu1/scciclient/irmc/elcm.py
--- 0.8.0-2/scciclient/irmc/elcm.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/irmc/elcm.py	2022-07-29 10:06:56.000000000 +0000
@@ -17,11 +17,11 @@ eLCM functionality.
 """
 
 import collections
-import six
 import time
 
 from oslo_serialization import jsonutils
 import requests
+import six
 
 from scciclient.irmc import scci
 
@@ -188,6 +188,10 @@ def elcm_request(irmc_info, method, path
           'irmc_port': 80 or 443, default is 443,
           'irmc_auth_method': 'basic' or 'digest', default is 'basic',
           'irmc_client_timeout': timeout, default is 60,
+          'irmc_verify_ca': Either a boolean, in which case it controls
+                            whether we verify the server's TLS certificate,
+                            or a string, in which case it must be a path to
+                            a CA bundle to use. Defaults to ``False``.
           ...
         }
     :param method: request method such as 'GET', 'POST'
@@ -203,6 +207,7 @@ def elcm_request(irmc_info, method, path
     userid = irmc_info['irmc_username']
     password = irmc_info['irmc_password']
     client_timeout = irmc_info.get('irmc_client_timeout', 60)
+    verify = irmc_info.get('irmc_verify_ca', False)
 
     # Request headers, params, and data
     headers = kwargs.get('headers', {'Accept': 'application/json'})
@@ -229,7 +234,7 @@ def elcm_request(irmc_info, method, path
                              headers=headers,
                              params=params,
                              data=data,
-                             verify=False,
+                             verify=verify,
                              timeout=client_timeout,
                              allow_redirects=False,
                              auth=auth_obj)
@@ -672,8 +677,12 @@ def _process_session_data(irmc_info, ope
                 if operation == 'CONFIG_RAID':
                     return result
 
-                elcm_profile_delete(irmc_info=irmc_info,
-                                    profile_name=PROFILE_BIOS_CONFIG)
+                # FIXME: Currently, creating a profile will restart the
+                # machine, which will cause an error during IPI installation,
+                # so temporarily comment out the operation of deleting the
+                # profile.
+                # elcm_profile_delete(irmc_info=irmc_info,
+                #                    profile_name=PROFILE_BIOS_CONFIG)
 
             except scci.SCCIError as e:
                 result['warning'] = e
@@ -712,31 +721,36 @@ def backup_bios_config(irmc_info):
             'warning': <warning message if there is>
         }
     """
+    result = {}
+
     # 1. Make sure there is no BiosConfig profile in the store
     try:
         # Get the profile first, if not found, then an exception
         # will be raised.
-        elcm_profile_get(irmc_info=irmc_info,
-                         profile_name=PROFILE_BIOS_CONFIG)
+        result['bios_config'] = elcm_profile_get(
+            irmc_info=irmc_info,
+            profile_name=PROFILE_BIOS_CONFIG)
+        # FIXME: Currently, creating a profile will restart the machine,
+        # which will cause an error during IPI installation,
+        # so temporarily comment out the operation of deleting the profile.
         # Profile found, delete it
-        elcm_profile_delete(irmc_info=irmc_info,
-                            profile_name=PROFILE_BIOS_CONFIG)
+        # elcm_profile_delete(irmc_info=irmc_info,
+        #                    profile_name=PROFILE_BIOS_CONFIG)
     except ELCMProfileNotFound:
-        # Ignore this error as it's not an error in this case
-        pass
-
-    # 2. Send request to create a new profile for BiosConfig
-    session = elcm_profile_create(irmc_info=irmc_info,
-                                  param_path=PARAM_PATH_BIOS_CONFIG)
+        # 2. Send request to create a new profile for BiosConfig
+        session = elcm_profile_create(irmc_info=irmc_info,
+                                      param_path=PARAM_PATH_BIOS_CONFIG)
+
+        # 3. Profile creation is in progress, we monitor the session
+        session_timeout = irmc_info.get('irmc_bios_session_timeout',
+                                        BIOS_CONFIG_SESSION_TIMEOUT)
+        return _process_session_data(
+            irmc_info=irmc_info,
+            operation='BACKUP_BIOS',
+            session_id=session['Session']['Id'],
+            session_timeout=session_timeout)
 
-    # 3. Profile creation is in progress, we monitor the session
-    session_timeout = irmc_info.get('irmc_bios_session_timeout',
-                                    BIOS_CONFIG_SESSION_TIMEOUT)
-    return _process_session_data(
-        irmc_info=irmc_info,
-        operation='BACKUP_BIOS',
-        session_id=session['Session']['Id'],
-        session_timeout=session_timeout)
+    return result
 
 
 def restore_bios_config(irmc_info, bios_config):
@@ -771,18 +785,21 @@ def restore_bios_config(irmc_info, bios_
     # 1. Parse the bios config and create the input data
     input_data = _process_bios_config()
 
+    # FIXME: Currently, creating a profile will restart the machine,
+    # which will cause an error during IPI installation,
+    # so temporarily comment out the operation of deleting the profile.
     # 2. Make sure there is no BiosConfig profile in the store
-    try:
-        # Get the profile first, if not found, then an exception
-        # will be raised.
-        elcm_profile_get(irmc_info=irmc_info,
-                         profile_name=PROFILE_BIOS_CONFIG)
-        # Profile found, delete it
-        elcm_profile_delete(irmc_info=irmc_info,
-                            profile_name=PROFILE_BIOS_CONFIG)
-    except ELCMProfileNotFound:
-        # Ignore this error as it's not an error in this case
-        pass
+    # try:
+    #     Get the profile first, if not found, then an exception
+    #     will be raised.
+    #    elcm_profile_get(irmc_info=irmc_info,
+    #                     profile_name=PROFILE_BIOS_CONFIG)
+    #     Profile found, delete it
+    #    elcm_profile_delete(irmc_info=irmc_info,
+    #                        profile_name=PROFILE_BIOS_CONFIG)
+    # except ELCMProfileNotFound:
+    #     Ignore this error as it's not an error in this case
+    #    pass
 
     # 3. Send a request to apply the param values
     session = elcm_profile_set(irmc_info=irmc_info,
@@ -897,7 +914,7 @@ def _update_raid_input_data(target_raid_
             array_info['LogicalDrives']['LogicalDrive'].append(
                 {'@Action': 'Create',
                  'RaidLevel': logical_disk['raid_level'],
-                 'InitMode': 'slow'})
+                 'InitMode': 'fast'})
             array_info['LogicalDrives']['LogicalDrive'][i].update({
                 "@Number": i})
 
@@ -919,7 +936,7 @@ def _update_raid_input_data(target_raid_
                     "ArrayRef": [
                     ]
                 },
-                "InitMode": "slow"
+                "InitMode": "fast"
             }
 
             array_info['Arrays']['Array'].append(arrays)
@@ -1014,7 +1031,7 @@ def create_raid_configuration(irmc_info,
     # create new RAID config.
     raid_adapter = get_raid_adapter(irmc_info)
     logical_drives = raid_adapter['Server']['HWConfigurationIrmc'][
-        'Adapters']['RAIDAdapter'][0]['LogicalDrives']
+        'Adapters']['RAIDAdapter'][0].get('LogicalDrives')
     session_timeout = irmc_info.get('irmc_raid_session_timeout',
                                     RAID_CONFIG_SESSION_TIMEOUT)
     if logical_drives is not None:
@@ -1092,8 +1109,8 @@ def set_bios_configuration(irmc_info, se
     if server_version:
         bios_config_data['Server']['@Version'] = server_version
     if bios_version:
-        bios_config_data['Server']['SystemConfig']['BiosConfig']['@Version'] = \
-            bios_version
+        (bios_config_data['Server']['SystemConfig']['BiosConfig']
+            ['@Version']) = bios_version
 
     configs = {}
     for setting_param in settings:
diff -pruN 0.8.0-2/scciclient/irmc/ipmi.py 0.12.3-0ubuntu1/scciclient/irmc/ipmi.py
--- 0.8.0-2/scciclient/irmc/ipmi.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/irmc/ipmi.py	2022-07-29 10:06:56.000000000 +0000
@@ -90,9 +90,10 @@ def get_tpm_status(d_info):
     # 80 28 00 C0 C0: True
     # 80 28 00 -- --: False (other values than 'C0 C0')
 
-    ipmicmd = ipmi_command.Command(bmc=d_info['irmc_address'],
-                                   userid=d_info['irmc_username'],
-                                   password=d_info['irmc_password'])
+    ipmicmd = ipmi_command.Command(
+        bmc=d_info['irmc_address'],
+        userid=d_info['irmc_username'].encode('utf-8'),
+        password=d_info['irmc_password'].encode('utf-8'))
     try:
         response = _send_raw_command(ipmicmd, GET_TPM_STATUS)
         if response['code'] != 0:
@@ -150,9 +151,10 @@ def get_pci_device(d_info, pci_device_id
     # data1: 2 octet of VendorID
     # data2: 2 octet of DeviceID
 
-    ipmicmd = ipmi_command.Command(bmc=d_info['irmc_address'],
-                                   userid=d_info['irmc_username'],
-                                   password=d_info['irmc_password'])
+    ipmicmd = ipmi_command.Command(
+        bmc=d_info['irmc_address'],
+        userid=d_info['irmc_username'].encode('utf-8'),
+        password=d_info['irmc_password'].encode('utf-8'))
 
     response = itertools.takewhile(
         lambda y: (y[1]['code'] != 0xC9 and y[1].get('error') is None),
diff -pruN 0.8.0-2/scciclient/irmc/scci.py 0.12.3-0ubuntu1/scciclient/irmc/scci.py
--- 0.8.0-2/scciclient/irmc/scci.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/irmc/scci.py	2022-07-29 10:06:56.000000000 +0000
@@ -17,9 +17,10 @@ SCCI functionalities shared between diff
 """
 
 import functools
+import re
 import time
-import xml.etree.ElementTree as ET
 
+import defusedxml.ElementTree as ET
 import requests
 import six
 
@@ -28,6 +29,14 @@ from scciclient.irmc import snmp
 
 DEBUG = False
 
+S4_PATTERN = re.compile(r"^iRMC\s*S4$")
+S5_PATTERN = re.compile(r"^iRMC\s*S5$")
+FW_VERSION_HEAD_PATTERN = re.compile(r"^\d[\d.]*")
+FW_VERSION_TAIL_PATTERN = re.compile(r"[a-zA-Z]*$")
+
+S4_FD_SUPPORT_UPPER = 9.21
+S5_FD_SUPPORT_UPPER = 1.25
+
 
 class SCCIError(Exception):
     """SCCI Error
@@ -68,8 +77,13 @@ class SCCIRAIDNotReady(SCCIError):
         super(SCCIRAIDNotReady, self).__init__(message)
 
 
+class SCCISessionTimeout(SCCIError):
+    def __init__(self, message):
+        super(SCCISessionTimeout, self).__init__(message)
+
+
 """
-List of iRMC S4 supported SCCI commands
+List of iRMC S4/S5 supported SCCI commands
 
 SCCI
 OpCode  SCCI Command String      Description
@@ -85,6 +99,14 @@ OpCode  SCCI Command String      Descrip
 0x0203  ResetFirmware  Perform a BMC Reset
 0x0251  ConnectRemoteFdImage     Connect or Disconnect a Floppy Disk image on a
                                  Remote Image Mount (NFS or CIFS Share )
+
+                                 This command was deprecated at following
+                                 version:
+                                   iRMC S4: 9.62F
+                                            (9.21F still supports virtual FD)
+                                   iRMC S5: 1.60P
+                                            (1.25P still supports virtual FD)
+
 0x0252  ConnectRemoteCdImage     Connect or Disconnect a CD/DVD .iso image on a
                                  Remote Image Mount (NFS or CIFS Share )
 0x0253  ConnectRemoteHdImage     Connect or Disconnect a Hard Disk image on a
@@ -242,7 +264,7 @@ def get_share_type(share_type):
 
 
 def scci_cmd(host, userid, password, cmd, port=443, auth_method='basic',
-             client_timeout=60, do_async=True, **kwargs):
+             client_timeout=60, do_async=True, verify=False, **kwargs):
     """execute SCCI command
 
     This function calls SCCI server modules
@@ -254,6 +276,10 @@ def scci_cmd(host, userid, password, cmd
     :param auth_method: irmc_username
     :param client_timeout: timeout for SCCI operations
     :param do_async: async call if True, sync call otherwise
+    :param verify: (optional) Either a boolean, in which case it
+                    controls whether we verify the server's TLS certificate,
+                    or a string, in which case it must be a path to
+                    a CA bundle to use. Defaults to ``False``.
     :returns: requests.Response from SCCI server
     :raises: SCCIInvalidInputError if port and/or auth_method params
              are invalid
@@ -275,15 +301,51 @@ def scci_cmd(host, userid, password, cmd
 
     try:
         header = {'Content-type': 'application/x-www-form-urlencoded'}
-        r = requests.post(protocol + '://' + host + '/config',
-                          data=cmd,
+        if kwargs.get('upgrade_type') == 'irmc':
+            with open(cmd, 'rb') as file:
+                data = file.read()
+            config_type = '/irmcupdate?flashSelect=255'
+        elif kwargs.get('upgrade_type') == 'bios':
+            with open(cmd, 'rb') as file:
+                data = file.read()
+            config_type = '/biosupdate'
+        else:
+            # For EJECT command, validate parameters to handle abnormal case
+            if check_eject_cd_cmd(cmd):
+                if not validate_params_cd_fd("cmd_cd", protocol,
+                                             host, auth_obj,
+                                             do_async, client_timeout,
+                                             verify):
+                    return
+            if check_eject_fd_cmd(cmd):
+                if not validate_params_cd_fd("cmd_fd", protocol,
+                                             host, auth_obj,
+                                             do_async, client_timeout,
+                                             verify):
+                    return
+            data = cmd
+            config_type = '/config'
+
+        r = requests.post(protocol + '://' + host + config_type,
+                          data=data,
                           headers=header,
-                          verify=False,
+                          verify=verify,
                           timeout=client_timeout,
                           allow_redirects=False,
                           auth=auth_obj)
+
         if not do_async:
             time.sleep(5)
+        else:
+            # Async mode
+            # Even in async mode, return immediately may cause error 5
+            # (Input/Output error) for some commands such as POWER_ON,
+            # POWER_OFF, POWER_RESET if we perform multiple calls of them
+            # in a tight sequence or in parallel.
+            # So, we sleep some time for such commands.
+            if cmd in (POWER_ON, POWER_OFF, POWER_RESET):
+                time.sleep(3)
+
         if DEBUG:
             print(cmd)
             print(r.text)
@@ -306,6 +368,9 @@ def scci_cmd(host, userid, password, cmd
         else:
             return r
 
+    except IOError as input_error:
+        raise SCCIClientError(input_error)
+
     except ET.ParseError as parse_error:
         raise SCCIClientError(parse_error)
 
@@ -313,8 +378,125 @@ def scci_cmd(host, userid, password, cmd
         raise SCCIClientError(requests_exception)
 
 
+def validate_params_cd_fd(cmd_type, protocol, host, auth_obj,
+                          do_async, client_timeout, verify):
+    """Validate parameters of CD/DVD or FD Image Virtual Media in iRMC
+
+    If one of parameters (ImageServer, ImageShareName or ImageName) set in
+    ServerView Config Space is empty, and you try to eject virtual FD/CD,
+    iRMC returns error. This function determines whether iRMC doesn't return
+    error when you try to eject virtual FD/CD.
+    :param cmd_type: command type has value switch between "cmd_cd" or "cmd_fd"
+    :param protocol:
+    :param host: hostname or IP of iRMC
+    :param auth_obj: irmc userid/password
+    :param do_async: async call if True, sync call otherwise
+    :param client_timeout: timeout for SCCI operations
+    :param verify: Either a boolean, in which case it
+                   controls whether we verify the server's TLS certificate,
+                   or a string, in which case it must be a path to
+                   a CA bundle to use.
+    :return: False if one of param is null. Otherwise, returns True.
+    """
+
+    if cmd_type == "cmd_cd":
+        oe_image_server = "1A60"
+        oe_image_server_share_name = "1A65"
+        oe_image_name = "1A66"
+    else:
+        oe_image_server = "1A50"
+        oe_image_server_share_name = "1A55"
+        oe_image_name = "1A56"
+
+    try:
+        param = {'P45': '1', 'SAVE_DATA': '1'}
+        header = {'Content-type': 'application/x-www-form-urlencoded'}
+        r = requests.get(protocol + '://' + host + '/iRMC_Settings.pre',
+                         params=param,
+                         headers=header,
+                         verify=verify,
+                         timeout=client_timeout,
+                         allow_redirects=False,
+                         auth=auth_obj)
+        if not do_async:
+            time.sleep(5)
+
+        if DEBUG:
+            print("---------------------------")
+            print("Current iRMC configuration:")
+            print(r.url)
+
+        if r.status_code not in (200, 201):
+            raise SCCIClientError(
+                ('HTTP PROTOCOL ERROR, STATUS CODE = %s' %
+                 str(r.status_code)))
+
+        result = r.text
+        cmdseq = ET.fromstring(result)
+        cfg_dict = {}
+        for cmd_tag in cmdseq.iter(tag='CMD'):
+            oe = cmd_tag.get('OE')
+            data = cmd_tag.find('DATA').text
+            cfg_dict[oe] = data
+
+        if DEBUG:
+            print("Server: ", cfg_dict[oe_image_server])
+            print("Share Name: ", cfg_dict[oe_image_server_share_name])
+            print("Image Name: ", cfg_dict[oe_image_name])
+            print("---------------------------")
+
+        if (cfg_dict[oe_image_server] is None) or \
+                (cfg_dict[oe_image_server_share_name] is None) or \
+                (cfg_dict[oe_image_name] is None):
+            return False
+
+    except ET.ParseError as parse_error:
+        raise SCCIClientError(parse_error)
+    except requests.exceptions.RequestException as requests_exception:
+        raise SCCIClientError(requests_exception)
+
+    return True
+
+
+def check_eject_cd_cmd(xml_cmd):
+    """To check command is MOUNT or UNMOUNT
+
+    :param xml_cmd: the command
+    :return: true if this is UNMOUNT command. Otherwise, return false.
+    """
+
+    try:
+        cmdseq = ET.fromstring(xml_cmd.strip())
+        cmd = cmdseq.find("./CMD")
+        data = cmd.find("./DATA")
+        if cmd.get("OC") == "ConnectRemoteCdImage" and \
+                cmd.get("Type") == "SET" and data.text == "0":
+            return True
+    except ET.ParseError as parse_error:
+        raise SCCIClientError(parse_error)
+    return False
+
+
+def check_eject_fd_cmd(xml_cmd):
+    """To check command is MOUNT or UNMOUNT
+
+    :param xml_cmd: the command
+    :return: true if this is UNMOUNT command. Otherwise, return false.
+    """
+    try:
+        cmdseq = ET.fromstring(xml_cmd.strip())
+        cmd = cmdseq.find("./CMD")
+        data = cmd.find("./DATA")
+        if cmd.get("OC") == "ConnectRemoteFdImage" and \
+                cmd.get("Type") == "SET" and data.text == "0":
+            return True
+    except ET.ParseError as parse_error:
+        raise SCCIClientError(parse_error)
+    return False
+
+
 def get_client(host, userid, password, port=443, auth_method='basic',
-               client_timeout=60, **kwargs):
+               client_timeout=60, verify=False, **kwargs):
     """get SCCI command partial function
 
     This function returns SCCI command partial function
@@ -324,12 +506,17 @@ def get_client(host, userid, password, p
     :param port: port number of iRMC
     :param auth_method: irmc_username
     :param client_timeout: timeout for SCCI operations
+    :param verify: (optional) Either a boolean, in which case it
+                    controls whether we verify the server's TLS certificate,
+                    or a string, in which case it must be a path to
+                    a CA bundle to use. Defaults to ``False``.
     :returns: scci_cmd partial function which takes a SCCI command param
     """
 
     return functools.partial(scci_cmd, host, userid, password,
                              port=port, auth_method=auth_method,
-                             client_timeout=client_timeout, **kwargs)
+                             client_timeout=client_timeout,
+                             verify=verify, **kwargs)
 
 
 def get_virtual_cd_set_params_cmd(remote_image_server,
@@ -396,7 +583,7 @@ def get_virtual_fd_set_params_cmd(remote
 
 
 def get_report(host, userid, password,
-               port=443, auth_method='basic', client_timeout=60):
+               port=443, auth_method='basic', client_timeout=60, verify=False):
     """get iRMC report
 
     This function returns iRMC report in XML format
@@ -406,6 +593,10 @@ def get_report(host, userid, password,
     :param port: port number of iRMC
     :param auth_method: irmc_username
     :param client_timeout: timeout for SCCI operations
+    :param verify: (optional) Either a boolean, in which case it
+                    controls whether we verify the server's TLS certificate,
+                    or a string, in which case it must be a path to
+                    a CA bundle to use. Defaults to ``False``.
     :returns: root element of SCCI report
     :raises: ISCCIInvalidInputError if port and/or auth_method params
              are invalid
@@ -428,7 +619,7 @@ def get_report(host, userid, password,
 
     try:
         r = requests.get(protocol + '://' + host + '/report.xml',
-                         verify=False,
+                         verify=verify,
                          timeout=(10, client_timeout),
                          allow_redirects=False,
                          auth=auth_obj)
@@ -457,7 +648,6 @@ def get_sensor_data_records(report):
     """
 
     sensor = report.find("./System/SensorDataRecords")
-    # ET.dump(sensor[0])
     return sensor
 
 
@@ -470,10 +660,56 @@ def get_irmc_version(report):
     """
 
     version = report.find("./System/ManagementControllers/iRMC")
-    # ET.dump(version[0])
     return version
 
 
+def get_irmc_version_str(report):
+    """extract iRMC OS and iRMC firmware version from SCCI report
+
+    This function returns iRMC OS name and iRMC firmware version
+    :param report: SCCI report element
+    :returns: a tuple of string (iRMC OS name, iRMC FW version)
+    """
+
+    version = get_irmc_version(report)
+    return version.get('Name'), version.find('Firmware').text
+
+
+def support_virtual_fd_str(irmc_os, fw_version):
+    """determine iRMC supports virtual floppy disk
+
+    This function determines whether iRMC supports virtual floppy disk
+    based on provided iRMC OS & iRMC firmware version
+    :param irmc_os: string representing iRMC OS
+    :param fw_version: string representing iRMC firmware version
+    :returns: boolean
+    """
+
+    version_head = FW_VERSION_HEAD_PATTERN.match(fw_version)
+
+    if S4_PATTERN.match(irmc_os):
+        if version_head and float(version_head.group()) <= S4_FD_SUPPORT_UPPER:
+            return True
+    elif S5_PATTERN.match(irmc_os):
+        if version_head and float(version_head.group()) <= S5_FD_SUPPORT_UPPER:
+            return True
+
+    return False
+
+
+def support_virtual_fd(report):
+    """determine iRMC supports virtual floppy disk
+
+    This function determines whether iRMC supports virtual floppy disk
+    based on SCCI report
+    :param report: SCCI report element
+    :returns: boolean
+    """
+
+    irmc_os, fwv = get_irmc_version_str(report)
+    return support_virtual_fd_str(irmc_os, fwv)
+
+
 def get_essential_properties(report, prop_keys):
     """get essential properties
 
@@ -521,11 +757,17 @@ def get_capabilities_properties(d_info,
     :returns: a dictionary which contains keys and their values.
     """
 
-    snmp_client = snmp.SNMPClient(d_info['irmc_address'],
-                                  d_info['irmc_snmp_port'],
-                                  d_info['irmc_snmp_version'],
-                                  d_info['irmc_snmp_community'],
-                                  d_info['irmc_snmp_security'])
+    snmp_client = snmp.SNMPClient(
+        address=d_info['irmc_address'],
+        port=d_info['irmc_snmp_port'],
+        version=d_info['irmc_snmp_version'],
+        read_community=d_info['irmc_snmp_community'],
+        user=d_info.get('irmc_snmp_user'),
+        auth_proto=d_info.get('irmc_snmp_auth_proto'),
+        auth_key=d_info.get('irmc_snmp_auth_password'),
+        priv_proto=d_info.get('irmc_snmp_priv_proto'),
+        priv_key=d_info.get('irmc_snmp_priv_password'))
+
     try:
         v = {}
         if 'rom_firmware_version' in capa_keys:
@@ -560,6 +802,54 @@ def get_capabilities_properties(d_info,
         raise SCCIClientError('Capabilities inspection failed: %s' % err)
 
 
+def process_session_status(irmc_info, session_timeout, upgrade_type):
+    """process session for Bios config backup/restore or RAID config operation
+
+    :param irmc_info: node info
+    :param session_timeout: session timeout
+    :param upgrade_type: flag to check upgrade with bios or irmc
+    :return: a dict with following values:
+        {
+            'upgrade_message': <Message of firmware upgrade mechanism>,
+            'upgrade_status'
+        }
+    """
+    session_expiration = time.time() + session_timeout
+
+    while time.time() < session_expiration:
+        try:
+            # Get session status to check
+            session = get_firmware_upgrade_status(irmc_info, upgrade_type)
+        except SCCIClientError:
+            # Ignore checking during rebooted server
+            time.sleep(10)
+            continue
+
+        status = session.find("./Value").text
+        severity = session.find("./Severity").text
+        message = session.find("./Message").text
+        result = {}
+
+        if severity == 'Information' and status != '0':
+            if 'FLASH successful' in message:
+                result['upgrade_status'] = 'Complete'
+                return result
+            # Sleep a bit
+            time.sleep(5)
+        elif severity == 'Error':
+            result['upgrade_status'] = 'Error'
+            return result
+        else:
+            # Error occurred, get session log to see what happened
+            session_log = message
+            raise SCCIClientError('Failed to set firmware upgrade. '
+                                  'Session log is %s.' % session_log)
+
+    else:
+        raise SCCISessionTimeout('Failed to time out mechanism with %s.'
+                                 % session_expiration)
+
+
 def get_raid_fgi_status(report):
     """Gather fgi(foreground initialization) information of raid configuration
 
@@ -590,3 +880,71 @@ def get_raid_fgi_status(report):
         fgi_status.update({name: status})
 
     return fgi_status
+
+
+def get_firmware_upgrade_status(irmc_info, upgrade_type):
+    """get firmware upgrade status of bios or irmc
+
+    :param irmc_info: dict of iRMC params to access the server node
+        {
+          'irmc_address': host,
+          'irmc_username': user_id,
+          'irmc_password': password,
+          'irmc_port': 80 or 443, default is 443,
+          'irmc_auth_method': 'basic' or 'digest', default is 'digest',
+          'irmc_client_timeout': timeout, default is 60,
+          'irmc_verify_ca': (optional) Either a boolean, in which case it
+                            controls whether we verify the server's TLS
+                            certificate, or a string, in which case it
+                            must be a path to a CA bundle to use.
+                            Defaults to ``False``.
+          ...
+        }
+    :param upgrade_type: flag to check upgrade with bios or irmc
+    :raises: ISCCIInvalidInputError if port and/or auth_method params
+             are invalid
+    :raises: SCCIClientError if SCCI failed
+    """
+
+    host = irmc_info.get('irmc_address')
+    userid = irmc_info.get('irmc_username')
+    password = irmc_info.get('irmc_password')
+    port = irmc_info.get('irmc_port', 443)
+    auth_method = irmc_info.get('irmc_auth_method', 'digest')
+    client_timeout = irmc_info.get('irmc_client_timeout', 60)
+    verify = irmc_info.get('irmc_verify_ca', False)
+
+    auth_obj = None
+    try:
+        protocol = {80: 'http', 443: 'https'}[port]
+        auth_obj = {
+            'basic': requests.auth.HTTPBasicAuth(userid, password),
+            'digest': requests.auth.HTTPDigestAuth(userid, password)
+        }[auth_method.lower()]
+    except KeyError:
+        raise SCCIInvalidInputError(
+            ("Invalid port %(port)d or " +
+             "auth_method for method %(auth_method)s") %
+            {'port': port, 'auth_method': auth_method})
+    try:
+        if upgrade_type == 'bios':
+            upgrade_type = '/biosprogress'
+        elif upgrade_type == 'irmc':
+            upgrade_type = '/irmcprogress'
+        r = requests.get(protocol + '://' + host + upgrade_type,
+                         verify=verify,
+                         timeout=(10, client_timeout),
+                         allow_redirects=False,
+                         auth=auth_obj)
+
+        if r.status_code not in (200, 201):
+            raise SCCIClientError(
+                ('HTTP PROTOCOL ERROR, STATUS CODE = %s' %
+                 str(r.status_code)))
+
+        upgrade_status_xml = ET.fromstring(r.text)
+        return upgrade_status_xml
+    except ET.ParseError as parse_error:
+        raise SCCIClientError(parse_error)
+    except requests.RequestException as requests_exception:
+        raise SCCIClientError(requests_exception)
diff -pruN 0.8.0-2/scciclient/irmc/snmp.py 0.12.3-0ubuntu1/scciclient/irmc/snmp.py
--- 0.8.0-2/scciclient/irmc/snmp.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/irmc/snmp.py	2022-07-29 10:06:56.000000000 +0000
@@ -12,10 +12,10 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+from pysnmp import error as snmp_error
+from pysnmp import hlapi as snmp
 import six
 
-from pysnmp.entity.rfc3413.oneliner import cmdgen
-from pysnmp import error as snmp_error
 
 BMC_NAME_OID = '1.3.6.1.4.1.231.2.10.2.2.10.3.4.1.3.1.1'
 IRMC_FW_VERSION_OID = '1.3.6.1.4.1.231.2.10.2.2.10.3.4.1.4.1.1'
@@ -125,42 +125,76 @@ class SNMPClient(object):
     interaction with PySNMP to simplify dynamic importing and unit testing.
     """
 
-    def __init__(self, address, port, version, community=None, security=None):
+    def __init__(self, address, port, version,
+                 read_community=None, write_community=None,
+                 user=None, auth_proto=None, auth_key=None,
+                 priv_proto=None, priv_key=None,
+                 context_engine_id=None, context_name=None):
         self.address = address
         self.port = port
         self.version = version
         if self.version == SNMP_V3:
-            self.security = security
+            self.user = user
+            self.auth_proto = auth_proto
+            self.auth_key = auth_key
+            self.priv_proto = priv_proto
+            self.priv_key = priv_key
         else:
-            self.community = community
-        self.cmd_gen = cmdgen.CommandGenerator()
+            self.read_community = read_community
+            self.write_community = write_community
+
+        self.context_engine_id = context_engine_id
+        self.context_name = context_name or ''
+        self.snmp_engine = snmp.SnmpEngine()
 
-    def _get_auth(self):
+    def _get_auth(self, write_mode=False):
         """Return the authorization data for an SNMP request.
 
-        :returns: A
-            :class:`pysnmp.entity.rfc3413.oneliner.cmdgen.CommunityData`
-            object.
+        :param write_mode: `True` if write class SNMP command is
+            executed. Default is `False`.
+        :returns: Either
+            :class:`pysnmp.hlapi.CommunityData`
+            or :class:`pysnmp.hlapi.UsmUserData`
+            object depending on SNMP version being used.
         """
         if self.version == SNMP_V3:
             # Handling auth/encryption credentials is not (yet) supported.
             # This version supports a security name analogous to community.
-            return cmdgen.UsmUserData(self.security)
+            return snmp.UsmUserData(self.user,
+                                    authKey=self.auth_key,
+                                    authProtocol=self.auth_proto,
+                                    privKey=self.priv_key,
+                                    privProtocol=self.priv_proto)
         else:
             mp_model = 1 if self.version == SNMP_V2C else 0
-            return cmdgen.CommunityData(self.community, mpModel=mp_model)
+            return snmp.CommunityData(
+                self.write_community if write_mode else self.read_community,
+                mpModel=mp_model
+            )
 
     def _get_transport(self):
         """Return the transport target for an SNMP request.
 
         :returns: A :class:
-            `pysnmp.entity.rfc3413.oneliner.cmdgen.UdpTransportTarget` object.
-        :raises: snmp_error.PySnmpError if the transport address is bad.
+            `pysnmp.hlapi.UdpTransportTarget` object.
+        :raises: :class:`pysnmp.error.PySnmpError` if the transport address
+            is bad.
         """
         # The transport target accepts timeout and retries parameters, which
         # default to 1 (second) and 5 respectively. These are deemed sensible
         # enough to allow for an unreliable network or slow device.
-        return cmdgen.UdpTransportTarget((self.address, self.port))
+        return snmp.UdpTransportTarget((self.address, self.port))
+
+    def _get_context(self):
+        """Return the SNMP context for an SNMP request.
+
+        :returns: A :class:
+            `pysnmp.hlapi.ContextData` object.
+        :raises: :class:`pysnmp.error.PySnmpError` if SNMP context data
+            is bad.
+        """
+        return snmp.ContextData(contextEngineId=self.context_engine_id,
+                                contextName=self.context_name)
 
     def get(self, oid):
         """Use PySNMP to perform an SNMP GET operation on a single object.
@@ -170,13 +204,15 @@ class SNMPClient(object):
         :returns: The value of the requested object.
         """
         try:
-            results = self.cmd_gen.getCmd(self._get_auth(),
-                                          self._get_transport(),
-                                          oid)
+            snmp_gen = snmp.getCmd(self.snmp_engine,
+                                   self._get_auth(),
+                                   self._get_transport(),
+                                   self._get_context(),
+                                   snmp.ObjectType(snmp.ObjectIdentity(oid)))
         except snmp_error.PySnmpError as e:
             raise SNMPFailure(SNMP_FAILURE_MSG % ("GET", e))
 
-        error_indication, error_status, error_index, var_binds = results
+        error_indication, error_status, error_index, var_binds = next(snmp_gen)
 
         if error_indication:
             # SNMP engine-level error.
@@ -189,8 +225,7 @@ class SNMPClient(object):
                 " %(index)s" %
                 {'operation': "GET", 'error': error_status.prettyPrint(),
                  'index':
-                     error_index and var_binds[int(error_index) - 1]
-                     or '?'})
+                     error_index and var_binds[int(error_index) - 1] or '?'})
 
         # We only expect a single value back
         name, val = var_binds[0]
@@ -204,30 +239,38 @@ class SNMPClient(object):
         :returns: A list of values of the requested table object.
         """
         try:
-            results = self.cmd_gen.nextCmd(self._get_auth(),
-                                           self._get_transport(),
-                                           oid)
+            snmp_gen = snmp.nextCmd(self.snmp_engine,
+                                    self._get_auth(),
+                                    self._get_transport(),
+                                    self._get_context(),
+                                    snmp.ObjectType(snmp.ObjectIdentity(oid)),
+                                    lexicographicMode=False)
         except snmp_error.PySnmpError as e:
             raise SNMPFailure(SNMP_FAILURE_MSG % ("GET_NEXT", e))
 
-        error_indication, error_status, error_index, var_binds = results
+        vals = []
+        for (error_indication, error_status, error_index,
+                var_binds) in snmp_gen:
+            if error_indication:
+                # SNMP engine-level error.
+                raise SNMPFailure(SNMP_FAILURE_MSG % ("GET_NEXT",
+                                                      error_indication))
+
+            if error_status:
+                # SNMP PDU error.
+                raise SNMPFailure(
+                    "SNMP operation '%(operation)s' failed: %(error)s at"
+                    " %(index)s" %
+                    {'operation': "GET_NEXT",
+                     'error': error_status.prettyPrint(),
+                     'index':
+                        error_index and var_binds[int(error_index) - 1]
+                        or '?'})
 
-        if error_indication:
-            # SNMP engine-level error.
-            raise SNMPFailure(
-                SNMP_FAILURE_MSG % ("GET_NEXT", error_indication))
-
-        if error_status:
-            # SNMP PDU error.
-            raise SNMPFailure(
-                "SNMP operation '%(operation)s' failed: %(error)s at"
-                " %(index)s" %
-                {'operation': "GET_NEXT", 'error': error_status.prettyPrint(),
-                 'index':
-                     error_index and var_binds[int(error_index) - 1]
-                     or '?'})
+            name, value = var_binds[0]
+            vals.append(value)
 
-        return [val for row in var_binds for name, val in row]
+        return vals
 
     def set(self, oid, value):
         """Use PySNMP to perform an SNMP SET operation on a single object.
@@ -237,13 +280,16 @@ class SNMPClient(object):
         :raises: SNMPFailure if an SNMP request fails.
         """
         try:
-            results = self.cmd_gen.setCmd(self._get_auth(),
-                                          self._get_transport(),
-                                          (oid, value))
+            snmp_gen = snmp.setCmd(self.snmp_engine,
+                                   self._get_auth(write_mode=True),
+                                   self._get_transport(),
+                                   self._get_context(),
+                                   snmp.ObjectType(snmp.ObjectIdentity(oid),
+                                                   value))
         except snmp_error.PySnmpError as e:
             raise SNMPFailure(SNMP_FAILURE_MSG % ("SET", e))
 
-        error_indication, error_status, error_index, var_binds = results
+        error_indication, error_status, error_index, var_binds = next(snmp_gen)
 
         if error_indication:
             # SNMP engine-level error.
@@ -256,5 +302,4 @@ class SNMPClient(object):
                 " %(index)s" %
                 {'operation': "SET", 'error': error_status.prettyPrint(),
                  'index':
-                     error_index and var_binds[int(error_index) - 1]
-                     or '?'})
+                     error_index and var_binds[int(error_index) - 1] or '?'})
diff -pruN 0.8.0-2/scciclient/irmc/viom/client.py 0.12.3-0ubuntu1/scciclient/irmc/viom/client.py
--- 0.8.0-2/scciclient/irmc/viom/client.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/irmc/viom/client.py	2022-07-29 10:06:56.000000000 +0000
@@ -14,10 +14,11 @@
 
 import abc
 import re
-import six
 import socket
 import struct
 
+import six
+
 from scciclient.irmc import scci
 from scciclient.irmc.viom import elcm
 
diff -pruN 0.8.0-2/scciclient/tests/irmc/test_elcm.py 0.12.3-0ubuntu1/scciclient/tests/irmc/test_elcm.py
--- 0.8.0-2/scciclient/tests/irmc/test_elcm.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/tests/irmc/test_elcm.py	2022-07-29 10:06:56.000000000 +0000
@@ -16,7 +16,8 @@
 Test class for iRMC eLCM functionality.
 """
 
-import mock
+from unittest import mock
+
 from oslo_utils import encodeutils
 import requests
 from requests_mock.contrib import fixture as rm_fixture
@@ -852,7 +853,7 @@ class ELCMTestCase(testtools.TestCase):
 
         self.assertEqual(2, mock_sleep.call_count)
         self.assertEqual(1, mock_session_delete.call_count)
-        self.assertEqual(1, mock_profile_delete.call_count)
+        self.assertEqual(0, mock_profile_delete.call_count)
 
     @mock.patch.object(elcm, 'elcm_profile_delete')
     @mock.patch.object(elcm, 'elcm_profile_get')
@@ -884,7 +885,7 @@ class ELCMTestCase(testtools.TestCase):
         mock_profile_get.assert_not_called()
         self.assertEqual(2, mock_sleep.call_count)
         self.assertEqual(1, mock_session_delete.call_count)
-        self.assertEqual(1, mock_profile_delete.call_count)
+        self.assertEqual(0, mock_profile_delete.call_count)
 
     @mock.patch.object(elcm, 'elcm_profile_delete')
     @mock.patch.object(elcm, 'elcm_profile_get')
@@ -971,12 +972,12 @@ class ELCMTestCase(testtools.TestCase):
         result = elcm.backup_bios_config(irmc_info=self.irmc_info)
         self.assertEqual(expected_bios_cfg, result['bios_config'])
 
-        self.assertEqual(2, mock_sleep.call_count)
-        self.assertEqual(True, mock_session_get.called)
-        self.assertEqual(1, mock_session_delete.call_count)
-        self.assertEqual(2, mock_profile_get.call_count)
-        self.assertEqual(1, mock_profile_create.call_count)
-        self.assertEqual(2, mock_profile_delete.call_count)
+        self.assertEqual(0, mock_sleep.call_count)
+        self.assertEqual(False, mock_session_get.called)
+        self.assertEqual(0, mock_session_delete.call_count)
+        self.assertEqual(1, mock_profile_get.call_count)
+        self.assertEqual(0, mock_profile_create.call_count)
+        self.assertEqual(0, mock_profile_delete.call_count)
 
     @mock.patch.object(elcm, 'elcm_profile_delete')
     @mock.patch.object(elcm, 'elcm_profile_get')
@@ -1005,9 +1006,9 @@ class ELCMTestCase(testtools.TestCase):
         self.assertEqual(2, mock_sleep.call_count)
         self.assertEqual(True, mock_session_get.called)
         self.assertEqual(1, mock_session_delete.call_count)
-        self.assertEqual(1, mock_profile_get.call_count)
+        self.assertEqual(0, mock_profile_get.call_count)
         self.assertEqual(1, mock_profile_set.call_count)
-        self.assertEqual(2, mock_profile_delete.call_count)
+        self.assertEqual(0, mock_profile_delete.call_count)
 
     def test_restore_bios_config_ok_with_dict(self):
         bios_cfg = {
@@ -1155,6 +1156,76 @@ class ELCMTestCase(testtools.TestCase):
     @mock.patch.object(elcm, 'get_raid_adapter')
     @mock.patch.object(elcm, 'elcm_profile_set')
     @mock.patch.object(elcm, '_process_session_data')
+    def test_create_raid_config_without_logical_drives(
+            self, session_mock, elcm_profile_set_mock, raid_info_mock):
+        elcm_profile_set_mock.return_value = {
+            "Session": {
+                "Id": 1,
+                "A_Param": "abc123"
+            }
+        }
+        session_id = 1
+        session_timeout = 1800
+        operation = 'CONFIG_RAID'
+
+        target_raid_config = {
+            'logical_disks': [
+                {
+                    'size_gb': 100,
+                    'raid_level': '1',
+                }
+            ]
+        }
+        expected_input = {
+            'Server': {
+                'HWConfigurationIrmc': {
+                    '@Processing': 'execute',
+                    'Adapters': {
+                        'RAIDAdapter': [
+                            {
+                                'Arrays': {
+                                    'Array': []
+                                },
+                                'LogicalDrives': {
+                                    'LogicalDrive': [
+                                        {
+                                            '@Number': 0,
+                                            '@Action': 'Create',
+                                            'RaidLevel': '1',
+                                            'InitMode': 'fast',
+                                            'Size': {
+                                                '@Unit': 'GB',
+                                                '#text': 100
+                                            },
+                                        }
+                                    ]
+                                }
+                            }
+                        ]
+                    },
+                    '@Version': '1.00'
+                },
+                '@Version': '1.01'
+            }
+        }
+        # In case of "LogicalDrives" doesn't exist
+        del self.raid_info['Server']['HWConfigurationIrmc'][
+            'Adapters']['RAIDAdapter'][0]['LogicalDrives']
+        raid_info_mock.return_value = self.raid_info
+
+        elcm.create_raid_configuration(
+            self.irmc_info, target_raid_config=target_raid_config)
+
+        session_mock.assert_called_once_with(self.irmc_info, operation,
+                                             session_id, session_timeout)
+        # Check raid_input data
+        raid_info_mock.assert_called_once_with(self.irmc_info)
+        elcm_profile_set_mock.assert_called_once_with(
+            self.irmc_info, expected_input)
+
+    @mock.patch.object(elcm, 'get_raid_adapter')
+    @mock.patch.object(elcm, 'elcm_profile_set')
+    @mock.patch.object(elcm, '_process_session_data')
     def test_create_raid_config_without_arrays_info_and_physical_disks(
             self, session_mock, elcm_profile_set_mock, raid_info_mock):
 
@@ -1185,7 +1256,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 0,
                                             '@Action': 'Create',
                                             'RaidLevel': '1',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1244,7 +1315,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 0,
                                             '@Action': 'Create',
                                             'RaidLevel': '0',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1254,7 +1325,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 1,
                                             '@Action': 'Create',
                                             'RaidLevel': '1',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1342,7 +1413,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 0,
                                             '@Action': 'Create',
                                             'RaidLevel': '1',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1451,7 +1522,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 0,
                                             '@Action': 'Create',
                                             'RaidLevel': '0',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1468,7 +1539,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 1,
                                             '@Action': 'Create',
                                             'RaidLevel': '1',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1592,7 +1663,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 0,
                                             '@Action': 'Create',
                                             'RaidLevel': '1',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1662,7 +1733,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 0,
                                             '@Action': 'Create',
                                             'RaidLevel': '0',
-                                            'InitMode': 'slow'
+                                            'InitMode': 'fast'
                                         }
                                     ]
                                 }
@@ -1739,7 +1810,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 0,
                                             '@Action': 'Create',
                                             'RaidLevel': '0',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1750,7 +1821,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 1,
                                             '@Action': 'Create',
                                             'RaidLevel': '1',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1834,7 +1905,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 0,
                                             '@Action': 'Create',
                                             'RaidLevel': '10',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1904,7 +1975,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 0,
                                             '@Action': 'Create',
                                             'RaidLevel': '50',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -1986,7 +2057,7 @@ class ELCMTestCase(testtools.TestCase):
                                             '@Number': 0,
                                             '@Action': 'None',
                                             'RaidLevel': '0',
-                                            'InitMode': 'slow',
+                                            'InitMode': 'fast',
                                             'Size': {
                                                 '@Unit': 'GB',
                                                 '#text': 100
@@ -2538,6 +2609,6 @@ class ELCMTestCase(testtools.TestCase):
             "name": "hyper_threading_enabled",
             "value": "True"
         }]
-        self.assertItemsEqual(expect_settings, result)
+        self.assertCountEqual(expect_settings, result)
         backup_bios_config_mock.assert_called_once_with(
             self.irmc_info)
diff -pruN 0.8.0-2/scciclient/tests/irmc/test_ipmi.py 0.12.3-0ubuntu1/scciclient/tests/irmc/test_ipmi.py
--- 0.8.0-2/scciclient/tests/irmc/test_ipmi.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/tests/irmc/test_ipmi.py	2022-07-29 10:06:56.000000000 +0000
@@ -15,11 +15,11 @@
 Test class for IPMI Module.
 """
 
-import mock
-import testtools
+from unittest import mock
 
 from pyghmi import exceptions as ipmi_exception
 from pyghmi.ipmi import command as ipmi_command
+import testtools
 
 from scciclient.irmc import ipmi
 
diff -pruN 0.8.0-2/scciclient/tests/irmc/test_scci.py 0.12.3-0ubuntu1/scciclient/tests/irmc/test_scci.py
--- 0.8.0-2/scciclient/tests/irmc/test_scci.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/tests/irmc/test_scci.py	2022-07-29 10:06:56.000000000 +0000
@@ -17,16 +17,120 @@ Test class for iRMC Power Driver
 
 import os
 import time
+from unittest import mock
 import xml.etree.ElementTree as ET
 
-import mock
+import defusedxml.ElementTree as dET
 from requests_mock.contrib import fixture as rm_fixture
+import six
+import six.moves.builtins as __builtin__
 import testtools
 
 from scciclient.irmc import ipmi
 from scciclient.irmc import scci
 from scciclient.irmc import snmp
 
+if six.PY3:
+    import io
+    file = io.BytesIO
+
+
+IRMC_CONFIG_PARTIAL = """<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CMDSEQ>
+<!-- "Many Items Ommited..." -->
+<!-- "ConfBmcRemoteFdImageServer" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A50" OI="0" Type="SET">
+  <DATA Type="xsd::string">10.124.196.156</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteFdImageUserName" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A51" OI="0" Type="SET">
+  <DATA Type="xsd::string"></DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteFdImageUserPassword" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A52" OI="0" Type="SET">
+  <DATA Type="xsd::string"></DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteFdImageUserDomain" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A53" OI="0" Type="SET">
+  <DATA Type="xsd::string"></DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteFdImageShareType" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A54" OI="0" Type="SET">
+  <DATA Type="xsd::integer">1</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteFdImageShareName" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A55" OI="0" Type="SET">
+  <DATA Type="xsd::string">/srv/nfs</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteFdImageImageName" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A56" OI="0" Type="SET">
+  <DATA Type="xsd::string">virtual-media.img</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcMediaOptionsFdAttachMode" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A57" OI="0" Type="SET">
+  <DATA Type="xsd::integer">1</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcMediaOptionsFdNumber" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A58" OI="0" Type="SET">
+  <DATA Type="xsd::integer">1</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteCdImageServer" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A60" OI="0" Type="SET">
+  <DATA Type="xsd::string">10.124.196.156</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteCdImageUserName" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A61" OI="0" Type="SET">
+  <DATA Type="xsd::string"></DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteCdImageUserPassword" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A62" OI="0" Type="SET">
+  <DATA Type="xsd::string"></DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteCdImageUserDomain" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A63" OI="0" Type="SET">
+  <DATA Type="xsd::string"></DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteCdImageShareType" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A64" OI="0" Type="SET">
+  <DATA Type="xsd::integer">1</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteCdImageShareName" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A65" OI="0" Type="SET">
+  <DATA Type="xsd::string">/srv/nfs</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcRemoteCdImageImageName" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A66" OI="0" Type="SET">
+  <DATA Type="xsd::string">virtual-media.iso</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcMediaOptionsCdAttachMode" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A67" OI="0" Type="SET">
+  <DATA Type="xsd::integer">1</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "ConfBmcMediaOptionsCdNumber" -->
+<CMD Context="SCCI" OC="ConfigSpace" OE="1A68" OI="0" Type="SET">
+  <DATA Type="xsd::integer">1</DATA>
+  <STATUS>0</STATUS>
+</CMD>
+<!-- "Many Items Ommited..." -->
+</CMDSEQ>"""
+
 
 class SCCITestCase(testtools.TestCase):
     """Tests for SCCI
@@ -43,13 +147,13 @@ class SCCITestCase(testtools.TestCase):
                 os.path.dirname(__file__),
                 'fixtures/irmc_report_ok.xml'), "r") as report_ok:
             self.report_ok_txt = report_ok.read()
-        self.report_ok_xml = ET.fromstring(self.report_ok_txt)
+        self.report_ok_xml = dET.fromstring(self.report_ok_txt)
 
         with open(os.path.join(
                 os.path.dirname(__file__),
                 'fixtures/irmc_report_ng.xml'), "r") as report_ng:
             self.report_ng_txt = report_ng.read()
-        self.report_ng_xml = ET.fromstring(self.report_ng_txt)
+        self.report_ng_xml = dET.fromstring(self.report_ng_txt)
 
         self.irmc_address = '10.124.196.159'
         self.irmc_username = 'admin'
@@ -264,7 +368,8 @@ class SCCITestCase(testtools.TestCase):
             'HTTP PROTOCOL ERROR, STATUS CODE = 302',
             str(e))
 
-    def test_power_on_ok(self):
+    @mock.patch.object(time, 'sleep')
+    def test_power_on_ok(self, mock_sleep):
         self.requests_mock.post("http://" + self.irmc_address + "/config",
                                 text="""<?xml version="1.0" encoding="UTF-8"?>
                                 <Status>
@@ -281,8 +386,10 @@ class SCCITestCase(testtools.TestCase):
                                  client_timeout=self.irmc_client_timeout)
         r = client(scci.POWER_ON)
         self.assertEqual(r.status_code, 200)
+        mock_sleep.assert_called_once_with(3)
 
-    def test_power_off_ok(self):
+    @mock.patch.object(time, 'sleep')
+    def test_power_off_ok(self, mock_sleep):
         self.requests_mock.post("http://" + self.irmc_address + "/config",
                                 text="""<?xml version="1.0" encoding="UTF-8"?>
                                 <Status>
@@ -299,6 +406,7 @@ class SCCITestCase(testtools.TestCase):
                                  client_timeout=self.irmc_client_timeout)
         r = client(scci.POWER_OFF)
         self.assertEqual(r.status_code, 200)
+        mock_sleep.assert_called_once_with(3)
 
     def test_power_cycle_ok(self):
         self.requests_mock.post("http://" + self.irmc_address + "/config",
@@ -318,7 +426,8 @@ class SCCITestCase(testtools.TestCase):
         r = client(scci.POWER_CYCLE)
         self.assertEqual(r.status_code, 200)
 
-    def test_power_reset_ok(self):
+    @mock.patch.object(time, 'sleep')
+    def test_power_reset_ok(self, mock_sleep):
         self.requests_mock.post("http://" + self.irmc_address + "/config",
                                 text="""<?xml version="1.0" encoding="UTF-8"?>
                                 <Status>
@@ -335,6 +444,7 @@ class SCCITestCase(testtools.TestCase):
                                  client_timeout=self.irmc_client_timeout)
         r = client(scci.POWER_RESET)
         self.assertEqual(r.status_code, 200)
+        mock_sleep.assert_called_once_with(3)
 
     def test_power_raise_nmi_ok(self):
         self.requests_mock.post("http://" + self.irmc_address + "/config",
@@ -498,7 +608,7 @@ class SCCITestCase(testtools.TestCase):
 
     def test_get_sensor_data_records_ng(self):
         sensor = scci.get_sensor_data_records(self.report_ng_xml)
-        self.assertEqual(sensor, None)
+        self.assertIsNone(sensor)
 
     def test_get_irmc_version_ok(self):
         version = scci.get_irmc_version(self.report_ok_xml)
@@ -506,7 +616,7 @@ class SCCITestCase(testtools.TestCase):
 
     def test_get_irmc_version_ng(self):
         version = scci.get_irmc_version(self.report_ng_xml)
-        self.assertEqual(version, None)
+        self.assertIsNone(version)
 
     def test_get_report_ok(self):
         self.requests_mock.get(
@@ -651,6 +761,9 @@ class SCCITestCase(testtools.TestCase):
                                 <Message>No Error</Message>
                                 </Status>""")
 
+        self.requests_mock.get("http://" + self.irmc_address +
+                               "/iRMC_Settings.pre", text=IRMC_CONFIG_PARTIAL)
+
         client = scci.get_client(self.irmc_address,
                                  self.irmc_username,
                                  self.irmc_password,
@@ -912,3 +1025,260 @@ class SCCITestCase(testtools.TestCase):
         fgi_status_expect = {'0': 'Idle'}
         result = scci.get_raid_fgi_status(report_fake)
         self.assertEqual(result, fgi_status_expect)
+
+    @mock.patch('scciclient.irmc.scci.requests.get')
+    def test_fail_get_bios_firmware_status(self, mock_requests_get):
+        mock_requests_get.return_value = mock.Mock(
+            status_code=404,
+            text="""</head>
+            <body>
+            <div id="main">
+                <div class="content message">
+                    <div id="alert_icon">
+                    </div>
+                    <div id="msg_title" class="title">
+                        File not found  <!-- This tag is OPTIONAL and is the
+                        title eg. 404 - File not found -->
+                    </div>
+                </div>
+            </div>
+            </body>
+            </html>""")
+        upgrade_type = 'biosss'
+        self.assertRaises(scci.SCCIClientError,
+                          scci.get_firmware_upgrade_status, self.irmc_info,
+                          upgrade_type=upgrade_type)
+
+    @mock.patch('scciclient.irmc.scci.requests.get')
+    def test_success_get_bios_firmware_status(self, mock_requests_get):
+        mock_requests_get.return_value = mock.Mock(
+            return_value='ok',
+            status_code=200,
+            text="""<?xml version="1.0" encoding="UTF-8"?>
+            <Status>
+            <Value>0</Value>
+            <Severity>Information</Severity>
+            <Message>No Error</Message>
+            </Status>""")
+        expected_status = "0"
+        expected_severity = "Information"
+        expected_message = "No Error"
+        upgrade_type = 'bios'
+        result = scci.get_firmware_upgrade_status(self.irmc_info, upgrade_type)
+        self.assertEqual(expected_status, result.find("./Value").text)
+        self.assertEqual(expected_severity, result.find("./Severity").text)
+        self.assertEqual(expected_message, result.find("./Message").text)
+
+    @mock.patch('scciclient.irmc.scci.requests.get')
+    def test_fail_get_irmc_firmware_status(self, mock_requests_get):
+        mock_requests_get.return_value = mock.Mock(
+            status_code=404,
+            text="""</head>
+            <body>
+            <div id="main">
+                <div class="content message">
+                    <div id="alert_icon">
+                    </div>
+                    <div id="msg_title" class="title">
+                        File not found  <!-- This tag is OPTIONAL and is the
+                        title eg. 404 - File not found -->
+                    </div>
+                </div>
+            </div>
+            </body>
+            </html>""")
+        upgrade_type = 'irmcccc'
+        self.assertRaises(scci.SCCIClientError,
+                          scci.get_firmware_upgrade_status, self.irmc_info,
+                          upgrade_type=upgrade_type)
+
+    @mock.patch('scciclient.irmc.scci.requests.get')
+    def test_success_get_irmc_firmware_status(self, mock_requests_get):
+        mock_requests_get.return_value = mock.Mock(
+            return_value='ok',
+            status_code=200,
+            text="""<?xml version="1.0" encoding="UTF-8"?>
+            <Status>
+            <Value>0</Value>
+            <Severity>Information</Severity>
+            <Message>No Error</Message>
+            </Status>""")
+        expected_status = "0"
+        expected_severity = "Information"
+        expected_message = "No Error"
+        upgrade_type = 'irmc'
+        result = scci.get_firmware_upgrade_status(self.irmc_info, upgrade_type)
+        self.assertEqual(expected_status, result.find("./Value").text)
+        self.assertEqual(expected_severity, result.find("./Severity").text)
+        self.assertEqual(expected_message, result.find("./Message").text)
+
+    @mock.patch('scciclient.irmc.scci.get_firmware_upgrade_status')
+    def test_failed_process_session_bios_status(self, mock_status):
+        session_timeout = 180
+        upgrade_type = 'bios'
+        # Fake status from server
+        status_fake = ET.Element(self)
+        status_fake.append(ET.Element("Value", name="Value"))
+        status_fake.append(ET.Element("Severity", name="Severity"))
+        status_fake.append(ET.Element("Message", name="Message"))
+        status_fake.find("./Value").text = '0'
+        status_fake.find("./Severity").text = 'Error'
+        status_fake.find("./Message").text = 'File not provided'
+
+        mock_status.return_value = status_fake
+        expected_status = 'Error'
+        result = scci.process_session_status(self.irmc_info, session_timeout,
+                                             upgrade_type)
+        self.assertEqual(expected_status, result['upgrade_status'])
+
+    @mock.patch('scciclient.irmc.scci.get_firmware_upgrade_status')
+    def test_success_process_session_bios_status(self, mock_status):
+        session_timeout = 180
+        upgrade_type = 'bios'
+        # Fake status from server
+        status_fake = ET.Element(self)
+        status_fake.append(ET.Element("Value", name="Value"))
+        status_fake.append(ET.Element("Severity", name="Severity"))
+        status_fake.append(ET.Element("Message", name="Message"))
+        status_fake.find("./Value").text = '9'
+        status_fake.find("./Severity").text = 'Information'
+        status_fake.find("./Message").text = 'FLASH successful'
+
+        mock_status.return_value = status_fake
+        expected_status = 'Complete'
+        result = scci.process_session_status(self.irmc_info, session_timeout,
+                                             upgrade_type)
+        self.assertEqual(expected_status, result['upgrade_status'])
+
+    @mock.patch('scciclient.irmc.scci.get_firmware_upgrade_status')
+    def test_failed_process_session_irmc_status(self, mock_status):
+        session_timeout = 180
+        upgrade_type = 'irmc'
+        # Fake status from server
+        status_fake = ET.Element(self)
+        status_fake.append(ET.Element("Value", name="Value"))
+        status_fake.append(ET.Element("Severity", name="Severity"))
+        status_fake.append(ET.Element("Message", name="Message"))
+        status_fake.find("./Value").text = '0'
+        status_fake.find("./Severity").text = 'Error'
+        status_fake.find("./Message").text = 'File not provided'
+
+        mock_status.return_value = status_fake
+        expected_status = 'Error'
+        result = scci.process_session_status(self.irmc_info, session_timeout,
+                                             upgrade_type)
+        self.assertEqual(expected_status, result['upgrade_status'])
+
+    @mock.patch('scciclient.irmc.scci.get_firmware_upgrade_status')
+    def test_success_process_session_irmc_status(self, mock_status):
+        session_timeout = 180
+        upgrade_type = 'irmc'
+        # Fake status from server
+        status_fake = ET.Element(self)
+        status_fake.append(ET.Element("Value", name="Value"))
+        status_fake.append(ET.Element("Severity", name="Severity"))
+        status_fake.append(ET.Element("Message", name="Message"))
+        status_fake.find("./Value").text = '9'
+        status_fake.find("./Severity").text = 'Information'
+        status_fake.find("./Message").text = 'FLASH successful'
+
+        mock_status.return_value = status_fake
+        expected_status = 'Complete'
+        result = scci.process_session_status(self.irmc_info, session_timeout,
+                                             upgrade_type)
+        self.assertEqual(expected_status, result['upgrade_status'])
+
+    @mock.patch.object(__builtin__, 'open', autospec=True)
+    def test_create_bios_firmware_upgrade(self, open_mock):
+        upgrade_type = 'bios'
+        self.requests_mock.post("http://" + self.irmc_address + "/biosupdate",
+                                text="""<?xml version="1.0" encoding="UTF-8"?>
+                                <Status>
+                                    <Value>0</Value>
+                                    <Severity>Information</Severity>
+                                    <Message>No Error</Message>
+                                </Status>""")
+        bios_input = '/media/DATA/D3099-B1.UPC'
+        open_mock.return_value = mock.mock_open(read_data="file").return_value
+        client = scci.get_client(self.irmc_address,
+                                 self.irmc_username,
+                                 self.irmc_password,
+                                 port=self.irmc_port,
+                                 auth_method=self.irmc_auth_method,
+                                 client_timeout=self.irmc_client_timeout,
+                                 upgrade_type=upgrade_type)
+        r = client(bios_input)
+        self.assertEqual(r.status_code, 200)
+
+    @mock.patch.object(__builtin__, 'open', side_effect=IOError, autospec=True)
+    def test_create_fail_bios_firmware_upgrade(self, open_mock):
+        upgrade_type = 'bios'
+        self.requests_mock.post("http://" + self.irmc_address + "/biosupdate",
+                                text="""<?xml version="1.0" encoding="UTF-8"?>
+                                <Status>
+                                <Value>6</Value>
+                                <Severity>Error</Severity>
+                                <Message>File not provided</Message>
+                                </Status>
+                                """)
+        # Fake wrong file directory
+        bios_input = '/media/DATA/D3099-B101.UPC'
+        open_mock.return_value = mock.mock_open(read_data="file").return_value
+        client = scci.get_client(self.irmc_address,
+                                 self.irmc_username,
+                                 self.irmc_password,
+                                 port=self.irmc_port,
+                                 auth_method=self.irmc_auth_method,
+                                 client_timeout=self.irmc_client_timeout,
+                                 upgrade_type=upgrade_type)
+
+        self.assertRaises(scci.SCCIClientError, client, bios_input)
+
+    @mock.patch.object(__builtin__, 'open', autospec=True)
+    def test_create_irmc_firmware_upgrade(self, open_mock):
+        upgrade_type = 'irmc'
+        self.requests_mock.post("http://" + self.irmc_address +
+                                "/irmcupdate?flashSelect=255",
+                                text="""<?xml version="1.0" encoding="UTF-8"?>
+                                <Status>
+                                    <Value>0</Value>
+                                    <Severity>Information</Severity>
+                                    <Message>No Error</Message>
+                                </Status>""")
+        irmc_input = '/media/DATA/TX2540M1.bin'
+        open_mock.return_value = mock.mock_open(read_data="file").return_value
+        client = scci.get_client(self.irmc_address,
+                                 self.irmc_username,
+                                 self.irmc_password,
+                                 port=self.irmc_port,
+                                 auth_method=self.irmc_auth_method,
+                                 client_timeout=self.irmc_client_timeout,
+                                 upgrade_type=upgrade_type)
+        r = client(irmc_input)
+        self.assertEqual(r.status_code, 200)
+
+    @mock.patch.object(__builtin__, 'open', side_effect=IOError, autospec=True)
+    def test_create_fail_irmc_firmware_upgrade(self, open_mock):
+        upgrade_type = 'irmc'
+        self.requests_mock.post("http://" + self.irmc_address +
+                                "/irmcupdate?flashSelect=255",
+                                text="""<?xml version="1.0" encoding="UTF-8"?>
+                                <Status>
+                                <Value>6</Value>
+                                <Severity>Error</Severity>
+                                <Message>File not provided</Message>
+                                </Status>
+                                """)
+        # Fake wrong file directory
+        irmc_input = '/media/DATA/TX2540M1111.bin'
+        mock_file_handle = mock.MagicMock(spec=file)
+        open_mock.return_value = mock_file_handle
+        client = scci.get_client(self.irmc_address,
+                                 self.irmc_username,
+                                 self.irmc_password,
+                                 port=self.irmc_port,
+                                 auth_method=self.irmc_auth_method,
+                                 client_timeout=self.irmc_client_timeout,
+                                 upgrade_type=upgrade_type)
+
+        self.assertRaises(scci.SCCIClientError, client, irmc_input)
diff -pruN 0.8.0-2/scciclient/tests/irmc/test_snmp.py 0.12.3-0ubuntu1/scciclient/tests/irmc/test_snmp.py
--- 0.8.0-2/scciclient/tests/irmc/test_snmp.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/tests/irmc/test_snmp.py	2022-07-29 10:06:56.000000000 +0000
@@ -15,10 +15,10 @@
 Test class for snmp module.
 """
 
+from unittest import mock
 
-import mock
-from pysnmp.entity.rfc3413.oneliner import cmdgen
 from pysnmp import error as snmp_error
+from pysnmp import hlapi as pysnmp
 import testtools
 
 from scciclient.irmc import snmp
@@ -125,7 +125,6 @@ class IRMCSnmpTestCase(testtools.TestCas
                          ' failed: Error', str(e))
 
 
-@mock.patch.object(cmdgen, 'CommandGenerator', autospec=True)
 class SNMPClientTestCase(testtools.TestCase):
     def setUp(self):
         super(SNMPClientTestCase, self).setUp()
@@ -134,172 +133,188 @@ class SNMPClientTestCase(testtools.TestC
         self.oid = 'oid'
         self.value = 'value'
 
-    def test___init__(self, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'SnmpEngine', authspec=True)
+    def test___init__(self, mock_snmpengine):
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1)
-        mock_cmdgen.assert_called_once_with()
+        mock_snmpengine.assert_called_once_with()
         self.assertEqual(self.address, client.address)
         self.assertEqual(self.port, client.port)
         self.assertEqual(snmp.SNMP_V1, client.version)
-        self.assertIsNone(client.community)
-        self.assertNotIn('security', client.__dict__)
-        self.assertEqual(mock_cmdgen.return_value, client.cmd_gen)
-
-    def test_get(self, mock_cmdgen):
-        var_bind = (self.oid, self.value)
-        mock_cmdgenerator = mock_cmdgen.return_value
-        mock_cmdgenerator.getCmd.return_value = ("", None, 0, [var_bind])
-        client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
-        val = client.get(self.oid)
-        self.assertEqual(var_bind[1], val)
-        mock_cmdgenerator.getCmd.assert_called_once_with(mock.ANY, mock.ANY,
-                                                         self.oid)
-
-    @mock.patch.object(cmdgen, 'CommunityData', autospec=True)
-    def test__get_auth_v1(self, mock_community, mock_cmdgen):
-        client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1)
+        self.assertIsNone(client.read_community)
+        self.assertIsNone(client.write_community)
+        self.assertNotIn('user', client.__dict__)
+        self.assertEqual(mock_snmpengine.return_value, client.snmp_engine)
+
+    @mock.patch.object(pysnmp, 'CommunityData', autospec=True)
+    def test__get_auth_v1_read(self, mock_community):
+        client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1,
+                                 read_community='public',
+                                 write_community='private')
         client._get_auth()
-        mock_cmdgen.assert_called_once_with()
-        mock_community.assert_called_once_with(client.community, mpModel=0)
+        mock_community.assert_called_once_with(client.read_community,
+                                               mpModel=0)
+
+    @mock.patch.object(pysnmp, 'CommunityData', autospec=True)
+    def test__get_auth_v1_write(self, mock_community):
+        client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1,
+                                 read_community='public',
+                                 write_community='private')
+        client._get_auth(write_mode=True)
+        mock_community.assert_called_once_with(client.write_community,
+                                               mpModel=0)
 
-    @mock.patch.object(cmdgen, 'CommunityData', autospec=True)
-    def test__get_auth_v2c(self, mock_community, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'CommunityData', autospec=True)
+    def test__get_auth_v2c(self, mock_community):
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V2C)
         client._get_auth()
-        mock_cmdgen.assert_called_once_with()
-        mock_community.assert_called_once_with(client.community, mpModel=1)
+        mock_community.assert_called_once_with(client.read_community,
+                                               mpModel=1)
 
-    @mock.patch.object(cmdgen, 'UsmUserData', autospec=True)
-    def test__get_auth_v3(self, mock_user, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'UsmUserData', autospec=True)
+    def test__get_auth_v3(self, mock_user):
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         client._get_auth()
-        mock_cmdgen.assert_called_once_with()
-        mock_user.assert_called_once_with(client.security)
+        mock_user.assert_called_once_with(client.user,
+                                          authKey=client.auth_key,
+                                          authProtocol=client.auth_proto,
+                                          privKey=client.priv_key,
+                                          privProtocol=client.priv_proto)
 
-    @mock.patch.object(cmdgen, 'UdpTransportTarget', autospec=True)
-    def test__get_transport(self, mock_transport, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'UdpTransportTarget', autospec=True)
+    def test__get_transport(self, mock_transport):
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         client._get_transport()
-        mock_cmdgen.assert_called_once_with()
         mock_transport.assert_called_once_with((client.address, client.port))
 
-    @mock.patch.object(cmdgen, 'UdpTransportTarget', autospec=True)
-    def test__get_transport_err(self, mock_transport, mock_cmdgen):
-        mock_transport.side_effect = snmp_error.PySnmpError()
+    @mock.patch.object(pysnmp, 'UdpTransportTarget', autospec=True)
+    def test__get_transport_err(self, mock_transport):
+        mock_transport.side_effect = snmp_error.PySnmpError
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         self.assertRaises(snmp_error.PySnmpError, client._get_transport)
-        mock_cmdgen.assert_called_once_with()
         mock_transport.assert_called_once_with((client.address, client.port))
 
-    def test_get_pdu_err(self, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'ContextData', authspec=True)
+    def test__get_context(self, mock_context):
+        client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1)
+        client._get_context()
+        mock_context.assert_called_once_with(contextEngineId=None,
+                                             contextName='')
+
+    @mock.patch.object(pysnmp, 'getCmd', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_transport', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_context', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_auth', authspec=True)
+    def test_get(self, mock_auth, mock_context, mock_transport,
+                 mock_getcmd):
         var_bind = (self.oid, self.value)
-        error_status = mock.Mock()
-        error_status.prettyPrint = lambda: "pdu error"
-        mock_cmdgenerator = mock_cmdgen.return_value
-        mock_cmdgenerator.getCmd.return_value = (None, error_status, 1,
-                                                 [var_bind])
+        mock_getcmd.return_value = iter([("", None, 0, [var_bind])])
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
-        self.assertRaises(snmp.SNMPFailure, client.get, self.oid)
-        mock_cmdgenerator.getCmd.assert_called_once_with(mock.ANY, mock.ANY,
-                                                         self.oid)
+        val = client.get(self.oid)
+        self.assertEqual(var_bind[1], val)
+        self.assertEqual(1, mock_getcmd.call_count)
 
-    def test_get_next(self, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'nextCmd', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_transport', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_context', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_auth', authspec=True)
+    def test_get_next(self, mock_auth, mock_context, mock_transport,
+                      mock_nextcmd):
         var_bind = (self.oid, self.value)
-        mock_cmdgenerator = mock_cmdgen.return_value
-        mock_cmdgenerator.nextCmd.return_value = (
-            "", None, 0, [[var_bind, var_bind]])
+        mock_nextcmd.return_value = iter([("", None, 0, [var_bind]),
+                                          ("", None, 0, [var_bind])])
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         val = client.get_next(self.oid)
         self.assertEqual([self.value, self.value], val)
-        mock_cmdgenerator.nextCmd.assert_called_once_with(mock.ANY, mock.ANY,
-                                                          self.oid)
+        self.assertEqual(1, mock_nextcmd.call_count)
 
-    @mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
-    def test_get_err_transport(self, mock_transport, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'getCmd', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_transport', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_context', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_auth', authspec=True)
+    def test_get_err_transport(self, mock_auth, mock_context, mock_transport,
+                               mock_getcmd):
         mock_transport.side_effect = snmp_error.PySnmpError
-        mock_cmdgenerator = mock_cmdgen.return_value
+        var_bind = (self.oid, self.value)
+        mock_getcmd.return_value = iter([("engine error", None, 0,
+                                         [var_bind])])
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         self.assertRaises(snmp.SNMPFailure, client.get, self.oid)
-        self.assertFalse(mock_cmdgenerator.getCmd.called)
+        self.assertFalse(mock_getcmd.called)
 
-    @mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
-    def test_get_next_err_transport(self, mock_transport,
-                                    mock_cmdgen):
+    @mock.patch.object(pysnmp, 'nextCmd', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_transport', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_context', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_auth', authspec=True)
+    def test_get_next_err_transport(self, mock_auth, mock_context,
+                                    mock_transport, mock_nextcmd):
         mock_transport.side_effect = snmp_error.PySnmpError
-        mock_cmdgenerator = mock_cmdgen.return_value
+        var_bind = (self.oid, self.value)
+        mock_nextcmd.return_value = iter([("engine error", None, 0,
+                                         [var_bind])])
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         self.assertRaises(snmp.SNMPFailure, client.get_next, self.oid)
-        self.assertFalse(mock_cmdgenerator.nextCmd.called)
+        self.assertFalse(mock_nextcmd.called)
 
-    def test_get_err_engine(self, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'getCmd', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_transport', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_context', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_auth', authspec=True)
+    def test_get_err_engine(self, mock_auth, mock_context, mock_transport,
+                            mock_getcmd):
         var_bind = (self.oid, self.value)
-        mock_cmdgenerator = mock_cmdgen.return_value
-        mock_cmdgenerator.getCmd.return_value = ("engine error", None, 0,
-                                                 [var_bind])
+        mock_getcmd.return_value = iter([("engine error", None, 0,
+                                         [var_bind])])
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         self.assertRaises(snmp.SNMPFailure, client.get, self.oid)
-        mock_cmdgenerator.getCmd.assert_called_once_with(mock.ANY, mock.ANY,
-                                                         self.oid)
-
-    def test_get_next_err_engine(self, mock_cmdgen):
-        var_bind = (self.oid, self.value)
-        mock_cmdgenerator = mock_cmdgen.return_value
-        mock_cmdgenerator.nextCmd.return_value = ("engine error", None, 0,
-                                                  [[var_bind, var_bind]])
-        client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
-        self.assertRaises(snmp.SNMPFailure, client.get_next, self.oid)
-        mock_cmdgenerator.nextCmd.assert_called_once_with(mock.ANY, mock.ANY,
-                                                          self.oid)
+        self.assertEqual(1, mock_getcmd.call_count)
 
-    def test_get_next_pdu_err(self, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'nextCmd', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_transport', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_context', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_auth', authspec=True)
+    def test_get_next_err_engine(self, mock_auth, mock_context, mock_transport,
+                                 mock_nextcmd):
         var_bind = (self.oid, self.value)
-        error_status = mock.Mock()
-        error_status.prettyPrint = lambda: "pdu error"
-        mock_cmdgenerator = mock_cmdgen.return_value
-        mock_cmdgenerator.nextCmd.return_value = (None, error_status, 1,
-                                                  [var_bind])
+        mock_nextcmd.return_value = iter([("engine error", None, 0,
+                                         [var_bind])])
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         self.assertRaises(snmp.SNMPFailure, client.get_next, self.oid)
-        mock_cmdgenerator.nextCmd.assert_called_once_with(mock.ANY, mock.ANY,
-                                                          self.oid)
+        self.assertEqual(1, mock_nextcmd.call_count)
 
-    def test_set(self, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'setCmd', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_transport', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_context', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_auth', authspec=True)
+    def test_set(self, mock_auth, mock_context, mock_transport,
+                 mock_setcmd):
         var_bind = (self.oid, self.value)
-        mock_cmdgenerator = mock_cmdgen.return_value
-        mock_cmdgenerator.setCmd.return_value = ("", None, 0, [var_bind])
+        mock_setcmd.return_value = iter([("", None, 0, [var_bind])])
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         client.set(self.oid, self.value)
-        mock_cmdgenerator.setCmd.assert_called_once_with(mock.ANY, mock.ANY,
-                                                         var_bind)
+        self.assertEqual(1, mock_setcmd.call_count)
 
-    @mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True)
-    def test_set_err_transport(self, mock_transport, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'setCmd', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_transport', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_context', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_auth', authspec=True)
+    def test_set_err_transport(self, mock_auth, mock_context, mock_transport,
+                               mock_setcmd):
         mock_transport.side_effect = snmp_error.PySnmpError
-        mock_cmdgenerator = mock_cmdgen.return_value
-        client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
-        self.assertRaises(snmp.SNMPFailure,
-                          client.set, self.oid, self.value)
-        self.assertFalse(mock_cmdgenerator.setCmd.called)
-
-    def test_set_err_engine(self, mock_cmdgen):
-        var_bind = (self.oid, self.value)
-        mock_cmdgenerator = mock_cmdgen.return_value
-        mock_cmdgenerator.setCmd.return_value = ("engine error", None, 0,
-                                                 [var_bind])
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         self.assertRaises(snmp.SNMPFailure,
                           client.set, self.oid, self.value)
-        mock_cmdgenerator.setCmd.assert_called_once_with(mock.ANY, mock.ANY,
-                                                         var_bind)
+        self.assertFalse(mock_setcmd.called)
 
-    def test_set_pdu_err(self, mock_cmdgen):
+    @mock.patch.object(pysnmp, 'setCmd', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_transport', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_context', authspec=True)
+    @mock.patch.object(snmp.SNMPClient, '_get_auth', authspec=True)
+    def test_set_err_engine(self, mock_auth, mock_context, mock_transport,
+                            mock_setcmd):
         var_bind = (self.oid, self.value)
-        error_status = mock.Mock()
-        error_status.prettyPrint = lambda: "pdu error"
-        mock_cmdgenerator = mock_cmdgen.return_value
-        mock_cmdgenerator.setCmd.return_value = (None, error_status, 1,
-                                                 [var_bind])
+        mock_setcmd.return_value = iter([("engine error", None, 0,
+                                         [var_bind])])
         client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3)
         self.assertRaises(snmp.SNMPFailure,
                           client.set, self.oid, self.value)
-        mock_cmdgenerator.setCmd.assert_called_once_with(mock.ANY, mock.ANY,
-                                                         var_bind)
+        self.assertEqual(1, mock_setcmd.call_count)
diff -pruN 0.8.0-2/scciclient/tests/irmc/viom/test_client.py 0.12.3-0ubuntu1/scciclient/tests/irmc/viom/test_client.py
--- 0.8.0-2/scciclient/tests/irmc/viom/test_client.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/tests/irmc/viom/test_client.py	2022-07-29 10:06:56.000000000 +0000
@@ -12,7 +12,8 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import mock
+from unittest import mock
+
 import testtools
 
 from scciclient.irmc import scci
diff -pruN 0.8.0-2/scciclient/tests/irmc/viom/test_elcm.py 0.12.3-0ubuntu1/scciclient/tests/irmc/viom/test_elcm.py
--- 0.8.0-2/scciclient/tests/irmc/viom/test_elcm.py	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/scciclient/tests/irmc/viom/test_elcm.py	2022-07-29 10:06:56.000000000 +0000
@@ -17,8 +17,8 @@ Test class for iRMC eLCM functionality.
 """
 
 import time
+from unittest import mock
 
-import mock
 import testtools
 
 from scciclient.irmc import elcm
@@ -507,7 +507,7 @@ class VIOMTableTestCase(testtools.TestCa
             processing='execute',
             mode='new')
         root.set_manage_table(VIOMTableTestCase._sample_manage_table())
-        self.assertEqual(None, root.get_slot(0, create=False))
+        self.assertIsNone(root.get_slot(0, create=False))
         slot = root.get_slot(0)
         VIOMTableTestCase._add_sample_cards_to_slot(slot)
         self.assertEqual(slot, root.get_slot(0))
@@ -1230,7 +1230,7 @@ class VIOMTableTestCase(testtools.TestCa
             ip='192.168.1.11',
             subnet='255.255.255.0',
             gateway='192.168.1.1'
-            )
+        )
         expected_json = {
             'DHCPUsage': False,
             'Name': 'iqn-2017-04.com.fujitsu:001',
@@ -1248,7 +1248,7 @@ class VIOMTableTestCase(testtools.TestCa
             subnet='255.255.255.0',
             gateway='192.168.1.1',
             vlan_id=123
-            )
+        )
         expected_json = {
             'DHCPUsage': False,
             'Name': 'iqn-2017-04.com.fujitsu:001',
@@ -1265,7 +1265,7 @@ class VIOMTableTestCase(testtools.TestCa
             iqn='iqn-2017-04.com.fujitsu:001',
             ip='192.168.1.11',
             subnet='255.255.255.0',
-            )
+        )
         expected_json = {
             'DHCPUsage': True,
             'Name': 'iqn-2017-04.com.fujitsu:001',
diff -pruN 0.8.0-2/setup.cfg 0.12.3-0ubuntu1/setup.cfg
--- 0.8.0-2/setup.cfg	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/setup.cfg	2022-07-29 10:07:36.953071400 +0000
@@ -1,28 +1,25 @@
 [metadata]
 name = python-scciclient
 summary = Python ServerView Common Command Interface (SCCI) Client Library
-description-file =
-    README.rst
+description-file = 
+	README.rst
 author = FUJITSU LIMITED
-author-email = lsoft-dev@ml.css.fujitsu.com
-home-page = https://github.com/openstack/python-scciclient
-classifier =
-    Development Status :: 4 - Beta
-    Environment :: Console
-    Environment :: OpenStack
-    Intended Audience :: Information Technology
-    Intended Audience :: System Administrators
-    License :: OSI Approved :: Apache Software License
-    Operating System :: POSIX :: Linux
-    Programming Language :: Python
-    Programming Language :: Python :: 2
-    Programming Language :: Python :: 2.7
-    Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.4
+author-email = fj-lsoft-scciclient@dl.jp.fujitsu.com
+home-page = https://opendev.org/x/python-scciclient
+classifier = 
+	Development Status :: 4 - Beta
+	Environment :: Console
+	Environment :: OpenStack
+	Intended Audience :: Information Technology
+	Intended Audience :: System Administrators
+	License :: OSI Approved :: Apache Software License
+	Operating System :: POSIX :: Linux
+	Programming Language :: Python
+	Programming Language :: Python :: 3
 
 [files]
-packages =
-    scciclient
+packages = 
+	scciclient
 
 [build_sphinx]
 source-dir = doc/source
@@ -45,3 +42,8 @@ input_file = scciclient/locale/python-sc
 keywords = _ gettext ngettext l_ lazy_gettext
 mapping_file = babel.cfg
 output_file = scciclient/locale/python-scciclient.pot
+
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff -pruN 0.8.0-2/test-requirements.txt 0.12.3-0ubuntu1/test-requirements.txt
--- 0.8.0-2/test-requirements.txt	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/test-requirements.txt	2022-07-29 10:06:56.000000000 +0000
@@ -2,18 +2,12 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 
-hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
 coverage!=4.4,>=4.0 # Apache-2.0
 fixtures>=3.0.0 # Apache-2.0/BSD
-mock>=2.0.0 # BSD
 python-subunit>=1.0.0 # Apache-2.0/BSD
-oslotest>=3.2.0 # Apache-2.0
-stestr>=2.0.0 # Apache-2.0
+oslotest>=3.2.0,<4;python_version<'3.6'  # Apache-2.0
+oslotest>=3.2.0;python_version>='3.6'  # Apache-2.0
+stestr>=2.0.0,!=2.3.0,!=3.0.0  # Apache-2.0
 testscenarios>=0.4 # Apache-2.0/BSD
 testtools>=2.2.0 # MIT
 requests-mock>=1.2.0 # Apache-2.0
-
-# Doc requirements
-sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
-oslosphinx>=4.7.0 # Apache-2.0
-
diff -pruN 0.8.0-2/tox.ini 0.12.3-0ubuntu1/tox.ini
--- 0.8.0-2/tox.ini	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/tox.ini	2022-07-29 10:06:56.000000000 +0000
@@ -1,47 +1,62 @@
 [tox]
-minversion = 2.0
-envlist = py35,py34,py27,pep8
+minversion = 3.9.0
+envlist = py3,pep8
 skipsdist = True
+ignore_basepython_conflict=true
 
 [testenv]
 usedevelop = True
 install_command = pip install {opts} {packages}
 deps =
-       -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
        -r{toxinidir}/requirements.txt
        -r{toxinidir}/test-requirements.txt
 commands = stestr run --slowest {posargs}
 
 [testenv:pep8]
-commands = flake8
+basepython = python3
+deps =
+    hacking>=3.1.0,<4.0.0 # Apache-2.0
+    doc8>=0.6.0 # Apache-2.0
+    flake8-import-order>=0.17.1 # LGPLv3
+    pycodestyle>=2.0.0,<2.7.0 # MIT
+    Pygments>=2.2.0 # BSD
+commands =
+    flake8 {posargs}
 
 [testenv:venv]
+basepython = python3
 commands = {posargs}
 
 [testenv:cover]
+basepython = python3
 setenv =
-    PYTHON=coverage run --source $project --parallel-mode
+    PYTHON=coverage run --source scciclient --parallel-mode
 commands =
-    stestr run '{posargs}'
+    stestr run {posargs}
     coverage combine
     coverage html -d cover
     coverage xml -o cover/coverage.xml
     coverage report
 
 [testenv:docs]
-commands = python setup.py build_sphinx
+basepython = python3
+deps =
+    -r{toxinidir}/requirements.txt
+    -r{toxinidir}/doc/requirements.txt
+commands =
+  sphinx-build -b html doc/source doc/build/html
 
 [flake8]
-# E123, E125 skipped as they are invalid PEP-8.
-
+ignore = W503,W504,W605
 show-source = True
-ignore = E123,E125
 builtins = _
 exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build
-
-[testenv:lower-constraints]
-basepython = python3
-deps =
-  -c{toxinidir}/lower-constraints.txt
-  -r{toxinidir}/test-requirements.txt
-  -r{toxinidir}/requirements.txt
+# [H106] Don't put vim configuration in source files.
+# [H203] Use assertIs(Not)None to check for None.
+# [H204] Use assert(Not)Equal to check for equality.
+# [H205] Use assert(Greater|Less)(Equal) for comparison.
+# [H904] Delay string interpolations at logging calls.
+enable-extensions=H106,H203,H204,H205,H904
+filename = *.py
+import-order-style = pep8
+application-import-names = scciclient
diff -pruN 0.8.0-2/.zuul.yaml 0.12.3-0ubuntu1/.zuul.yaml
--- 0.8.0-2/.zuul.yaml	2018-08-24 12:05:36.000000000 +0000
+++ 0.12.3-0ubuntu1/.zuul.yaml	2022-07-29 10:06:56.000000000 +0000
@@ -1,7 +1,5 @@
 - project:
-    check:
-      jobs:
-        - openstack-tox-lower-constraints
-    gate:
-      jobs:
-        - openstack-tox-lower-constraints
+    templates:
+      - check-requirements
+      - openstack-python3-yoga-jobs
+      - publish-openstack-docs-pti
