././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1692971673.122654 python-scciclient-0.15.0/0000775000175000017500000000000000000000000015257 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/.coveragerc0000664000175000017500000000017000000000000017376 0ustar00zuulzuul00000000000000[run] branch = True source = scciclient omit = scciclient/tests/*,scciclient/openstack/* [report] ignore_errors = True ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/.mailmap0000664000175000017500000000013100000000000016673 0ustar00zuulzuul00000000000000# Format is: # # ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/.stestr.conf0000664000175000017500000000006200000000000017526 0ustar00zuulzuul00000000000000[DEFAULT] test_path=./scciclient/tests top_dir=./ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/.zuul.yaml0000664000175000017500000000016700000000000017224 0ustar00zuulzuul00000000000000- project: templates: - check-requirements - openstack-python3-jobs - publish-openstack-docs-pti ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971672.0 python-scciclient-0.15.0/AUTHORS0000664000175000017500000000223100000000000016325 0ustar00zuulzuul0000000000000098k <18552437190@163.com> Andreas Jaeger Dao Cong Tien Doug Hellmann Hironori Shiina Jamie Lennox Janonymous Jin Hase Kobayashi Daisuke Luong Anh Tuan Naohiro Tamura Ngo Quoc Cuong Nguyen Hung Phuong Nguyen Quang Huy Nguyen Van Trung Riccardo Pittau Shukun Song Swapnil Kulkarni (coolsvap) Thomas Bechtold Thomas Goirand Tony Breeds Vanou Ishii Vieri <15050873171@163.com> Vu Cong Tuan Yushiro FURUKAWA qingszhao ricolin shangxiaobj shu-mutou vanou yatinkarel ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/CONTRIBUTING.rst0000664000175000017500000000104600000000000017721 0ustar00zuulzuul00000000000000If you would like to contribute to the development of OpenStack, you must follow the steps in this page: https://docs.openstack.org/infra/manual/developers.html Once those steps have been completed, changes to OpenStack should be submitted for review via the Gerrit tool, following the workflow documented at: https://docs.openstack.org/infra/manual/developers.html#development-workflow Pull requests submitted through GitHub will be ignored. Bugs should be filed on Launchpad, not GitHub: https://bugs.launchpad.net/python-scciclient ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971672.0 python-scciclient-0.15.0/ChangeLog0000664000175000017500000001154700000000000017041 0ustar00zuulzuul00000000000000CHANGES ======= 0.15.0 ------ * Migrate to pysnmp lextudio ecosystem 0.14.0 ------ * Modify incompatible default value passed to requests * Encode parameters passed to pyghmi.ipmi.Command * Change the name of keys to mask passwords 0.12.1 ------ * 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/HACKING.rst0000664000175000017500000000024700000000000017060 0ustar00zuulzuul00000000000000python-scciclient Style Commandments =============================================== Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/LICENSE0000664000175000017500000002363700000000000016277 0ustar00zuulzuul00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/MANIFEST.in0000664000175000017500000000013600000000000017015 0ustar00zuulzuul00000000000000include AUTHORS include ChangeLog exclude .gitignore exclude .gitreview global-exclude *.pyc ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1692971673.122654 python-scciclient-0.15.0/PKG-INFO0000664000175000017500000000222600000000000016356 0ustar00zuulzuul00000000000000Metadata-Version: 1.1 Name: python-scciclient Version: 0.15.0 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/README.rst0000664000175000017500000000050200000000000016743 0ustar00zuulzuul00000000000000=============================== 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/babel.cfg0000664000175000017500000000002100000000000016776 0ustar00zuulzuul00000000000000[python: **.py] ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1692971673.1146545 python-scciclient-0.15.0/doc/0000775000175000017500000000000000000000000016024 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/doc/requirements.txt0000664000175000017500000000010300000000000021302 0ustar00zuulzuul00000000000000sphinx>=2.0.0,!=2.1.0 # BSD openstackdocstheme>=2.2.1 # Apache-2.0 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1692971673.1186543 python-scciclient-0.15.0/doc/source/0000775000175000017500000000000000000000000017324 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/doc/source/conf.py0000775000175000017500000000476500000000000020642 0ustar00zuulzuul00000000000000# -*- coding: utf-8 -*- # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys sys.path.insert(0, os.path.abspath('../..')) # -- General configuration ---------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', 'openstackdocstheme' ] # autodoc generation is a bit aggressive and a nuisance when doing heavy # text edit cycles. # execute "export SPHINX_DEBUG=1" in your terminal to disable # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = u'python-scciclient' copyright = u'2013, OpenStack Foundation' # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). add_module_names = True # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. # 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 # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ ('index', '%s.tex' % project, u'%s Documentation' % project, u'OpenStack Foundation', 'manual'), ] # 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' ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/doc/source/contributing.rst0000664000175000017500000000011300000000000022560 0ustar00zuulzuul00000000000000============ Contributing ============ .. include:: ../../CONTRIBUTING.rst ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/doc/source/index.rst0000664000175000017500000000100500000000000021161 0ustar00zuulzuul00000000000000.. python-scciclient documentation master file, created by sphinx-quickstart on Tue Jul 9 22:26:36 2013. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to python-scciclient's documentation! ======================================================== Contents: .. toctree:: :maxdepth: 2 readme installation usage contributing Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/doc/source/installation.rst0000664000175000017500000000033400000000000022557 0ustar00zuulzuul00000000000000============ Installation ============ At the command line:: $ pip install python-scciclient Or, if you have virtualenvwrapper installed:: $ mkvirtualenv python-scciclient $ pip install python-scciclient ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/doc/source/readme.rst0000664000175000017500000000003600000000000021312 0ustar00zuulzuul00000000000000.. include:: ../../README.rst ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/doc/source/usage.rst0000664000175000017500000000013000000000000021154 0ustar00zuulzuul00000000000000======== Usage ======== To use python-scciclient in a project:: import scciclient ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/openstack-common.conf0000664000175000017500000000021100000000000021375 0ustar00zuulzuul00000000000000[DEFAULT] # The list of modules to copy from oslo-incubator.git # The base module to hold the copy of openstack.common base=scciclient ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1692971673.1186543 python-scciclient-0.15.0/python_scciclient.egg-info/0000775000175000017500000000000000000000000022472 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971672.0 python-scciclient-0.15.0/python_scciclient.egg-info/PKG-INFO0000664000175000017500000000222600000000000023571 0ustar00zuulzuul00000000000000Metadata-Version: 1.1 Name: python-scciclient Version: 0.15.0 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971673.0 python-scciclient-0.15.0/python_scciclient.egg-info/SOURCES.txt0000664000175000017500000000245400000000000024363 0ustar00zuulzuul00000000000000.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././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971672.0 python-scciclient-0.15.0/python_scciclient.egg-info/dependency_links.txt0000664000175000017500000000000100000000000026540 0ustar00zuulzuul00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971672.0 python-scciclient-0.15.0/python_scciclient.egg-info/not-zip-safe0000664000175000017500000000000100000000000024720 0ustar00zuulzuul00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971672.0 python-scciclient-0.15.0/python_scciclient.egg-info/pbr.json0000664000175000017500000000005600000000000024151 0ustar00zuulzuul00000000000000{"git_version": "a0d98f9", "is_release": true}././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971672.0 python-scciclient-0.15.0/python_scciclient.egg-info/requires.txt0000664000175000017500000000035200000000000025072 0ustar00zuulzuul00000000000000Babel!=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 pyasn1-lextudio>=1.1.0 pyasn1-modules-lextudio>=0.2.0 pyghmi>=1.0.24 pysnmp-lextudio>=5.0.0 requests>=2.14.2 six>=1.10.0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971672.0 python-scciclient-0.15.0/python_scciclient.egg-info/top_level.txt0000664000175000017500000000001300000000000025216 0ustar00zuulzuul00000000000000scciclient ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/requirements.txt0000664000175000017500000000104100000000000020537 0ustar00zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # 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.24 # Apache-2.0 pysnmp-lextudio>=5.0.0 # BSD pyasn1-lextudio>=1.1.0 # BSD pyasn1-modules-lextudio>=0.2.0 # 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 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1692971673.1186543 python-scciclient-0.15.0/scciclient/0000775000175000017500000000000000000000000017377 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/__init__.py0000664000175000017500000000124100000000000021506 0ustar00zuulzuul00000000000000# -*- coding: utf-8 -*- # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import pbr.version __version__ = pbr.version.VersionInfo( 'python-scciclient').version_string() ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1692971673.1186543 python-scciclient-0.15.0/scciclient/irmc/0000775000175000017500000000000000000000000020331 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/irmc/__init__.py0000664000175000017500000000117300000000000022444 0ustar00zuulzuul00000000000000# Copyright 2015 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from . import elcm # noqa from . import scci # noqa ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/irmc/elcm.py0000664000175000017500000012225400000000000021631 0ustar00zuulzuul00000000000000# Copyright 2016 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ eLCM functionality. """ import collections import time from oslo_serialization import jsonutils import requests import six from scciclient.irmc import scci """ List of profile names """ PROFILE_BIOS_CONFIG = 'BiosConfig' PROFILE_RAID_CONFIG = 'RAIDAdapter' """ List of URL paths for profiles """ URL_PATH_PROFILE_MGMT = '/rest/v1/Oem/eLCM/ProfileManagement/' """ List of request params for profiles """ PARAM_PATH_SYSTEM_CONFIG = 'Server/SystemConfig/' PARAM_PATH_BIOS_CONFIG = PARAM_PATH_SYSTEM_CONFIG + PROFILE_BIOS_CONFIG PARAM_PATH_HW_CONFIG = 'Server/HWConfigurationIrmc/Adapters/' PARAM_PATH_RAID_CONFIG = PARAM_PATH_HW_CONFIG + PROFILE_RAID_CONFIG """ Timeout values """ PROFILE_CREATE_TIMEOUT = 300 # 300 secs PROFILE_SET_TIMEOUT = 300 # 300 secs BIOS_CONFIG_SESSION_TIMEOUT = 30 * 60 # 30 mins RAID_CONFIG_SESSION_TIMEOUT = 30 * 60 # 30 mins BIOS_CONFIGURATION_DICTIONARY = { "boot_option_filter": "CsmConfig_BootOptionFilter", "boot_removable_media_enabled": "BootConfig_BootRemovableMediaEnabled", "check_controllers_health_status_enabled": "BootConfig_CheckControllersHealthStatusEnabled", "cpu_active_processor_cores": "CpuConfig_ActiveProcessorCores", "cpu_adjacent_cache_line_prefetch_enabled": "CpuConfig_AdjacentCacheLinePrefetchEnabled", "cpu_dcu_ip_prefetch_enabled": "CpuConfig_DcuIpPrefetchEnabled", "cpu_early_snoop": "CpuConfig_EarlySnoop", "cpu_energy_performance_mode": "CpuConfig_EnergyPerformanceMode", "cpu_enhanced_speed_step_enabled": "CpuConfig_EnhancedSpeedStepEnabled", "cpu_execute_disable_bit_enabled": "CpuConfig_ExecuteDisableBitEnabled", "cpu_frequency_floor_overwrite_enabled": "CpuConfig_FrequencyFloorOverwriteEnabled", "cpu_hardware_prefetcher_enabled": "CpuConfig_HardwarePrefetcherEnabled", "cpu_power_technology": "CpuConfig_PowerTechnology", "cpu_turbo_mode_enabled": "CpuConfig_TurboModeEnabled", "cpu_uncore_frequencey_override_enabled": "CpuConfig_UncoreFrequenceyOverrideEnabled", "cpu_vt_enabled": "CpuConfig_VtEnabled", "flash_write_enabled": "SecurityConfig_FlashWriteEnabled", "hyper_threading_enabled": "CpuConfig_HyperThreadingEnabled", "keep_void_boot_options_enabled": "BootConfig_KeepVoidBootOptionsEnabled", "launch_csm_enabled": "CsmConfig_LaunchCsmEnabled", "limit_cpu_id_maximum_enabled": "CpuConfig_LimitCpuIdMaximumEnabled", "memory_mode": "MemoryConfig_MemoryMode", "network_stack_enabled": "NetworkStackConfig_Enabled", "os_energy_performance_override_enabled": "CpuConfig_OsEnergyPerformanceOverrideEnabled", "pci_aspm_support": "PciConfig_ASPMSupport", "pci_above_4g_decoding_enabled": "PciConfig_Above4GDecodingEnabled", "pending_tpm_operation": "TpmConfig_PendingTpmOperation", "power_on_source": "PowerConfig_PowerOnSource", "power_wake_on_lan_boot": "PowerConfig_WakeOnLanBoot", "pxe_boot_option_retry": "BootConfig_PxeBootOptionRetry", "pxe_option_rom_policy": "CsmConfig_PxeOptionRomPolicy", "quiet_boot_enabled": "BootConfig_QuietBootEnabled", "sas_sata_driver": "OnboardDeviceConfig_SasSataDriver", "sas_sata_enabled": "OnboardDeviceConfig_SasSataEnabled", "sas_sata_option_rom_enabled": "OnboardDeviceConfig_SasSataOptionRomEnabled", "sata_controller_enabled": "SataConfig_SataControllerEnabled", "sata_mode": "SataConfig_SataMode", "secure_boot_control_enabled": "SecurityConfig_SecureBootControlEnabled", "secure_boot_mode": "SecurityConfig_SecureBootMode", "single_root_io_virtualization_support_enabled": "PciConfig_SingleRootIOVirtualizationSupportEnabled", "storage_option_rom_policy": "CsmConfig_StorageOptionRomPolicy", "tpm_hash_policy": "TpmConfig_HashPolicy", "tpm_state_enabled": "TpmConfig_TpmStateEnabled", "usb_legacy_support": "UsbConfig_LegacySupport", "usb_port_disable": "UsbConfig_PortDisable", "usb_xhci_mode": "UsbConfig_XHCIMode", "video_option_rom_policy": "CsmConfig_VideoOptionRomPolicy" } class ELCMInvalidResponse(scci.SCCIError): def __init__(self, message): super(ELCMInvalidResponse, self).__init__(message) class ELCMProfileNotFound(scci.SCCIError): def __init__(self, message): super(ELCMProfileNotFound, self).__init__(message) class ELCMSessionNotFound(scci.SCCIError): def __init__(self, message): super(ELCMSessionNotFound, self).__init__(message) class ELCMSessionTimeout(scci.SCCIError): def __init__(self, message): super(ELCMSessionTimeout, self).__init__(message) class SecureBootConfigNotFound(scci.SCCIError): def __init__(self, message): super(SecureBootConfigNotFound, self).__init__(message) class ELCMValueError(scci.SCCIError): def __init__(self, message): super(ELCMValueError, self).__init__(message) class BiosConfigNotFound(scci.SCCIError): def __init__(self, message): super(BiosConfigNotFound, self).__init__(message) def _parse_elcm_response_body_as_json(response): """parse eLCM response body as json data eLCM response should be in form of: _ Key1: value1 <-- optional --> Key2: value2 <-- optional --> KeyN: valueN <-- optional --> - CRLF - JSON string - :param response: eLCM response :return: json object if success :raise ELCMInvalidResponse: if the response does not contain valid json data. """ try: body = response.text body_parts = body.split('\r\n') if len(body_parts) > 0: return jsonutils.loads(body_parts[-1]) else: return None except (TypeError, ValueError): raise ELCMInvalidResponse('eLCM response does not contain valid json ' 'data. Response is "%s".' % body) def elcm_request(irmc_info, method, path, **kwargs): """send an eLCM request to the server :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 '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' :param path: url path for eLCM request :returns: requests.Response from SCCI server :raises SCCIInvalidInputError: if port and/or auth_method params are invalid :raises SCCIClientError: if SCCI failed """ host = irmc_info['irmc_address'] port = irmc_info.get('irmc_port', 443) auth_method = irmc_info.get('irmc_auth_method', 'basic') 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'}) params = kwargs.get('params') data = kwargs.get('data') 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 scci.SCCIInvalidInputError( ("Invalid port %(port)d or " + "auth_method for method %(auth_method)s") % {'port': port, 'auth_method': auth_method}) try: r = requests.request(method, protocol + '://' + host + path, headers=headers, params=params, data=data, verify=verify, timeout=client_timeout, allow_redirects=False, auth=auth_obj) except requests.exceptions.RequestException as requests_exception: raise scci.SCCIClientError(requests_exception) # Process status_code 401 if r.status_code == 401: raise scci.SCCIClientError('UNAUTHORIZED') return r def elcm_profile_get_versions(irmc_info): """send an eLCM request to get profile versions :param irmc_info: node info :returns: dict object of profiles if succeed { "Server":{ "@Version": "1.01", "AdapterConfigIrmc":{ "@Version": "1.00" }, "HWConfigurationIrmc":{ "@Version": "1.00" }, "SystemConfig":{ "IrmcConfig":{ "@Version": "1.02" }, "BiosConfig":{ "@Version": "1.02" } } } } :raises: SCCIClientError if SCCI failed """ # Send GET request to the server resp = elcm_request(irmc_info, method='GET', path=URL_PATH_PROFILE_MGMT + 'version') if resp.status_code == 200: return _parse_elcm_response_body_as_json(resp) else: raise scci.SCCIClientError(('Failed to get profile versions with ' 'error code %s' % resp.status_code)) def elcm_profile_list(irmc_info): """send an eLCM request to list all profiles :param irmc_info: node info :returns: dict object of profiles if succeed { 'Links': { 'profileStore': [ { '@odata.id': id1 }, { '@odata.id': id2 }, { '@odata.id': idN }, ] } } :raises: SCCIClientError if SCCI failed """ # Send GET request to the server resp = elcm_request(irmc_info, method='GET', path=URL_PATH_PROFILE_MGMT) if resp.status_code == 200: return _parse_elcm_response_body_as_json(resp) else: raise scci.SCCIClientError(('Failed to list profiles with ' 'error code %s' % resp.status_code)) def elcm_profile_get(irmc_info, profile_name): """send an eLCM request to get profile data :param irmc_info: node info :param profile_name: name of profile :returns: dict object of profile data if succeed :raises: ELCMProfileNotFound if profile does not exist :raises: SCCIClientError if SCCI failed """ # Send GET request to the server resp = elcm_request(irmc_info, method='GET', path=URL_PATH_PROFILE_MGMT + profile_name) if resp.status_code == 200: return _parse_elcm_response_body_as_json(resp) elif resp.status_code == 404: raise ELCMProfileNotFound('Profile "%s" not found ' 'in the profile store.' % profile_name) else: raise scci.SCCIClientError(('Failed to get profile "%(profile)s" with ' 'error code %(error)s' % {'profile': profile_name, 'error': resp.status_code})) def elcm_profile_create(irmc_info, param_path): """send an eLCM request to create profile To create a profile, a new session is spawned with status 'running'. When profile is created completely, the session ends. :param irmc_info: node info :param param_path: path of profile :returns: dict object of session info if succeed { 'Session': { 'Id': id 'Status': 'activated' ... } } :raises: SCCIClientError if SCCI failed """ # Send POST request to the server # NOTE: This task may take time, so set a timeout _irmc_info = dict(irmc_info) _irmc_info['irmc_client_timeout'] = PROFILE_CREATE_TIMEOUT resp = elcm_request(_irmc_info, method='POST', path=URL_PATH_PROFILE_MGMT + 'get', params={'PARAM_PATH': param_path}) if resp.status_code == 202: return _parse_elcm_response_body_as_json(resp) else: raise scci.SCCIClientError(('Failed to create profile for path ' '"%(param_path)s" with error code ' '%(error)s' % {'param_path': param_path, 'error': resp.status_code})) def elcm_profile_set(irmc_info, input_data): """send an eLCM request to set param values To apply param values, a new session is spawned with status 'running'. When values are applied or error, the session ends. :param irmc_info: node info :param input_data: param values to apply, eg. { 'Server': { 'SystemConfig': { 'BiosConfig': { '@Processing': 'execute', -- config data -- } } } } :returns: dict object of session info if succeed { 'Session': { 'Id': id 'Status': 'activated' ... } } :raises: SCCIClientError if SCCI failed """ # Prepare the data to apply if isinstance(input_data, dict): data = jsonutils.dumps(input_data) else: data = input_data # Send POST request to the server # NOTE: This task may take time, so set a timeout _irmc_info = dict(irmc_info) _irmc_info['irmc_client_timeout'] = PROFILE_SET_TIMEOUT content_type = 'application/x-www-form-urlencoded' if input_data['Server'].get('HWConfigurationIrmc'): content_type = 'application/json' resp = elcm_request(_irmc_info, method='POST', path=URL_PATH_PROFILE_MGMT + 'set', headers={'Content-type': content_type}, data=data) if resp.status_code == 202: return _parse_elcm_response_body_as_json(resp) else: raise scci.SCCIClientError(('Failed to apply param values with ' 'error code %(error)s' % {'error': resp.status_code})) def elcm_profile_delete(irmc_info, profile_name): """send an eLCM request to delete a profile :param irmc_info: node info :param profile_name: name of profile :raises: ELCMProfileNotFound if the profile does not exist :raises: SCCIClientError if SCCI failed """ # Send DELETE request to the server resp = elcm_request(irmc_info, method='DELETE', path=URL_PATH_PROFILE_MGMT + profile_name) if resp.status_code == 200: # Profile deleted return elif resp.status_code == 404: # Profile not found raise ELCMProfileNotFound('Profile "%s" not found ' 'in the profile store.' % profile_name) else: raise scci.SCCIClientError(('Failed to delete profile "%(profile)s" ' 'with error code %(error)s' % {'profile': profile_name, 'error': resp.status_code})) def elcm_session_list(irmc_info): """send an eLCM request to list all sessions :param irmc_info: node info :returns: dict object of sessions if succeed { 'SessionList': { 'Contains': [ { 'Id': id1, 'Name': name1 }, { 'Id': id2, 'Name': name2 }, { 'Id': idN, 'Name': nameN }, ] } } :raises: SCCIClientError if SCCI failed """ # Send GET request to the server resp = elcm_request(irmc_info, method='GET', path='/sessionInformation/') if resp.status_code == 200: return _parse_elcm_response_body_as_json(resp) else: raise scci.SCCIClientError(('Failed to list sessions with ' 'error code %s' % resp.status_code)) def elcm_session_get_status(irmc_info, session_id): """send an eLCM request to get session status :param irmc_info: node info :param session_id: session id :returns: dict object of session info if succeed { 'Session': { 'Id': id 'Status': status ... } } :raises: ELCMSessionNotFound if the session does not exist :raises: SCCIClientError if SCCI failed """ # Send GET request to the server resp = elcm_request(irmc_info, method='GET', path='/sessionInformation/%s/status' % session_id) if resp.status_code == 200: return _parse_elcm_response_body_as_json(resp) elif resp.status_code == 404: raise ELCMSessionNotFound('Session "%s" does not exist' % session_id) else: raise scci.SCCIClientError(('Failed to get status of session ' '"%(session)s" with error code %(error)s' % {'session': session_id, 'error': resp.status_code})) def elcm_session_get_log(irmc_info, session_id): """send an eLCM request to get session log :param irmc_info: node info :param session_id: session id :returns: dict object of session log if succeed { 'Session': { 'Id': id ... } } :raises: ELCMSessionNotFound if the session does not exist :raises: SCCIClientError if SCCI failed """ # Send GET request to the server resp = elcm_request(irmc_info, method='GET', path='/sessionInformation/%s/log' % session_id) if resp.status_code == 200: return _parse_elcm_response_body_as_json(resp) elif resp.status_code == 404: raise ELCMSessionNotFound('Session "%s" does not exist' % session_id) else: raise scci.SCCIClientError(('Failed to get log of session ' '"%(session)s" with error code %(error)s' % {'session': session_id, 'error': resp.status_code})) def elcm_session_terminate(irmc_info, session_id): """send an eLCM request to terminate a session :param irmc_info: node info :param session_id: session id :raises: ELCMSessionNotFound if the session does not exist :raises: SCCIClientError if SCCI failed """ # Send DELETE request to the server resp = elcm_request(irmc_info, method='DELETE', path='/sessionInformation/%s/terminate' % session_id) if resp.status_code == 200: return elif resp.status_code == 404: raise ELCMSessionNotFound('Session "%s" does not exist' % session_id) else: raise scci.SCCIClientError(('Failed to terminate session ' '"%(session)s" with error code %(error)s' % {'session': session_id, 'error': resp.status_code})) def elcm_session_delete(irmc_info, session_id, terminate=False): """send an eLCM request to remove a session from the session list :param irmc_info: node info :param session_id: session id :param terminate: a running session must be terminated before removing :raises: ELCMSessionNotFound if the session does not exist :raises: SCCIClientError if SCCI failed """ # Terminate the session first if needs to if terminate: # Get session status to check session = elcm_session_get_status(irmc_info, session_id) status = session['Session']['Status'] # Terminate session if it is activated or running if status == 'running' or status == 'activated': elcm_session_terminate(irmc_info, session_id) # Send DELETE request to the server resp = elcm_request(irmc_info, method='DELETE', path='/sessionInformation/%s/remove' % session_id) if resp.status_code == 200: return elif resp.status_code == 404: raise ELCMSessionNotFound('Session "%s" does not exist' % session_id) else: raise scci.SCCIClientError(('Failed to remove session ' '"%(session)s" with error code %(error)s' % {'session': session_id, 'error': resp.status_code})) def _process_session_data(irmc_info, operation, session_id, session_timeout=BIOS_CONFIG_SESSION_TIMEOUT): """process session for Bios config backup/restore or RAID config operation :param irmc_info: node info :param operation: one of 'BACKUP_BIOS', 'RESTORE_BIOS' or 'CONFIG_RAID' :param session_id: session id :param session_timeout: session timeout :return: a dict with following values: { 'bios_config': , 'warning': } or { 'raid_config': , 'warning': } """ session_expiration = time.time() + session_timeout while time.time() < session_expiration: # Get session status to check session = elcm_session_get_status(irmc_info=irmc_info, session_id=session_id) status = session['Session']['Status'] if status == 'running' or status == 'activated': # Sleep a bit time.sleep(5) elif status == 'terminated regularly': result = {} if operation == 'BACKUP_BIOS': # Bios profile is created, get the data now result['bios_config'] = elcm_profile_get( irmc_info=irmc_info, profile_name=PROFILE_BIOS_CONFIG) elif operation == 'RESTORE_BIOS': # Bios config applied successfully pass elif operation == 'CONFIG_RAID': # Getting raid config result['raid_config'] = elcm_profile_get(irmc_info, PROFILE_RAID_CONFIG) # Cleanup operation by deleting related session and profile. # In case of error, report it as warning instead of error. try: elcm_session_delete(irmc_info=irmc_info, session_id=session_id, terminate=True) if operation == 'CONFIG_RAID': return result # 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 return result else: # Error occurred, get session log to see what happened session_log = elcm_session_get_log(irmc_info=irmc_info, session_id=session_id) raise scci.SCCIClientError( ('Failed to %(operation)s config. ' 'Session log is "%(session_log)s".' % {'operation': operation, 'session_log': jsonutils.dumps(session_log)})) else: raise ELCMSessionTimeout( ('Failed to %(operation)s config. ' 'Session %(session_id)s log is timeout.' % {'operation': operation, 'session_id': session_id})) def backup_bios_config(irmc_info): """backup current bios configuration This function sends a BACKUP BIOS request to the server. Then when the bios config data are ready for retrieving, it will return the data to the caller. Note that this operation may take time. :param irmc_info: node info :return: a dict with following values: { 'bios_config': , 'warning': } """ 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. 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) except ELCMProfileNotFound: # 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) return result def restore_bios_config(irmc_info, bios_config): """restore bios configuration This function sends a RESTORE BIOS request to the server. Then when the bios is ready for restoring, it will apply the provided settings and return. Note that this operation may take time. :param irmc_info: node info :param bios_config: bios config """ def _process_bios_config(): try: if isinstance(bios_config, dict): input_data = bios_config else: input_data = jsonutils.loads(bios_config) # The input data must contain flag "@Processing":"execute" in the # equivalent section. bios_cfg = input_data['Server']['SystemConfig']['BiosConfig'] bios_cfg['@Processing'] = 'execute' return input_data except (TypeError, ValueError, KeyError): raise scci.SCCIInvalidInputError( ('Invalid input bios config "%s".' % bios_config)) # 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 # 3. Send a request to apply the param values session = elcm_profile_set(irmc_info=irmc_info, input_data=input_data) # 4. Param values applying is in progress, we monitor the session session_timeout = irmc_info.get('irmc_bios_session_timeout', BIOS_CONFIG_SESSION_TIMEOUT) _process_session_data(irmc_info=irmc_info, operation='RESTORE_BIOS', session_id=session['Session']['Id'], session_timeout=session_timeout) def get_secure_boot_mode(irmc_info): """Get the status if secure boot is enabled or not. :param irmc_info: node info. :raises: SecureBootConfigNotFound, if there is no configuration for secure boot mode in the bios. :return: True if secure boot mode is enabled on the node, False otherwise. """ result = backup_bios_config(irmc_info=irmc_info) try: bioscfg = result['bios_config']['Server']['SystemConfig']['BiosConfig'] return bioscfg['SecurityConfig']['SecureBootControlEnabled'] except KeyError: msg = ("Failed to get secure boot mode from server %s. Upgrading iRMC " "firmware may resolve this issue." % irmc_info['irmc_address']) raise SecureBootConfigNotFound(msg) def set_secure_boot_mode(irmc_info, enable): """Enable/Disable secure boot on the server. :param irmc_info: node info :param enable: True, if secure boot needs to be enabled for next boot, else False. """ bios_config_data = { 'Server': { '@Version': '1.01', 'SystemConfig': { 'BiosConfig': { '@Version': '1.01', 'SecurityConfig': { 'SecureBootControlEnabled': enable } } } } } restore_bios_config(irmc_info=irmc_info, bios_config=bios_config_data) def _update_raid_input_data(target_raid_config, raid_input): """Process raid input data. :param target_raid_config: node raid info :param raid_input: raid information for creating via eLCM :raises ELCMValueError: raise msg if wrong input :return: raid_input: raid input data which create raid configuration { "Server":{ "HWConfigurationIrmc":{ "@Processing":"execute", "Adapters":{ "RAIDAdapter":[ { "@AdapterId":"RAIDAdapter0", "@ConfigurationType":"Addressing", "LogicalDrives":{ "LogicalDrive":[ { "@Number":0, "@Action":"Create", "RaidLevel":"1" } ] } } ] }, "@Version":"1.00" }, "@Version":"1.01" } } """ logical_disk_list = target_raid_config['logical_disks'] raid_input['Server']['HWConfigurationIrmc'].update({'@Processing': 'execute'}) array_info = raid_input['Server']['HWConfigurationIrmc']['Adapters'][ 'RAIDAdapter'][0] array_info['LogicalDrives'] = {'LogicalDrive': []} array_info['Arrays'] = {'Array': []} for i, logical_disk in enumerate(logical_disk_list): physical_disks = logical_disk.get('physical_disks') # Auto create logical drive along with random physical disks. # Allow auto create along with raid 10 and raid 50 # with specific physical drive. if not physical_disks or logical_disk['raid_level'] \ in ('10', '50'): array_info['LogicalDrives']['LogicalDrive'].append( {'@Action': 'Create', 'RaidLevel': logical_disk['raid_level'], 'InitMode': 'fast'}) array_info['LogicalDrives']['LogicalDrive'][i].update({ "@Number": i}) else: # Create array disks with specific physical servers arrays = { "@Number": i, "@ConfigurationType": "Setting", "PhysicalDiskRefs": { "PhysicalDiskRef": [] } } lo_drive = { "@Number": i, "@Action": "Create", "RaidLevel": "", "ArrayRefs": { "ArrayRef": [ ] }, "InitMode": "fast" } array_info['Arrays']['Array'].append(arrays) array_info['LogicalDrives']['LogicalDrive'].append(lo_drive) lo_drive.update({'RaidLevel': logical_disk['raid_level']}) lo_drive['ArrayRefs']['ArrayRef'].append({"@Number": i}) for element in logical_disk['physical_disks']: arrays['PhysicalDiskRefs']['PhysicalDiskRef'].append({ '@Number': element}) if logical_disk['size_gb'] != "MAX": # Ensure correctly order these items in dict size = collections.OrderedDict() size['@Unit'] = 'GB' size['#text'] = logical_disk['size_gb'] array_info['LogicalDrives']['LogicalDrive'][i]['Size'] = size return raid_input def get_raid_adapter(irmc_info): """Collect raid information on the server. :param irmc_info: node info :returns: raid_adapter: get latest raid adapter information """ # Update raid adapter, due to raid adapter cannot auto update after # created raid configuration. _create_raid_adapter_profile(irmc_info) return elcm_profile_get(irmc_info, PROFILE_RAID_CONFIG) def _get_existing_logical_drives(raid_adapter): """Collect existing logical drives on the server. :param raid_adapter: raid adapter info :returns: existing_logical_drives: get logical drive on server """ existing_logical_drives = [] logical_drives = raid_adapter['Server']['HWConfigurationIrmc'][ 'Adapters']['RAIDAdapter'][0].get('LogicalDrives') if logical_drives is not None: for drive in logical_drives['LogicalDrive']: existing_logical_drives.append(drive['@Number']) return existing_logical_drives def _create_raid_adapter_profile(irmc_info): """Attempt delete exist adapter then create new raid adapter on the server. :param irmc_info: node info :returns: result: a dict with following values: { 'raid_config': , 'warning': } """ try: # Attempt erase exist adapter on BM Server elcm_profile_delete(irmc_info, PROFILE_RAID_CONFIG) except ELCMProfileNotFound: # Ignore this error as it's not an error in this case pass session = elcm_profile_create(irmc_info, PARAM_PATH_RAID_CONFIG) # Monitoring currently session until done. session_timeout = irmc_info.get('irmc_raid_session_timeout', RAID_CONFIG_SESSION_TIMEOUT) return _process_session_data(irmc_info, 'CONFIG_RAID', session['Session']['Id'], session_timeout) def create_raid_configuration(irmc_info, target_raid_config): """Process raid_input then perform raid configuration into server. :param irmc_info: node info :param target_raid_config: node raid information """ if len(target_raid_config['logical_disks']) < 1: raise ELCMValueError(message="logical_disks must not be empty") # Check RAID config in the new RAID adapter. Must be erased before # create new RAID config. raid_adapter = get_raid_adapter(irmc_info) logical_drives = raid_adapter['Server']['HWConfigurationIrmc'][ 'Adapters']['RAIDAdapter'][0].get('LogicalDrives') session_timeout = irmc_info.get('irmc_raid_session_timeout', RAID_CONFIG_SESSION_TIMEOUT) if logical_drives is not None: # Delete exist logical drives in server. # NOTE(trungnv): Wait session complete and raise error if # delete raid config during FGI(Foreground Initialization) in-progress # in previous mechanism. delete_raid_configuration(irmc_info) # Updating raid adapter profile after deleted profile. raid_adapter = get_raid_adapter(irmc_info) # Create raid configuration based on target_raid_config of node raid_input = _update_raid_input_data(target_raid_config, raid_adapter) session = elcm_profile_set(irmc_info, raid_input) # Monitoring raid creation session until done. _process_session_data(irmc_info, 'CONFIG_RAID', session['Session']['Id'], session_timeout) def delete_raid_configuration(irmc_info): """Delete whole raid configuration or one of logical drive on the server. :param irmc_info: node info """ # Attempt to get raid configuration on BM Server raid_adapter = get_raid_adapter(irmc_info) existing_logical_drives = _get_existing_logical_drives(raid_adapter) # Ironic requires delete_configuration first. Will pass if blank raid # configuration in server. if not existing_logical_drives: return raid_adapter['Server']['HWConfigurationIrmc'].update({ '@Processing': 'execute'}) logical_drive = raid_adapter['Server']['HWConfigurationIrmc'][ 'Adapters']['RAIDAdapter'][0]['LogicalDrives']['LogicalDrive'] for drive in logical_drive: drive['@Action'] = 'Delete' # Attempt to delete logical drive in the raid config session = elcm_profile_set(irmc_info, raid_adapter) # Monitoring raid config delete session until done. session_timeout = irmc_info.get('irmc_raid_session_timeout', RAID_CONFIG_SESSION_TIMEOUT) _process_session_data(irmc_info, 'CONFIG_RAID', session['Session']['Id'], session_timeout) # Attempt to delete raid adapter elcm_profile_delete(irmc_info, PROFILE_RAID_CONFIG) def set_bios_configuration(irmc_info, settings): """Set BIOS configurations on the server. :param irmc_info: node info :param settings: Dictionary containing the BIOS configuration. :raise: BiosConfigNotFound, if there is wrong settings for bios configuration. """ bios_config_data = { 'Server': { 'SystemConfig': { 'BiosConfig': {} } } } versions = elcm_profile_get_versions(irmc_info) server_version = versions['Server'].get('@Version') bios_version = \ versions['Server']['SystemConfig']['BiosConfig'].get('@Version') if server_version: bios_config_data['Server']['@Version'] = server_version if bios_version: (bios_config_data['Server']['SystemConfig']['BiosConfig'] ['@Version']) = bios_version configs = {} for setting_param in settings: setting_name = setting_param.get("name") setting_value = setting_param.get("value") # Revert-conversion from a string of True/False to boolean. # It will be raise failed if put "True" or "False" string value. if isinstance(setting_value, six.string_types): if setting_value.lower() == "true": setting_value = True elif setting_value.lower() == "false": setting_value = False try: type_config, config = BIOS_CONFIGURATION_DICTIONARY[ setting_name].split("_") if type_config in configs.keys(): configs[type_config][config] = setting_value else: configs.update({type_config: {config: setting_value}}) except KeyError: raise BiosConfigNotFound("Invalid BIOS setting: %s" % setting_param) bios_config_data['Server']['SystemConfig']['BiosConfig'].update(configs) restore_bios_config(irmc_info, bios_config_data) def get_bios_settings(irmc_info): """Get the current BIOS settings on the server :param irmc_info: node info. :returns: a list of dictionary BIOS settings """ bios_config = backup_bios_config(irmc_info)['bios_config'] bios_config_data = bios_config['Server']['SystemConfig']['BiosConfig'] settings = [] # TODO(trungnv): Allow working with multi levels of BIOS dictionary. for setting_param in BIOS_CONFIGURATION_DICTIONARY: type_config, config = BIOS_CONFIGURATION_DICTIONARY[ setting_param].split("_") if config in bios_config_data.get(type_config, {}): value = six.text_type(bios_config_data[type_config][config]) settings.append({'name': setting_param, 'value': value}) return settings ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/irmc/ipmi.py0000775000175000017500000001257700000000000021660 0ustar00zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import functools import itertools from pyghmi import exceptions as ipmi_exception from pyghmi.ipmi import command as ipmi_command # F1 1A - Get the number of specific PCI devices on baremetal GET_PCI = '0x2E 0xF1 0x80 0x28 0x00 0x1A %s 0x00' # F5 81 - GET TPM STATUS GET_TPM_STATUS = '0x2E 0xF5 0x80 0x28 0x00 0x81 0xC0' class IPMIFailure(Exception): """IPMI Failure This exception is used when IPMI operation failed. """ def __init__(self, message): super(IPMIFailure, self).__init__(message) class InvalidParameterValue(IPMIFailure): """Invalid Parameter Value Failure This exception is used when invalid parameter values are passed to the APIs exposed by this module. """ def __init__(self, message): super(InvalidParameterValue, self).__init__(message) def _parse_raw_bytes(raw_bytes): """Convert a string of hexadecimal values to decimal values parameters Example: '0x2E 0xF1 0x80 0x28 0x00 0x1A 0x01 0x00' is converted to: 46, 241, [128, 40, 0, 26, 1, 0] :param raw_bytes: string of hexadecimal values :returns: 3 decimal values """ bytes_list = [int(x, base=16) for x in raw_bytes.split()] return bytes_list[0], bytes_list[1], bytes_list[2:] def _send_raw_command(ipmicmd, raw_bytes): """Use IPMI command object to send raw ipmi command to BMC :param ipmicmd: IPMI command object :param raw_bytes: string of hexadecimal values. This is commonly used for certain vendor specific commands. :returns: dict -- The response from IPMI device """ netfn, command, data = _parse_raw_bytes(raw_bytes) response = ipmicmd.raw_command(netfn, command, data=data) return response def get_tpm_status(d_info): """Get the TPM support status. Get the TPM support status of the node. :param d_info: the list of ipmitool parameters for accessing a node. :returns: TPM support status """ # note: # Get TPM support status : ipmi cmd '0xF5', valid flags '0xC0' # # $ ipmitool raw 0x2E 0xF5 0x80 0x28 0x00 0x81 0xC0 # # Raw response: # 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'].encode('utf-8'), password=d_info['irmc_password'].encode('utf-8')) try: response = _send_raw_command(ipmicmd, GET_TPM_STATUS) if response['code'] != 0: raise IPMIFailure( "IPMI operation '%(operation)s' failed: %(error)s" % {'operation': "GET TMP status", 'error': response.get('error')}) out = ' '.join('{:02X}'.format(x) for x in response['data']) return out is not None and out[-5:] == 'C0 C0' except ipmi_exception.IpmiException as e: raise IPMIFailure( "IPMI operation '%(operation)s' failed: %(error)s" % {'operation': "GET TMP status", 'error': e}) def _pci_seq(ipmicmd): """Get output of ipmiraw command and the ordinal numbers. :param ipmicmd: IPMI command object. :returns: List of tuple contain ordinal number and output of ipmiraw command. """ for i in range(1, 0xff + 1): try: res = _send_raw_command(ipmicmd, GET_PCI % hex(i)) yield i, res except ipmi_exception.IpmiException as e: raise IPMIFailure( "IPMI operation '%(operation)s' failed: %(error)s" % {'operation': "GET PCI device quantity", 'error': e}) def get_pci_device(d_info, pci_device_ids): """Get quantity of PCI devices. Get quantity of PCI devices of the node. :param d_info: the list of ipmitool parameters for accessing a node. :param pci_device_ids: the list contains pairs of / for PCI devices. :returns: the number of PCI devices. """ # note: # Get quantity of PCI devices: # ipmi cmd '0xF1' # # $ ipmitool raw 0x2E 0xF1 0x80 0x28 0x00 0x1A 0x01 0x00 # # Raw response: # 80 28 00 00 00 05 data1 data2 34 17 76 11 00 04 # 01 # data1: 2 octet of VendorID # data2: 2 octet of DeviceID 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), _pci_seq(ipmicmd)) def _pci_count(accm, v): out = v[1]['data'] # if system returns value, record id will be increased. pci_id = "0x{:02x}{:02x}/0x{:02x}{:02x}".format( out[7], out[6], out[9], out[8]) return accm + 1 if pci_id in pci_device_ids else accm device_count = functools.reduce(_pci_count, response, 0) return device_count ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/irmc/scci.py0000775000175000017500000010343000000000000021630 0ustar00zuulzuul00000000000000# Copyright 2015 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ SCCI functionalities shared between different iRMC modules. """ import functools import re import time import defusedxml.ElementTree as ET import requests import six from scciclient.irmc import ipmi 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 This exception is general exception. """ def __init__(self, message, errorcode=None): super(SCCIError, self).__init__(message) class SCCIInvalidInputError(SCCIError): """SCCIInvalidInputError This exception is used when invalid inputs are passed to the APIs exposed by this module. """ def __init__(self, message): super(SCCIInvalidInputError, self).__init__(message) class SCCIClientError(SCCIError): """SCCIClientError This exception is used when a problem is encountered in executing an operation on the iRMC """ def __init__(self, message): super(SCCIClientError, self).__init__(message) class SCCIRAIDNotReady(SCCIError): """SCCIRAIDNotReady This exception is used when a mechanism not applied into a configuration on the iRMC yet """ def __init__(self, message): super(SCCIRAIDNotReady, self).__init__(message) class SCCISessionTimeout(SCCIError): def __init__(self, message): super(SCCISessionTimeout, self).__init__(message) """ List of iRMC S4/S5 supported SCCI commands SCCI OpCode SCCI Command String Description 0xE002 ConfigSpace ConfigSpace Write 0x0111 PowerOnCabinet Power On the Server 0x0112 PowerOffCabinet Power Off the Server 0x0113 PowerOffOnCabinet Power Cycle the Server 0x0204 ResetServer Hard Reset the Server 0x020C RaiseNMI Pulse the NMI (Non Maskable Interrupt) 0x0205 RequestShutdownAndOff Graceful Shutdown, requires running Agent 0x0206 RequestShutdownAndReset Graceful Reboot, requires running Agent 0x0209 ShutdownRequestCancelled Cancel a Shutdown Request 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 Remote Image Mount (NFS or CIFS Share ) """ _POWER_CMD = ''' ''' POWER_ON = _POWER_CMD % "PowerOnCabinet" POWER_OFF = _POWER_CMD % "PowerOffCabinet" POWER_CYCLE = _POWER_CMD % "PowerOffOnCabinet" POWER_RESET = _POWER_CMD % "ResetServer" POWER_RAISE_NMI = _POWER_CMD % "RaiseNMI" POWER_SOFT_OFF = _POWER_CMD % "RequestShutdownAndOff" POWER_SOFT_CYCLE = _POWER_CMD % "RequestShutdownAndReset" POWER_CANCEL_SHUTDOWN = _POWER_CMD % "ShutdownRequestCancelled" _VIRTUAL_MEDIA_CMD = ''' %d ''' MOUNT_CD = _VIRTUAL_MEDIA_CMD % ("ConnectRemoteCdImage", 1) UNMOUNT_CD = _VIRTUAL_MEDIA_CMD % ("ConnectRemoteCdImage", 0) MOUNT_FD = _VIRTUAL_MEDIA_CMD % ("ConnectRemoteFdImage", 1) UNMOUNT_FD = _VIRTUAL_MEDIA_CMD % ("ConnectRemoteFdImage", 0) _VIRTUAL_MEDIA_CD_SETTINGS = ''' 1 1 %s %s %d %s %s %s %s ''' _VIRTUAL_MEDIA_FD_SETTINGS = ''' 1 1 %s %s %d %s %s %s %s ''' class MetaShareType(type): @property def nfs(cls): return cls.NFS @property def cifs(cls): return cls.CIFS @six.add_metaclass(MetaShareType) class ShareType(object): """"Virtual Media Share Type.""" NFS = 0 CIFS = 1 def get_share_type(share_type): """get share type.""" return({'nfs': ShareType.nfs, 'cifs': ShareType.cifs}[share_type.lower()]) def scci_cmd(host, userid, password, cmd, port=443, auth_method='basic', client_timeout=60, do_async=True, verify=False, **kwargs): """execute SCCI command This function calls SCCI server modules :param host: hostname or IP of iRMC :param userid: userid for iRMC with administrator privileges :param password: password for userid :param cmd: SCCI command :param port: port number of iRMC :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 :raises: SCCIClientError if SCCI failed """ 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: header = {'Content-type': 'application/x-www-form-urlencoded'} 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=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) print("do_async = %s" % do_async) if r.status_code not in (200, 201): raise SCCIClientError( ('HTTP PROTOCOL ERROR, STATUS CODE = %s' % str(r.status_code))) result_xml = ET.fromstring(r.text) status = result_xml.find("./Value") # severity = result_xml.find("./Severity") error = result_xml.find("./Error") message = result_xml.find("./Message") if not int(status.text) == 0: raise SCCIClientError( ('SCCI PROTOCOL ERROR, STATUS CODE = %s, ' 'ERROR = %s, MESSAGE = %s' % (str(status.text), error.text, message.text))) else: return r except IOError as input_error: raise SCCIClientError(input_error) except ET.ParseError as parse_error: raise SCCIClientError(parse_error) except requests.exceptions.RequestException as requests_exception: 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, verify=False, **kwargs): """get SCCI command partial function This function returns SCCI command partial function :param host: hostname or IP of iRMC :param userid: userid for iRMC with administrator privileges :param password: password for userid :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, verify=verify, **kwargs) def get_virtual_cd_set_params_cmd(remote_image_server, remote_image_user_domain, remote_image_share_type, remote_image_share_name, remote_image_deploy_iso, remote_image_username, remote_image_user_password): """get Virtual CD Media Set Parameters Command This function returns Virtual CD Media Set Parameters Command :param remote_image_server: remote image server name or IP :param remote_image_user_domain: domain name of remote image server :param remote_image_share_type: share type of ShareType :param remote_image_share_name: share name :param remote_image_deploy_iso: deploy ISO image file name :param remote_image_username: username of remote image server :param remote_image_user_password: password of the username :returns: SCCI command """ cmd = _VIRTUAL_MEDIA_CD_SETTINGS % ( remote_image_server, remote_image_user_domain, remote_image_share_type, remote_image_share_name, remote_image_deploy_iso, remote_image_username, remote_image_user_password) return cmd def get_virtual_fd_set_params_cmd(remote_image_server, remote_image_user_domain, remote_image_share_type, remote_image_share_name, remote_image_floppy_fat, remote_image_username, remote_image_user_password): """get Virtual FD Media Set Parameters Command This function returns Virtual FD Media Set Parameters Command :param remote_image_server: remote image server name or IP :param remote_image_user_domain: domain name of remote image server :param remote_image_share_type: share type of ShareType :param remote_image_share_name: share name :param remote_image_deploy_iso: deploy ISO image file name :param remote_image_username: username of remote image server :param remote_image_user_password: password of the username :returns: SCCI command """ cmd = _VIRTUAL_MEDIA_FD_SETTINGS % ( remote_image_server, remote_image_user_domain, remote_image_share_type, remote_image_share_name, remote_image_floppy_fat, remote_image_username, remote_image_user_password) return cmd def get_report(host, userid, password, port=443, auth_method='basic', client_timeout=60, verify=False): """get iRMC report This function returns iRMC report in XML format :param host: hostname or IP of iRMC :param userid: userid for iRMC with administrator privileges :param password: password for userid :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 :raises: SCCIClientError if SCCI failed """ 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: r = requests.get(protocol + '://' + host + '/report.xml', 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))) root = ET.fromstring(r.text) return root except ET.ParseError as parse_error: raise SCCIClientError(parse_error) except requests.exceptions.RequestException as requests_exception: raise SCCIClientError(requests_exception) def get_sensor_data_records(report): """get sensor data This function returns sensor data in XML :param report: SCCI report element :returns: sensor element of SCCI report, or None """ sensor = report.find("./System/SensorDataRecords") return sensor def get_irmc_version(report): """get iRMC version This function returns iRMC version number :param report: SCCI report element :returns: version element of SCCI report, or None """ version = report.find("./System/ManagementControllers/iRMC") 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 This function returns a dictionary which contains keys as in prop_keys and its values from the report. :param report: SCCI report element :param prop_keys: a list of keys for essential properties :returns: a dictionary which contains keys as in prop_keys and its values. """ v = {} v['memory_mb'] = int(report.find('./System/Memory/Installed').text) v['local_gb'] = sum( [int(int(size.text) / 1024) for size in report.findall('.//PhysicalDrive/ConfigurableSize')]) v['cpus'] = sum([int(cpu.find('./CoreNumber').text) for cpu in report.find('./System/Processor') if cpu.find('./CoreNumber') is not None]) # v['cpus'] = sum([int(cpu.find('./LogicalCpuNumber').text) # for cpu in report.find('./System/Processor')]) v['cpu_arch'] = 'x86_64' return {k: v[k] for k in prop_keys} def get_capabilities_properties(d_info, capa_keys, gpu_ids, fpga_ids=None, **kwargs): """get capabilities properties This function returns a dictionary which contains keys and their values from the report. :param d_info: the dictionary of ipmitool parameters for accessing a node. :param capa_keys: a list of keys for additional capabilities properties. :param gpu_ids: the list of string contains / for GPU. :param fpga_ids: the list of string contains / for CPU FPGA. :param kwargs: additional arguments passed to scciclient. :returns: a dictionary which contains keys and their values. """ 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: v['rom_firmware_version'] = \ snmp.get_bios_firmware_version(snmp_client) if 'irmc_firmware_version' in capa_keys: v['irmc_firmware_version'] = \ snmp.get_irmc_firmware_version(snmp_client) if 'server_model' in capa_keys: v['server_model'] = snmp.get_server_model(snmp_client) # Sometime the server started but PCI device list building is # still in progress so system will response error. We have to wait # for some more seconds. if kwargs.get('sleep_flag', False) and \ any(k in capa_keys for k in ('pci_gpu_devices', 'cpu_fpga')): time.sleep(5) if 'pci_gpu_devices' in capa_keys: v['pci_gpu_devices'] = ipmi.get_pci_device(d_info, gpu_ids) if fpga_ids is not None and 'cpu_fpga' in capa_keys: v['cpu_fpga'] = ipmi.get_pci_device(d_info, fpga_ids) if 'trusted_boot' in capa_keys: v['trusted_boot'] = ipmi.get_tpm_status(d_info) return v except (snmp.SNMPFailure, ipmi.IPMIFailure) as err: 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': , '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 This function returns a fgi status which contains activity status and its values from the report. :param report: SCCI report information :returns: dict of fgi status of logical_drives, such as Initializing (10%) or Idle. e.g: {'0': 'Idle', '1': 'Initializing (10%)'} :raises: SCCIInvalidInputError: fail report input. SCCIRAIDNotReady: waiting for RAID configuration to complete. """ fgi_status = {} raid_path = "./Software/ServerView/ServerViewRaid" if not report.find(raid_path): raise SCCIInvalidInputError( "ServerView RAID not available in Bare metal Server") if not report.find(raid_path + "/amEMSV/System/Adapter/LogicalDrive"): raise SCCIRAIDNotReady( "RAID configuration not configure in Bare metal Server yet") logical_drives = report.findall(raid_path + "/amEMSV/System/Adapter/LogicalDrive") for logical_drive_name in logical_drives: status = logical_drive_name.find("./Activity").text name = logical_drive_name.find("./LogDriveNumber").text 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) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/irmc/snmp.py0000664000175000017500000002602500000000000021665 0ustar00zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # 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 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' BIOS_FW_VERSION_OID = '1.3.6.1.4.1.231.2.10.2.2.10.4.1.1.11.1' SERVER_MODEL_OID = '1.3.6.1.4.1.231.2.10.2.2.10.2.3.1.4.1' SNMP_V1 = '1' SNMP_V2C = '2c' SNMP_V3 = '3' SNMP_FAILURE_MSG = "SNMP operation '%s' failed: %s" class SNMPFailure(Exception): """SNMP Failure This exception is used when invalid inputs are passed to the APIs exposed by this module. """ def __init__(self, message): super(SNMPFailure, self).__init__(message) class SNMPIRMCFirmwareFailure(SNMPFailure): """SNMP iRMC Firmware Failure This exception is used when error occurs when collecting iRMC firmware. """ def __init__(self, message): super(SNMPIRMCFirmwareFailure, self).__init__(message) class SNMPBIOSFirmwareFailure(SNMPFailure): """SNMP BIOS Firmware Failure This exception is used when error occurs when collecting BIOS firmware. """ def __init__(self, message): super(SNMPBIOSFirmwareFailure, self).__init__(message) class SNMPServerModelFailure(SNMPFailure): """SNMP Server Model Failure This exception is used when error occurs when collecting server model. """ def __init__(self, message): super(SNMPServerModelFailure, self).__init__(message) def get_irmc_firmware_version(snmp_client): """Get irmc firmware version of the node. :param snmp_client: an SNMP client object. :raises: SNMPFailure if SNMP operation failed. :returns: a string of bmc name and irmc firmware version. """ try: bmc_name = snmp_client.get(BMC_NAME_OID) irmc_firm_ver = snmp_client.get(IRMC_FW_VERSION_OID) return ('%(bmc)s%(sep)s%(firm_ver)s' % {'bmc': bmc_name if bmc_name else '', 'firm_ver': irmc_firm_ver if irmc_firm_ver else '', 'sep': '-' if bmc_name and irmc_firm_ver else ''}) except SNMPFailure as e: raise SNMPIRMCFirmwareFailure( SNMP_FAILURE_MSG % ("GET IRMC FIRMWARE VERSION", e)) def get_bios_firmware_version(snmp_client): """Get bios firmware version of the node. :param snmp_client: an SNMP client object. :raises: SNMPFailure if SNMP operation failed. :returns: a string of bios firmware version. """ try: bios_firmware_version = snmp_client.get(BIOS_FW_VERSION_OID) return six.text_type(bios_firmware_version) except SNMPFailure as e: raise SNMPBIOSFirmwareFailure( SNMP_FAILURE_MSG % ("GET BIOS FIRMWARE VERSION", e)) def get_server_model(snmp_client): """Get server model of the node. :param snmp_client: an SNMP client object. :raises: SNMPFailure if SNMP operation failed. :returns: a string of server model. """ try: server_model = snmp_client.get(SERVER_MODEL_OID) return six.text_type(server_model) except SNMPFailure as e: raise SNMPServerModelFailure( SNMP_FAILURE_MSG % ("GET SERVER MODEL", e)) class SNMPClient(object): """SNMP client object. Performs low level SNMP get and set operations. Encapsulates all interaction with PySNMP to simplify dynamic importing and unit testing. """ 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.user = user self.auth_proto = auth_proto self.auth_key = auth_key self.priv_proto = priv_proto self.priv_key = priv_key else: 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, write_mode=False): """Return the authorization data for an SNMP request. :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 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 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.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 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. :param oid: The OID of the object to get. :raises: SNMPFailure if an SNMP request fails. :returns: The value of the requested object. """ try: 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 = next(snmp_gen) if error_indication: # SNMP engine-level error. raise SNMPFailure(SNMP_FAILURE_MSG % ("GET", error_indication)) if error_status: # SNMP PDU error. raise SNMPFailure( "SNMP operation '%(operation)s' failed: %(error)s at" " %(index)s" % {'operation': "GET", 'error': error_status.prettyPrint(), 'index': error_index and var_binds[int(error_index) - 1] or '?'}) # We only expect a single value back name, val = var_binds[0] return val def get_next(self, oid): """Use PySNMP to perform an SNMP GET NEXT operation on a table object. :param oid: The OID of the object to get. :raises: SNMPFailure if an SNMP request fails. :returns: A list of values of the requested table object. """ try: 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)) 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 '?'}) name, value = var_binds[0] vals.append(value) return vals def set(self, oid, value): """Use PySNMP to perform an SNMP SET operation on a single object. :param oid: The OID of the object to set. :param value: The value of the object to set. :raises: SNMPFailure if an SNMP request fails. """ try: 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 = next(snmp_gen) if error_indication: # SNMP engine-level error. raise SNMPFailure(SNMP_FAILURE_MSG % ("SET", error_indication)) if error_status: # SNMP PDU error. raise SNMPFailure( "SNMP operation '%(operation)s' failed: %(error)s at" " %(index)s" % {'operation': "SET", 'error': error_status.prettyPrint(), 'index': error_index and var_binds[int(error_index) - 1] or '?'}) ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1692971673.1186543 python-scciclient-0.15.0/scciclient/irmc/viom/0000775000175000017500000000000000000000000021303 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/irmc/viom/__init__.py0000664000175000017500000000000000000000000023402 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/irmc/viom/client.py0000664000175000017500000003753100000000000023144 0ustar00zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import abc import re import socket import struct import six from scciclient.irmc import scci from scciclient.irmc.viom import elcm ONBOARD = 'onboard' ADDON = 'addon' _CARD_DICT = { ONBOARD: elcm.OnboardCard, ADDON: elcm.AddOnCard} LAN = 'LAN' FC = 'FC' CNA = 'CNA' _ADAPTER_DICT = { LAN: elcm.LANAdapter, FC: elcm.FCAdapter, CNA: elcm.CNAAdapter } _POSSIBLE_CARD_TYPE = _ADAPTER_DICT.keys() _CNA_LAN_FUNC_IDX = 1 _CNA_FCOE_FUNC_IDX = 2 _CNA_ISCSI_FUNC_IDX = 3 @six.add_metaclass(abc.ABCMeta) class _PortHandler(object): """VIOM Configurator with physical port information""" def __init__(self, slot_type, card_type, slot_idx, card_idx, port_idx): self.slot_type = slot_type self.card_type = card_type self.slot_idx = slot_idx self.card_idx = card_idx self.port_idx = port_idx def need_padding(self): return False def create_card(self): return _CARD_DICT[self.slot_type]( self.card_idx, _ADAPTER_DICT[self.card_type]()) def create_lan_port(self, mac=None, port_enable=True): raise NotImplementedError() def set_lan_port(self, port, mac=None): raise NotImplementedError() def set_iscsi_port(self, port, iscsi_boot): raise NotImplementedError() def create_iscsi_port(self, iscsi_boot): raise NotImplementedError() def set_fc_port(self, port, fc_boot, wwnn=None, wwpn=None): raise NotImplementedError() def create_fc_port(self, fc_boot, wwnn=None, wwpn=None): raise NotImplementedError() class _LANPortHandler(_PortHandler): """Configurator for LAN card.""" def need_padding(self): return True if self.slot_type == ONBOARD else False def create_lan_port(self, mac=None, port_enable=True): return elcm.LANPort(self.port_idx, port_enable=port_enable, use_virtual_addresses=bool(mac), mac=mac) def set_lan_port(self, port, mac=None): port.port_enable = True port.mac = mac port.use_virtual_addresses = bool(mac) def set_iscsi_port(self, port, iscsi_boot): port.boot = iscsi_boot def create_iscsi_port(self, iscsi_boot): return elcm.LANPort(self.port_idx, boot=iscsi_boot, port_enable=True) class _FCPortHandler(_PortHandler): """Configurator for FC card.""" def set_fc_port(self, port, fc_boot, wwnn=None, wwpn=None): port.boot = fc_boot port.port_enable = True port.use_virtual_addresses = bool(wwnn or wwpn) port.wwnn = wwnn port.wwpn = wwpn def create_fc_port(self, fc_boot, wwnn=None, wwpn=None): return elcm.FCPort(self.port_idx, boot=fc_boot, wwnn=wwnn, wwpn=wwpn, use_virtual_addresses=bool(wwnn or wwpn), port_enable=True) class _CNAPortHandler(_PortHandler): """Configurator for CNA card.""" def _create_port(self, function): cna_port = elcm.CNAPort(self.port_idx) if not isinstance(function, elcm.LANFunction): # LanFunction is must cna_port.add_function( elcm.LANFunction(_CNA_LAN_FUNC_IDX, function_enable=False, boot=None)) cna_port.add_function(function) return cna_port def create_lan_port(self, mac=None, port_enable=True): function = elcm.LANFunction(_CNA_LAN_FUNC_IDX, function_enable=port_enable, use_virtual_addresses=bool(mac), mac=mac) return self._create_port(function) def set_lan_port(self, port, mac=None): function = port.get_function(_CNA_LAN_FUNC_IDX) # Lan Function is always created when port is created. function.function_enable = True function.mac = mac function.use_virtual_addresses = bool(mac) def set_iscsi_port(self, port, iscsi_boot): function = port.get_function(_CNA_ISCSI_FUNC_IDX) if function: function.boot = iscsi_boot else: function = elcm.ISCSIFunction(_CNA_ISCSI_FUNC_IDX, boot=iscsi_boot, function_enable=True) port.add_function(function) def create_iscsi_port(self, iscsi_boot): function = elcm.ISCSIFunction(_CNA_ISCSI_FUNC_IDX, boot=iscsi_boot) return self._create_port(function) def set_fc_port(self, port, fc_boot, wwnn=None, wwpn=None): function = port.get_function(_CNA_FCOE_FUNC_IDX) if function: function.boot = fc_boot function.use_virtual_addresses = bool(wwnn or wwpn) function.wwnn = wwnn function.wwpn = wwpn else: function = elcm.FCoEFunction( _CNA_FCOE_FUNC_IDX, boot=fc_boot, function_enable=True, use_virtual_addresses=bool(wwnn or wwpn), wwnn=wwnn, wwpn=wwpn) port.add_function(function) def create_fc_port(self, fc_boot, wwnn=None, wwpn=None): function = elcm.FCoEFunction( _CNA_FCOE_FUNC_IDX, boot=fc_boot, function_enable=True, use_virtual_addresses=bool(wwnn or wwpn), wwnn=wwnn, wwpn=wwpn) return self._create_port(function) _PORT_HANDLERS = { LAN: _LANPortHandler, FC: _FCPortHandler, CNA: _CNAPortHandler, } def _parse_physical_port_id(port_id): message = ('Physical port ID should follow the format: ' '- like CNA1-1. ' ' must be chosen from CNA, FC, or LAN. ' ' should be 0 for onboard slot or 1-9 for addon ' 'slot. should be 1-9.') m = re.match('^([a-zA-Z]+)([0-9])-([1-9])$', port_id) if not m: raise scci.SCCIInvalidInputError(message) card_type = m.group(1).upper() if card_type not in _POSSIBLE_CARD_TYPE: raise scci.SCCIInvalidInputError(message) slot_idx = 0 if int(m.group(2)) == 0: slot_type = ONBOARD card_idx = 1 else: slot_type = ADDON card_idx = int(m.group(2)) port_idx = int(m.group(3)) return _PORT_HANDLERS[card_type](slot_type, card_type, slot_idx, card_idx, port_idx) def _create_iscsi_boot(initiator_iqn, initiator_dhcp=False, initiator_ip=None, initiator_netmask=None, target_dhcp=False, target_iqn=None, target_ip=None, target_port=None, target_lun=None, boot_prio=1, chap_user=None, chap_secret=None, mutual_chap_secret=None): iscsi_initiator = elcm.ISCSIInitiator(dhcp_usage=initiator_dhcp, iqn=initiator_iqn, ip=initiator_ip, subnet=initiator_netmask) if chap_user and chap_secret: auth_method = 'MutualCHAP' if mutual_chap_secret else 'CHAP' else: auth_method = 'None' iscsi_target = elcm.ISCSITarget(dhcp_usage=target_dhcp, iqn=target_iqn, ip=target_ip, port=target_port, lun=target_lun, auth_method=auth_method, chap_user=chap_user, chap_secret=chap_secret, mutual_chap_secret=mutual_chap_secret) iscsi_boot = elcm.ISCSIBoot(iscsi_initiator, iscsi_target, boot_prio=boot_prio) return iscsi_boot def _convert_netmask(mask): """Convert netmask from CIDR format(integer) to doted decimal string.""" if mask not in range(0, 33): raise scci.SCCIInvalidInputError( 'Netmask value is invalid.') return socket.inet_ntoa(struct.pack( '!L', int('1' * mask + '0' * (32 - mask), 2))) class VIOMConfiguration(object): """VIOM Configurator for volume boot""" def __init__(self, irmc_info, identification): self.client = elcm.ELCMVIOMClient(irmc_info) self.root = elcm.VIOMTable() self.root.set_manage_table( elcm.ManageTable(identification=identification)) def apply(self, reboot=False): """Apply the configuration to iRMC.""" self.root.use_virtual_addresses = True self.root.manage.manage = True self.root.mode = 'new' self.root.init_boot = reboot self.client.set_profile(self.root.get_json()) def terminate(self, reboot=False): """Delete VIOM configuration from iRMC.""" self.root.manage.manage = False self.root.mode = 'delete' self.root.init_boot = reboot self.client.set_profile(self.root.get_json()) def _find_card(self, port_handler): slot = self.root.get_slot(port_handler.slot_idx, create=False) if not slot: return None if port_handler.slot_type == ONBOARD: return slot.get_onboard_card(port_handler.card_idx) else: return slot.get_addon_card(port_handler.card_idx) def _get_card(self, port_handler): card = self._find_card(port_handler) if card: return card card = port_handler.create_card() self.root.get_slot(port_handler.slot_idx).add_card(card) return card def _find_port(self, port_handler): card = self._find_card(port_handler) if not card: return None return card.get_port(port_handler.port_idx) def _add_port(self, port_handler, port): self._pad_former_ports(port_handler) card = self._get_card(port_handler) card.add_port(port) def set_lan_port(self, port_id, mac=None): """Set LAN port information to configuration. :param port_id: Physical port ID. :param mac: virtual MAC address if virtualization is necessary. """ port_handler = _parse_physical_port_id(port_id) port = self._find_port(port_handler) if port: port_handler.set_lan_port(port, mac) else: self._add_port(port_handler, port_handler.create_lan_port(mac)) def set_iscsi_volume(self, port_id, initiator_iqn, initiator_dhcp=False, initiator_ip=None, initiator_netmask=None, target_dhcp=False, target_iqn=None, target_ip=None, target_port=3260, target_lun=0, boot_prio=1, chap_user=None, chap_secret=None, mutual_chap_secret=None): """Set iSCSI volume information to configuration. :param port_id: Physical port ID. :param initiator_iqn: IQN of initiator. :param initiator_dhcp: True if DHCP is used in the iSCSI network. :param initiator_ip: IP address of initiator. None if DHCP is used. :param initiator_netmask: Netmask of initiator as integer. None if DHCP is used. :param target_dhcp: True if DHCP is used for iSCSI target. :param target_iqn: IQN of target. None if DHCP is used. :param target_ip: IP address of target. None if DHCP is used. :param target_port: Port number of target. None if DHCP is used. :param target_lun: LUN number of target. None if DHCP is used, :param boot_prio: Boot priority of the volume. 1 indicates the highest priority. """ initiator_netmask = (_convert_netmask(initiator_netmask) if initiator_netmask else None) port_handler = _parse_physical_port_id(port_id) iscsi_boot = _create_iscsi_boot( initiator_iqn, initiator_dhcp=initiator_dhcp, initiator_ip=initiator_ip, initiator_netmask=initiator_netmask, target_dhcp=target_dhcp, target_iqn=target_iqn, target_ip=target_ip, target_port=target_port, target_lun=target_lun, boot_prio=boot_prio, chap_user=chap_user, chap_secret=chap_secret, mutual_chap_secret=mutual_chap_secret) port = self._find_port(port_handler) if port: port_handler.set_iscsi_port(port, iscsi_boot) else: port = port_handler.create_iscsi_port(iscsi_boot) self._add_port(port_handler, port) def set_fc_volume(self, port_id, target_wwn, target_lun=0, boot_prio=1, initiator_wwnn=None, initiator_wwpn=None): """Set FibreChannel volume information to configuration. :param port_id: Physical port ID. :param target_wwn: WWN of target. :param target_lun: LUN number of target. :param boot_prio: Boot priority of the volume. 1 indicates the highest priority. :param initiator_wwnn: Virtual WWNN for initiator if necessary. :param initiator_wwpn: Virtual WWPN for initiator if necessary. """ port_handler = _parse_physical_port_id(port_id) fc_target = elcm.FCTarget(target_wwn, target_lun) fc_boot = elcm.FCBoot(boot_prio=boot_prio, boot_enable=True) fc_boot.add_target(fc_target) port = self._find_port(port_handler) if port: port_handler.set_fc_port(port, fc_boot, wwnn=initiator_wwnn, wwpn=initiator_wwpn) else: port = port_handler.create_fc_port(fc_boot, wwnn=initiator_wwnn, wwpn=initiator_wwpn) self._add_port(port_handler, port) def dump_json(self): """Create JSON profile based on current configuration. :returns: JSON data created from current configurtion. It can be logged by a caller. """ return self.root.get_json() def _pad_former_ports(self, port_handler): """Create ports with former port index. :param port_handler: Port information to be registered. Depending on slot type and card type, it is necessary to register LAN ports with former index to VIOM table. """ if not port_handler.need_padding(): return for port_idx in range(1, port_handler.port_idx): pad_handler = port_handler.__class__( port_handler.slot_type, port_handler.card_type, port_handler.slot_idx, port_handler.card_idx, port_idx) if not self._find_port(pad_handler): self._add_port(pad_handler, pad_handler.create_lan_port()) def validate_physical_port_id(port_id): """Validate physical port ID. Physical port ID is required for configure interfaces with VIOM API. The format is: - * Card type is chosen from CNA, FC or LAN. * Slot Idx should be 0, which indecates on-board slot or 1-9, which specify add-on slot index. * Port Idx should be 1-9, which indicate port number. :param port_id: Physical port ID following the format. """ _parse_physical_port_id(port_id) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/irmc/viom/elcm.py0000664000175000017500000006723700000000000022614 0ustar00zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import abc import json import time import six from scciclient.irmc import elcm from scciclient.irmc import scci PROFILE_NAME = 'AdapterConfigIrmc' PARAM_PATH = 'Server/AdapterConfigIrmc' class ELCMVIOMClient(object): """Client calling eLCM REST APIs for VIOM feature""" def __init__(self, irmc_info): self.irmc_info = irmc_info def _wait_session(self, session_id, timeout=1800): session_expiration = time.time() + timeout while True: resp = elcm.elcm_session_get_status(self.irmc_info, session_id) status = resp['Session']['Status'] if status == 'running' or status == 'activated': # Sleep a bit time.sleep(5) elif status == 'terminated regularly': return {} else: # Error occurred, get session log to see what happened try: session_log = elcm.elcm_session_get_log( irmc_info=self.irmc_info, session_id=session_id) except scci.SCCIClientError as e: raise scci.SCCIClientError( ('Operation Failed. Session %(session_id)s state is ' '%(session_state)s. Session log collection failed: ' '%(reason)s' % {'session_id': session_id, 'session_state': resp['Session']['Status'], 'reason': e})) raise scci.SCCIClientError( ('Operation failed. Session %(session_id)s state is ' '%(session_state)s. Session log is: "%(session_log)s".' % {'session_id': session_id, 'session_state': resp['Session']['Status'], 'session_log': json.dumps(session_log)})) # Check for timeout if time.time() > session_expiration: # Timeout occurred, get session log to see what happened try: session_log = elcm.elcm_session_get_log( irmc_info=self.irmc_info, session_id=session_id) except scci.SCCIClientError as e: raise elcm.ELCMSessionTimeout( 'Operation timed out. Session %(session_id)s has not ' 'finished in %(timeout)d seconds. Session log ' 'collection failed: %(reason)s' % {'session_id': session_id, 'timeout': timeout, 'reason': e}) raise elcm.ELCMSessionTimeout( 'Operation timed out. Session %(session_id)s has not ' 'finished in %(timeout)d seconds. Session log is: ' '"%(session_log)s.' % {'session_id': session_id, 'timeout': timeout, 'session_log': json.dumps(session_log)}) def set_profile(self, adapter_config): _adapter_config = dict(adapter_config) _adapter_config.update({'@Processing': 'execute'}) req = {'Server': {'AdapterConfigIrmc': _adapter_config, '@Version': '1.01'}} resp = elcm.elcm_profile_set(self.irmc_info, req) self._wait_session(resp['Session']['Id']) def get_profile(self): # delete old one try: elcm.elcm_profile_delete(self.irmc_info, PROFILE_NAME) except elcm.ELCMProfileNotFound: pass resp = elcm.elcm_profile_create(self.irmc_info, PARAM_PATH) self._wait_session(resp['Session']['Id']) resp = elcm.elcm_profile_get(self.irmc_info, PROFILE_NAME) return resp class VIOMAttribute(object): """Attribute in VIOM Element. This class is used for conversion between Python class and JSON table. """ def __init__(self, name, key, init=None): self.name = name self.key = key self.init = init @six.add_metaclass(abc.ABCMeta) class VIOMElement(object): """Element in VIOM table.""" def __init__(self, **kwargs): for attr in self.__class__._BASIC_ATTRIBUTES: setattr(self, attr.name, kwargs.get(attr.name, attr.init)) def get_basic_json(self): table = {} for attr in self.__class__._BASIC_ATTRIBUTES: value = getattr(self, attr.name) if value is not None: table[attr.key] = value return table class VIOMTable(VIOMElement): """Root class of VIOM table""" _BASIC_ATTRIBUTES = [ VIOMAttribute('use_virtual_addresses', 'UseVirtualAddresses'), VIOMAttribute('viom_boot_enable', 'VIOMBootEnable'), VIOMAttribute('boot_menu_enable', 'BootMenuEnable'), VIOMAttribute('sriov', 'SRIOV'), VIOMAttribute('smux', 'Smux'), VIOMAttribute('boot_mode', 'BootMode'), VIOMAttribute('init_boot', 'InitBoot'), VIOMAttribute('processing', '@Processing'), VIOMAttribute('mode', 'Mode'), VIOMAttribute('version', '@Version', '1.00'), ] def __init__(self, **kwargs): super(VIOMTable, self).__init__(**kwargs) self.slots = {} self.manage = None def get_slot(self, slot_idx, create=True): slot = self.slots.get(slot_idx) if slot or not create: return slot slot = Slot(slot_idx) self.slots[slot_idx] = slot return slot def set_manage_table(self, manage): self.manage = manage def get_json(self): """Create JSON data for AdapterConfig. :returns: JSON data as follows: { "VIOMManage":{ }, "InitBoot":{ }, "UseVirtualAddresses":{ }, "BootMenuEnable":{ }, "SmuxSetting":{ }, "Slots":{ } } """ viom_table = self.get_basic_json() if self.slots: viom_table['Slots'] = { 'Slot': [s.get_json() for s in self.slots.values()] } if self.manage: viom_table['VIOMManage'] = self.manage.get_json() return viom_table class ManageTable(VIOMElement): """Class for ViomManage element.""" _BASIC_ATTRIBUTES = [ VIOMAttribute('manage', 'Manage'), VIOMAttribute('identification', 'Identification'), VIOMAttribute('trap_destination', 'TrapDestination'), VIOMAttribute('force', 'Force'), VIOMAttribute('preferred_version', 'PreferredInventoryVersion') ] def __init__(self, **kwargs): super(ManageTable, self).__init__(**kwargs) def get_json(self): """Create JSON data for ViomManage. :returns: JSON data for ViomManage as follows: { "Manage":{ }, "Force":{ }, "Identification":{ }, "TrapDestination":{ }, "PreferredInventoryVersion":{ } } """ return self.get_basic_json() class Slot(VIOMElement): """Class for Slot element.""" _BASIC_ATTRIBUTES = [ VIOMAttribute('slot_idx', '@SlotIdx', 0), ] def __init__(self, slot_idx, **kwargs): super(Slot, self).__init__(slot_idx=slot_idx, **kwargs) self.onboard_cards = {} self.addon_cards = {} def add_card(self, card): if isinstance(card, OnboardCard): self.onboard_cards[card.card_idx] = card else: self.addon_cards[card.card_idx] = card def get_onboard_card(self, card_idx): return self.onboard_cards.get(card_idx) def get_addon_card(self, card_idx): return self.addon_cards.get(card_idx) def get_json(self): """Create JSON data for slot. :returns: JSON data for slot as follows: { "@SlotIdx":0, "OnboardControllers":{ "OnboardController": [ ] }, "AddOnCards":{ "AddOnCard": [ ] } } """ json = self.get_basic_json() if self.onboard_cards: json['OnboardControllers'] = { 'OnboardController': [c.get_json() for c in self.onboard_cards.values()] } if self.addon_cards: json['AddOnCards'] = { 'AddOnCard': [c.get_json() for c in self.addon_cards.values()] } return json @six.add_metaclass(abc.ABCMeta) class PCICard(object): "Abstract class for PCI cards." def __init__(self, card_idx, adapter): self.card_idx = card_idx self.adapter = adapter def add_port(self, port): self.adapter.add_port(port) def get_port(self, port_idx): return self.adapter.get_port(port_idx) def get_json(self): """Create JSON data for PCI card element. :returns: JSON data for PCI card. Data for onboard card is as follows: { "@OnboardControllerIdx":1, "LANAdapter":{ }, "CNAAdapter":{ } } Data for add-on card is as follows: { "@AddOnCardIdx":1, "LANAdapter":{ }, "FCAdapter":{ }, "CNAAdapter":{ } } """ json = {self.INDEX_KEY: self.card_idx} json.update(self.adapter.get_json()) return json class OnboardCard(PCICard): """Class for onboard Card.""" INDEX_KEY = '@OnboardControllerIdx' class AddOnCard(PCICard): """Class for add on card.""" INDEX_KEY = '@AddOnCardIdx' @six.add_metaclass(abc.ABCMeta) class Adapter(object): """Abstract class for adapters. Adapter represents type of PCI card. """ def __init__(self): self.ports = {} def add_port(self, port): self.ports[port.port_idx] = port def get_port(self, port_idx): return self.ports.get(port_idx) def get_json(self): """Create JSON data for adapter :returns: JSON data for adapter as follows: { "LANAdapter":{ "Ports":{ "Port": [ ] } } } """ return { self.ADAPTER_NAME: { 'Ports': { 'Port': [p.get_json() for p in self.ports.values()] } } } class LANAdapter(Adapter): """LAN adapter.""" ADAPTER_NAME = 'LANAdapter' class FCAdapter(Adapter): """FC adapter.""" ADAPTER_NAME = 'FCAdapter' class CNAAdapter(Adapter): """CNA adatper.""" ADAPTER_NAME = 'CNAAdapter' @six.add_metaclass(abc.ABCMeta) class AdapterPort(VIOMElement): """Port in adapters.""" def __init__(self, port_idx, **kwargs): super(AdapterPort, self).__init__(port_idx=port_idx, **kwargs) class LANPort(AdapterPort): """LAN Port.""" _BASIC_ATTRIBUTES = [ VIOMAttribute('port_idx', '@PortIdx', 1), VIOMAttribute('port_enable', 'PortEnable'), VIOMAttribute('sriov', 'SRIOV'), VIOMAttribute('use_virtual_addresses', 'UseVirtualAddresses'), ] def __init__(self, port_idx, port_enable=True, mac=None, boot=None, **kwargs): super(LANPort, self).__init__(port_idx, port_enable=port_enable, **kwargs) self.mac = mac self.boot = boot if boot else NoneBoot() def get_json(self): """Create JSON data for LANPort. :returns: JSON data as follows: { "@PortIdx":1, "PortEnable":{ }, "UseVirtualAddresses":{ }, "BootProtocol":{ }, "VirtualAddress":{ "MAC":{ } }, "BootPriority":{ }, "ISCSIBootEnvironment":{ } } """ port = self.get_basic_json() port.update({ 'BootProtocol': self.boot.BOOT_PROTOCOL, 'BootPriority': self.boot.boot_prio, }) boot_env = self.boot.get_json() if boot_env: port.update(boot_env) if self.use_virtual_addresses and self.mac: port['VirtualAddress'] = {'MAC': self.mac} return port class FCPort(AdapterPort): """FC Port.""" _BASIC_ATTRIBUTES = [ VIOMAttribute('port_idx', '@PortIdx', 1), VIOMAttribute('port_enable', 'PortEnable'), VIOMAttribute('sriov', 'SRIOV'), VIOMAttribute('use_virtual_addresses', 'UseVirtualAddresses'), ] def __init__(self, port_idx, port_enable=True, wwnn=None, wwpn=None, boot=None, **kwargs): super(FCPort, self).__init__(port_idx, port_enable=port_enable, **kwargs) self.wwnn = wwnn self.wwpn = wwpn self.boot = boot if boot else NoneBoot() def get_json(self): """Create FC port. :returns: JSON for FC port as follows: { "@PortIdx":1, "PortEnable":{ }, "UseVirtualAddresses":{ }, "VirtualAddress":{ "WWNN":{ }, "WWPN":{ }, "MAC":{ } }, "BootProtocol":{ }, "BootPriority":{ }, "FCBootEnvironment":{ } } """ port = self.get_basic_json() port.update({ 'BootProtocol': self.boot.BOOT_PROTOCOL, 'BootPriority': self.boot.boot_prio, }) boot_env = self.boot.get_json() if boot_env: port.update(boot_env) if self.use_virtual_addresses: addresses = {} if self.wwnn: addresses['WWNN'] = self.wwnn if self.wwpn: addresses['WWPN'] = self.wwpn if addresses: port['VirtualAddress'] = addresses return port class CNAPort(AdapterPort): """CNA port.""" _BASIC_ATTRIBUTES = [ VIOMAttribute('port_idx', '@PortIdx', 1), VIOMAttribute('port_enable', 'PortEnable'), ] def __init__(self, port_idx, port_enable=True): super(CNAPort, self).__init__(port_idx, port_enable=port_enable) self.functions = {} def add_function(self, function): self.functions[function.func_idx] = function def get_function(self, func_idx): return self.functions.get(func_idx) def get_json(self): """Create JSON for CNA port. :returns: JSON for CNA port as follows: { "@PortIdx":1, "PortEnable":{ }, "Functions":{ } } """ port = self.get_basic_json() port['Functions'] = { 'Function': [f.get_json() for f in self.functions.values()] } return port @six.add_metaclass(abc.ABCMeta) class CNAFunction(VIOMElement): """Abstract class for Functions for CNA card""" _BASIC_ATTRIBUTES = [ VIOMAttribute('function_enable', 'FunctionEnable'), VIOMAttribute('vlan_id', 'VLANId'), VIOMAttribute('sriov', 'SRIOV'), VIOMAttribute('use_virtual_addresses', 'UseVirtualAddresses'), VIOMAttribute('bandwidth', 'Bandwidth'), VIOMAttribute('rate_limit', 'RateLimit'), ] def __init__(self, func_idx, function_enable=True, boot=None, **kwargs): super(CNAFunction, self).__init__(**kwargs) self.func_idx = func_idx self.boot = boot if boot else NoneBoot() self.function_enable = function_enable def _get_virtual_addresses_json(self, json): return None def get_json(self): """Create JSON for CNA function. :returns: JSON for CNA function. * LANFunction creates the following JSON: { "LANFunction":{ "FunctionEnable":{ }, "BootProtocol":{ }, "UseVirtualAddresses":{ }, "BootPriority":{ }, "Bandwidth":{ }, "RateLimit":{ }, "VLANId":{ }, "VirtualAddress":{ "MAC":{ } } } } * FCoEFunction creates the following JSON: { "FCoEFunction":{ "FunctionEnable":{ }, "BootProtocol":{ }, "UseVirtualAddresses":{ }, "BootPriority":{ }, "Bandwidth":{ }, "RateLimit":{ }, "VLANId":{ }, "VirtualAddress":{ "WWNN":{ }, "WWPN":{ }, "MAC":{ } }, "FCBootEnvironment":{ } } } * ISCSIFunction creates the following JSON: { "@FunctionIdx": 1, "ISCSIFunction":{ "FunctionEnable":{ }, "BootProtocol":{ }, "UseVirtualAddresses":{ }, "BootPriority":{ }, "Bandwidth":{ }, "RateLimit":{ }, "VLANId":{ }, "VirtualAddress":{ "MAC":{ } }, "ISCSIBootEnvironment":{ } } } """ function = self.get_basic_json() function['BootProtocol'] = self.boot.BOOT_PROTOCOL function['BootPriority'] = self.boot.boot_prio if self.use_virtual_addresses: virtual_addresses = self._get_virtual_addresses_json() if virtual_addresses: function['VirtualAddress'] = virtual_addresses boot_env = self.boot.get_json() if boot_env: function.update(boot_env) return {'@FunctionIdx': self.func_idx, self.FUNCTION_NAME: function} class LANFunction(CNAFunction): """LAN function for CNA card""" FUNCTION_NAME = 'LANFunction' def __init__(self, func_idx, function_enable=True, boot=None, mac=None, **kwargs): super(LANFunction, self).__init__( func_idx, function_enable=function_enable, boot=boot, **kwargs) self.mac = mac def _get_virtual_addresses_json(self): return {'MAC': self.mac} if self.mac else None class FCoEFunction(CNAFunction): """FCoE Function for CNA card.""" FUNCTION_NAME = 'FCoEFunction' def __init__(self, func_idx, function_enable=True, boot=None, wwnn=None, wwpn=None, mac=None, **kwargs): super(FCoEFunction, self).__init__( func_idx, function_enable=function_enable, boot=boot, **kwargs) self.wwnn = wwnn self.wwpn = wwpn self.mac = mac def _get_virtual_addresses_json(self): virtual_addresses = {} if self.mac: virtual_addresses['MAC'] = self.mac if self.wwnn: virtual_addresses['WWNN'] = self.wwnn if self.wwpn: virtual_addresses['WWPN'] = self.wwpn return virtual_addresses class ISCSIFunction(CNAFunction): """iSCSI Function for CNA card.""" FUNCTION_NAME = 'ISCSIFunction' def __init__(self, func_idx, function_enable=True, boot=None, mac=None, **kwargs): super(ISCSIFunction, self).__init__( func_idx, function_enable=function_enable, boot=boot, **kwargs) self.mac = mac def _get_virtual_addresses_json(self): return {'MAC': self.mac} if self.mac else None @six.add_metaclass(abc.ABCMeta) class Boot(VIOMElement): """Abstract class for BootProtocol""" _BASIC_ATTRIBUTES = [] def __init__(self, boot_prio=1, **kwargs): super(Boot, self).__init__(**kwargs) self.boot_prio = boot_prio def get_json(self): return {} class NoneBoot(Boot): """None BootProtocol.""" BOOT_PROTOCOL = 'None' class PXEBoot(Boot): """PXE BootProtocol.""" BOOT_PROTOCOL = 'PXE' class FCBoot(Boot): """FC BootProtocol with FCBootEnvironment elemnt.""" BOOT_PROTOCOL = 'FC' _BASIC_ATTRIBUTES = [ VIOMAttribute('link_speed', 'FCLinkSpeed', 'auto'), VIOMAttribute('topology', 'FCTopology', 'auto_loop'), VIOMAttribute('boot_enable', 'SANBootEnable'), ] def __init__(self, boot_prio=1, **kwargs): super(FCBoot, self).__init__(boot_prio, **kwargs) self.targets = [] def add_target(self, target): self.targets.append(target) def get_json(self): """Create JSON for FCBootEnvironment. :returns: JSON for FCBootEnvironment as follows: { "FCBootEnvironment":{ "FCTargets":{ "FCTarget":[ ] }, "FCLinkSpeed":{ }, "SANBootEnable":{ }, "FCTopology":{ } } } """ json = self.get_basic_json() for i in range(len(self.targets)): # @FCTargetIdx starts from 1. self.targets[i].set_index(i + 1) json['FCTargets'] = { 'FCTarget': [t.get_json() for t in self.targets] } return {'FCBootEnvironment': json} class FCTarget(VIOMElement): """FC Target.""" _BASIC_ATTRIBUTES = [ VIOMAttribute('index', '@FCTargetIdx', 1), VIOMAttribute('wwpn', 'TargetWWPN'), VIOMAttribute('lun', 'TargetLUN') ] def __init__(self, wwpn, lun=0, **kwargs): super(FCTarget, self).__init__(wwpn=wwpn, lun=lun) def set_index(self, index): self.index = index def get_json(self): """Create JSON for FCTarget. :returns: JSON data for FCTarget as follows: { "@FCTargetIdx":1, "TargetWWPN":{ }, "TargetLUN":{ } } """ return self.get_basic_json() class ISCSIBoot(Boot): """iSCSI BootProtocol with ISCSIBootEnvironment elment.""" BOOT_PROTOCOL = 'ISCSI' def __init__(self, initiator, target, boot_prio=1): super(ISCSIBoot, self).__init__(boot_prio) self.initiator = initiator self.target = target def get_json(self): """Create JSON for ISCSIBoot. :returns: JSON data for ISCSIBoot as follows: { "ISCSIBootEnvironment":{ "ISCSIInitiator":{ }, "ISCSITarget":{ } } } """ return { 'ISCSIBootEnvironment': { 'ISCSIInitiator': self.initiator.get_json(), 'ISCSITarget': self.target.get_json() } } class ISCSIInitiator(VIOMElement): """iSCSIInitiator.""" _BASIC_ATTRIBUTES = [ VIOMAttribute('dhcp_usage', 'DHCPUsage', False), VIOMAttribute('iqn', 'Name'), VIOMAttribute('ip', 'IPv4Address'), VIOMAttribute('subnet', 'SubnetMask'), VIOMAttribute('gateway', 'GatewayIPv4Address'), VIOMAttribute('vlan_id', 'VLANId', 0), ] def __init__(self, **kwargs): super(ISCSIInitiator, self).__init__(**kwargs) def get_json(self): """Create JSON data for iSCSI initiator. :returns: JSON data for iSCSI initiator as follows: { "DHCPUsage":{ }, "Name":{ }, "IPv4Address":{ }, "SubnetMask":{ }, "GatewayIPv4Address":{ }, "VLANId":{ } } """ if self.dhcp_usage: return {'DHCPUsage': self.dhcp_usage, 'Name': self.iqn} else: return self.get_basic_json() class ISCSITarget(VIOMElement): """iSCSI target.""" _BASIC_ATTRIBUTES = [ VIOMAttribute('dhcp_usage', 'DHCPUsage', False), VIOMAttribute('iqn', 'Name'), VIOMAttribute('ip', 'IPv4Address'), VIOMAttribute('port', 'PortNumber', 3260), VIOMAttribute('lun', 'BootLUN', 0), VIOMAttribute('auth_method', 'AuthenticationMethod', 'None'), VIOMAttribute('chap_user', 'ChapUserName'), VIOMAttribute('chap_secret', 'ChapSecret'), VIOMAttribute('mutual_chap_secret', 'MutualChapSecret'), ] def __init__(self, **kwargs): super(ISCSITarget, self).__init__(**kwargs) def get_json(self): """Create JSON data for iSCSI target. :returns: JSON data for iSCSI target as follows: { "DHCPUsage":{ }, "Name":{ }, "IPv4Address":{ }, "PortNumber":{ }, "BootLUN":{ }, "AuthenticationMethod":{ }, "ChapUserName":{ }, "ChapSecret":{ }, "MutualChapSecret":{ } } """ json = { 'DHCPUsage': self.dhcp_usage, 'AuthenticationMethod': self.auth_method, } if not self.dhcp_usage: json['Name'] = self.iqn json['IPv4Address'] = self.ip json['PortNumber'] = self.port json['BootLUN'] = self.lun if self.chap_user: json['ChapUserName'] = self.chap_user if self.chap_secret: json['ChapSecret'] = self.chap_secret if self.mutual_chap_secret: json['MutualChapSecret'] = self.mutual_chap_secret return json ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1692971673.1186543 python-scciclient-0.15.0/scciclient/tests/0000775000175000017500000000000000000000000020541 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/__init__.py0000664000175000017500000000000000000000000022640 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1692971673.122654 python-scciclient-0.15.0/scciclient/tests/irmc/0000775000175000017500000000000000000000000021473 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/irmc/__init__.py0000664000175000017500000000000000000000000023572 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1692971673.122654 python-scciclient-0.15.0/scciclient/tests/irmc/fixtures/0000775000175000017500000000000000000000000023344 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/irmc/fixtures/irmc_report_ng.xml0000664000175000017500000007406400000000000027112 0ustar00zuulzuul00000000000000 true 2014/12/15 18:46:20 14 FUJITSU iRMC38058D iRMC S4 7.65F SDR: 3.71 ID 0356 RX300S8 10.124.196.159 fe80::921b:eff:fe38:58d 4 important error(s) in system event log (SEL)! 1 important warning(s) in system event log SEL 2 important warning(s) in internal event log IEL V4.6.5.4 R1.14.0 for D2939-B1x CPU1 Intel Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz 2600 1 8 16 8000 512 2048 20480 CPU2 Intel Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz 2600 1 8 16 8000 512 2048 20480 CPU2 0 8192 0 0 0 0 0 0 0 0 0 0 0 0 1 true 8192 DDR3 1600 9128 9128 Micron Technology 2014,37 18KSF1G72PZ-1G6E2 12869 730413837 RDIMM DDR3_SDRAM 1Gx4/16x11x3 1600 1.35V/1.5V 5;6;7;8;9;10;11; 72 1 0 0 0 0 0 0 0 0 0 0 0 0 1 5820 5820 5700 1 5820 6000 5820 1 5820 5820 5700 1 5700 5700 5580 1 6000 6000 5820 1 3600 17920 17920 1 3680 17920 17920 6 28 37 42 6 28 75 80 6 33 75 80 6 37 82 86 6 37 82 86 0 0 0 0 6 29 78 82 0 0 0 6 28 57 61 6 28 57 61 6 53 102 107 6 52 102 107 0 6 69 110 115 1 76 1 80 1 3.15 3.00 2.01 3.50 1 11.88 12.00 11.28 12.96 1 5.10 5.00 4.63 5.42 1 3.30 3.30 3.02 3.57 1 1.78 1.80 1.67 1.93 1 1.48 1.50 1.39 1.61 1 0.98 1.00 0.93 1.08 1 12.16 12.00 11.31 12.90 1 4.98 5.00 4.63 5.42 1 3.35 3.30 3.02 3.57 1 1.47 1.50 1.42 1.58 1 1.09 1.10 1.02 1.18 1 0.99 1.00 0.93 1.07 1 0.98 1.00 0.93 1.07 1 1000 11E4 005B 1734 Mass storage controller RAID controller 7 1 10DF E208 E200 10DF Serial bus controller Fibre Channel 1 1 10DF E208 E200 10DF Serial bus controller Fibre Channel 1 1 8086 00A2 1521 8086 Network controller Ethernet controller 5 1 8086 00A2 1521 8086 Network controller Ethernet controller 5 1 8086 001A 1528 8086 Network controller Ethernet controller 6 1 8086 001A 1528 8086 Network controller Ethernet controller 6 2014/12/10 10:13:40 INFO 160011 BIOS change detected 02 D4 1C 88 54 01 00 04 2B 00 6F C1 09 00 2014/12/10 10:11:18 INFO 420020 Management Engine: Direct Flash update requested by the BIOS 02 46 1C 88 54 2C 00 04 DC 17 75 A0 06 00 2014/12/10 10:03:11 INFO 160014 Online firmware flash: iRMC S4 reboot EEPROM 1 Version 7.65 02 5F 1A 88 54 20 00 04 EC FE 6F A1 07 41 2014/12/10 09:57:50 INFO 160013 Online firmware flash EEPROM 1 Version 7.65 02 1E 19 88 54 20 00 04 EC FE 6F A0 07 41 2014/12/10 09:30:31 MAJOR 160018 BIOS TFTP or HTTP/HTTPS flash failed 02 B7 12 88 54 20 00 04 EC FE 6F 03 FF FF 2014/12/08 13:33:15 MAJOR 160018 BIOS TFTP or HTTP/HTTPS flash failed 02 9B A8 85 54 20 00 04 EC FE 6F 03 FF FF 2014/12/08 13:30:09 MAJOR 160018 BIOS TFTP or HTTP/HTTPS flash failed 02 E1 A7 85 54 20 00 04 EC FE 6F 03 FF FF 2014/12/08 13:22:18 MAJOR 160018 BIOS TFTP or HTTP/HTTPS flash failed 02 0A A6 85 54 20 00 04 EC FE 6F 03 FF FF 2014/12/08 10:52:58 INFO 160014 Online firmware flash: iRMC S4 reboot EEPROM 2 Version 7.65 02 0A 83 85 54 20 00 04 EC FE 6F A1 87 41 2014/12/08 10:52:54 INFO 160016 Firmware change detected Version 7.65 02 06 83 85 54 20 00 04 2B 00 6F 01 07 41 2014/12/10 12:09:42 INFO 2300E4 2014/12/10 10:48:34 INFO 2300B1 2014/12/10 08:59:07 INFO 2300E4 2014/12/10 08:53:51 INFO 2300B1 2014/12/08 18:15:24 INFO 2300E4 2014/12/08 15:41:28 INFO 2300B2 2014/12/08 15:40:39 INFO 2300B1 2014/12/08 14:33:44 INFO 2300B8 2014/12/08 13:33:34 INFO 01002B 2014/12/08 13:32:59 INFO 01002B 1 1 0 0 FTS RAID Ctrl SAS 6G 1GB (D3116C) (0) Fujitsu Technology Solutions RAID Ctrl SAS 6G 1GB (D3116C) 0000000045118882 0x5003005701AB2E40 8 SAS600 23.9.0-0033 1024 16 true true 32 0 0 Idle Make Data Consistent Enabled 300 Automatic 255 No 168 0 20 Disabled 30 30 30 30 4 6 2 Enabled None Disabled Normal Initialization Enabled Enabled Enabled Enabled Disabled Enabled Enabled 30 Disabled Enabled OK 005B 11E4 1000 1734 PCIe 64 256 false true Port 0 - 3 1 FTS COR SAS20BP_12_25HD 0700 FTS COR Unknown (1) OK 0x500605B0000272BD 0 7 1 FTS COR SAS20BP_12_25HD (1:1) SES FTS COR SAS20BP_12_25HD x36-254.7.0.0 0700 OK 0 TOSHIBA PX02SMF020 (1:0) TOSHIBA PX02SMF020 SAS 5203 9440A01OTB9A 0x50000395CC88808A 1 9 0 1 190782 190240 Available Idle false 0 0 0 SSD Active 34 Port 4 - 7 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/irmc/fixtures/irmc_report_ok.xml0000664000175000017500000013570000000000000027112 0ustar00zuulzuul00000000000000 true 2014/12/15 18:46:20 14 FUJITSU iRMC38058D iRMC S4 7.65F SDR: 3.71 ID 0356 RX300S8 10.124.196.159 fe80::921b:eff:fe38:58d 4 important error(s) in system event log (SEL)! 1 important warning(s) in system event log SEL 2 important warning(s) in internal event log IEL V4.6.5.4 R1.14.0 for D2939-B1x CPU1 Intel Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz 2600 1 8 16 8000 512 2048 20480 CPU2 Intel Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz 2600 1 8 16 8000 512 2048 20480 8192 0 0 0 0 0 0 0 0 0 0 0 0 1 true 8192 DDR3 1600 9128 9128 Micron Technology 2014,37 18KSF1G72PZ-1G6E2 12869 730413837 RDIMM DDR3_SDRAM 1Gx4/16x11x3 1600 1.35V/1.5V 5;6;7;8;9;10;11; 72 1 0 0 0 0 0 0 0 0 0 0 0 0 1 5820 5820 5700 1 5820 6000 5820 1 5820 5820 5700 1 5700 5700 5580 1 6000 6000 5820 1 3600 17920 17920 1 3680 17920 17920 6 28 37 42 6 28 75 80 6 33 75 80 6 37 82 86 6 37 82 86 0 0 0 0 6 29 78 82 0 0 0 6 28 57 61 6 28 57 61 6 53 102 107 6 52 102 107 0 6 69 110 115 1 76 1 80 1 3.15 3.00 2.01 3.50 1 11.88 12.00 11.28 12.96 1 5.10 5.00 4.63 5.42 1 3.30 3.30 3.02 3.57 1 1.78 1.80 1.67 1.93 1 1.48 1.50 1.39 1.61 1 0.98 1.00 0.93 1.08 1 12.16 12.00 11.31 12.90 1 4.98 5.00 4.63 5.42 1 3.35 3.30 3.02 3.57 1 1.47 1.50 1.42 1.58 1 1.09 1.10 1.02 1.18 1 0.99 1.00 0.93 1.07 1 0.98 1.00 0.93 1.07 01 00 51 01 3B 20 00 01 37 00 3B 54 01 01 85 32 85 32 1B 1B 00 01 00 00 19 00 00 00 00 E0 00 00 00 00 FF 00 00 A8 94 00 04 18 07 07 00 00 00 C7 41 6D 62 69 65 6E 74 00 00 00 00 00 00 00 00 00 20 0 0 1 55 0 Ambient 1 Temperature 1 0 degree C unspecified 168 42 4 1 148 37 24 6 02 00 51 01 3B 20 00 02 07 00 3B 54 01 01 80 02 80 32 18 18 00 01 00 00 01 00 00 00 00 00 00 00 00 00 FF 00 00 50 4B 00 00 00 01 01 00 00 00 CD 53 79 73 74 65 6D 62 6F 61 72 64 20 31 00 00 00 20 0 0 2 7 0 Systemboard 1 1 Temperature 1 0 degree C unspecified 80 80 75 75 03 00 51 01 3B 20 00 03 07 00 3B 54 01 01 80 02 80 32 18 18 00 01 00 00 01 00 00 00 00 00 00 00 00 00 FF 00 00 50 4B 00 00 00 01 01 00 00 00 CD 53 79 73 74 65 6D 62 6F 61 72 64 20 32 00 00 00 20 0 0 3 7 0 Systemboard 2 1 Temperature 1 0 degree C unspecified 80 80 75 75 04 00 51 01 3B 20 00 04 03 00 3B 54 01 01 80 02 80 32 18 18 00 01 00 00 01 00 00 00 00 00 00 00 00 00 FF 00 00 56 52 00 01 06 01 00 00 00 00 C4 43 50 55 31 00 00 00 00 00 00 00 00 00 00 00 00 20 0 0 4 3 0 CPU1 1 Temperature 1 0 degree C unspecified 86 86 82 82 05 00 51 01 3B 20 00 05 03 01 3B 54 01 01 80 02 80 32 18 18 00 01 00 00 01 00 00 00 00 00 00 00 00 00 FF 00 00 56 52 00 01 06 01 00 00 00 00 C4 43 50 55 32 00 00 00 00 00 00 00 00 00 00 00 00 20 0 0 5 3 1 CPU2 1 Temperature 1 0 degree C unspecified 86 86 82 82 06 00 51 01 3B 20 00 06 20 00 3B 54 01 01 80 02 80 32 18 18 00 01 00 00 01 00 00 00 00 00 00 00 00 00 FF 00 00 52 4E 00 01 06 01 01 00 00 81 C5 4D 45 4D 20 41 00 00 00 00 00 00 00 00 00 00 00 20 0 0 6 32 0 MEM A 1 Temperature 1 0 degree C unspecified 82 82 78 78 07 00 51 01 3B 20 00 07 20 01 3B 54 01 01 80 02 80 32 18 18 00 01 00 00 01 00 00 00 00 00 00 00 00 00 FF 00 00 52 4E 00 01 06 01 01 00 00 81 C5 4D 45 4D 20 42 00 00 00 00 00 00 00 00 00 00 00 20 0 0 7 32 1 MEM B 1 Temperature 1 0 degree C unspecified 82 82 78 78 08 00 51 01 3B 20 00 08 20 02 3B 54 01 01 80 02 80 32 18 18 00 01 00 00 01 00 00 00 00 00 00 00 00 00 FF 00 00 52 4E 00 01 06 01 01 00 00 81 C5 4D 45 4D 20 43 00 00 00 00 00 00 00 00 00 00 00 20 0 0 8 32 2 MEM C 1 Temperature 1 0 degree C unspecified 82 82 78 78 09 00 51 01 3B 20 00 09 20 03 3B 54 01 01 80 02 80 32 18 18 00 01 00 00 01 00 00 00 00 00 00 00 00 00 FF 00 00 52 4E 00 01 06 01 01 00 00 81 C5 4D 45 4D 20 44 00 00 00 00 00 00 00 00 00 00 00 20 0 0 9 32 3 MEM D 1 Temperature 1 0 degree C unspecified 82 82 78 78 0A 00 51 01 3B 20 00 0A 20 04 3B 54 01 01 80 02 80 32 18 18 00 01 00 00 01 00 00 00 00 00 00 00 00 00 FF 00 00 52 4E 00 01 06 01 01 00 00 81 C5 4D 45 4D 20 45 00 00 00 00 00 00 00 00 00 00 00 20 0 0 10 32 4 MEM E 1 Temperature 1 0 degree C unspecified 82 82 78 78 1 1000 11E4 005B 1734 Mass storage controller RAID controller 7 1 10DF E208 E200 10DF Serial bus controller Fibre Channel 1 1 10DF E208 E200 10DF Serial bus controller Fibre Channel 1 1 8086 00A2 1521 8086 Network controller Ethernet controller 5 1 8086 00A2 1521 8086 Network controller Ethernet controller 5 1 8086 001A 1528 8086 Network controller Ethernet controller 6 1 8086 001A 1528 8086 Network controller Ethernet controller 6 2014/12/10 10:13:40 INFO 160011 BIOS change detected 02 D4 1C 88 54 01 00 04 2B 00 6F C1 09 00 2014/12/10 10:11:18 INFO 420020 Management Engine: Direct Flash update requested by the BIOS 02 46 1C 88 54 2C 00 04 DC 17 75 A0 06 00 2014/12/10 10:03:11 INFO 160014 Online firmware flash: iRMC S4 reboot EEPROM 1 Version 7.65 02 5F 1A 88 54 20 00 04 EC FE 6F A1 07 41 2014/12/10 09:57:50 INFO 160013 Online firmware flash EEPROM 1 Version 7.65 02 1E 19 88 54 20 00 04 EC FE 6F A0 07 41 2014/12/10 09:30:31 MAJOR 160018 BIOS TFTP or HTTP/HTTPS flash failed 02 B7 12 88 54 20 00 04 EC FE 6F 03 FF FF 2014/12/08 13:33:15 MAJOR 160018 BIOS TFTP or HTTP/HTTPS flash failed 02 9B A8 85 54 20 00 04 EC FE 6F 03 FF FF 2014/12/08 13:30:09 MAJOR 160018 BIOS TFTP or HTTP/HTTPS flash failed 02 E1 A7 85 54 20 00 04 EC FE 6F 03 FF FF 2014/12/08 13:22:18 MAJOR 160018 BIOS TFTP or HTTP/HTTPS flash failed 02 0A A6 85 54 20 00 04 EC FE 6F 03 FF FF 2014/12/08 10:52:58 INFO 160014 Online firmware flash: iRMC S4 reboot EEPROM 2 Version 7.65 02 0A 83 85 54 20 00 04 EC FE 6F A1 87 41 2014/12/08 10:52:54 INFO 160016 Firmware change detected Version 7.65 02 06 83 85 54 20 00 04 2B 00 6F 01 07 41 2014/12/10 12:09:42 INFO 2300E4 2014/12/10 10:48:34 INFO 2300B1 2014/12/10 08:59:07 INFO 2300E4 2014/12/10 08:53:51 INFO 2300B1 2014/12/08 18:15:24 INFO 2300E4 2014/12/08 15:41:28 INFO 2300B2 2014/12/08 15:40:39 INFO 2300B1 2014/12/08 14:33:44 INFO 2300B8 2014/12/08 13:33:34 INFO 01002B 2014/12/08 13:32:59 INFO 01002B 1 1 0 7.65F 10.124.196.159 255.255.255.0 10.124.196.1 90-1B-0E-38-05-8D 0 0 0 FTS RAID Ctrl SAS 6G 1GB (D3116C) (0) Fujitsu Technology Solutions RAID Ctrl SAS 6G 1GB (D3116C) 0000000045118882 0x5003005701AB2E40 8 SAS600 23.9.0-0033 1024 16 true true 32 0 0 Idle Make Data Consistent Enabled 300 Automatic 255 No 168 0 20 Disabled 30 30 30 30 4 6 2 Enabled None Disabled Normal Initialization Enabled Enabled Enabled Enabled Disabled Enabled Enabled 30 Disabled Enabled OK 005B 11E4 1000 1734 PCIe 64 256 false true Port 0 - 3 1 FTS COR SAS20BP_12_25HD 0700 FTS COR Unknown (1) OK 0x500605B0000272BD 0 7 1 FTS COR SAS20BP_12_25HD (1:1) SES FTS COR SAS20BP_12_25HD x36-254.7.0.0 0700 OK 0 TOSHIBA PX02SMF020 (1:0) TOSHIBA PX02SMF020 SAS 5203 9440A01OTB9A 0x50000395CC88808A 1 9 0 1 190782 190240 Available Idle false 0 0 0 SSD Active 34 Port 4 - 7 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/irmc/test_elcm.py0000664000175000017500000030511500000000000024031 0ustar00zuulzuul00000000000000# Copyright 2016 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Test class for iRMC eLCM functionality. """ from unittest import mock from oslo_utils import encodeutils import requests from requests_mock.contrib import fixture as rm_fixture import testtools from scciclient.irmc import elcm from scciclient.irmc import scci class ELCMTestCase(testtools.TestCase): """Tests for eLCM""" RESPONSE_TEMPLATE = ('Date: Mon, 07 Dec 2015 17:10:55 GMT\n' 'Server: iRMC S4 Webserver\n' 'Content-Length: 123\n' 'Content-Type: application/json; charset=UTF-8\n' '\r\n' '{\n' '%(json_text)s\n' '}') def setUp(self): super(ELCMTestCase, self).setUp() self.requests_mock = self.useFixture(rm_fixture.Fixture()) self.irmc_info = { 'irmc_address': '10.124.196.159', 'irmc_username': 'admin', 'irmc_password': 'admin0', 'irmc_port': 80, 'irmc_auth_method': 'basic', 'irmc_client_timeout': 60, } self.raid_info = { 'Server': { 'HWConfigurationIrmc': { 'Adapters': { 'RAIDAdapter': [ { 'Arrays': None, 'LogicalDrives': None } ] }, '@Version': '1.00' }, '@Version': '1.01' } } def _create_server_url(self, path, port=None): scheme = 'unknown' if port is None: port = self.irmc_info['irmc_port'] if port == 80: scheme = 'http' elif port == 443: scheme = 'https' return ('%(scheme)s://%(addr)s%(path)s' % {'scheme': scheme, 'addr': self.irmc_info['irmc_address'], 'path': path}) def _create_server_response(self, content): response = requests.Response() response._content = encodeutils.safe_encode(content) response.encoding = 'utf-8' return response def test__parse_elcm_response_body_as_json_empty(self): response = self._create_server_response('') self.assertRaises(elcm.ELCMInvalidResponse, elcm._parse_elcm_response_body_as_json, response=response) def test__parse_elcm_response_body_as_json_invalid(self): content = 'abc123' response = self._create_server_response(content) self.assertRaises(elcm.ELCMInvalidResponse, elcm._parse_elcm_response_body_as_json, response=response) def test__parse_elcm_response_body_as_json_missing_empty_line(self): content = ('key1:val1\nkey2:val2\n' '{"1":1,"2":[123, "abc"],"3":3}') response = self._create_server_response(content) self.assertRaises(elcm.ELCMInvalidResponse, elcm._parse_elcm_response_body_as_json, response=response) def test__parse_elcm_response_body_as_json_ok(self): content = ('key1:val1\nkey2:val2\n' '\r\n' '{"1":1,"2":[123, "abc"],"3":3}') response = self._create_server_response(content) result = elcm._parse_elcm_response_body_as_json(response) expected = { "1": 1, "2": [123, "abc"], "3": 3 } self.assertEqual(expected, result) def test_elcm_request_protocol_http_ok(self): irmc_info = dict(self.irmc_info) irmc_info['irmc_port'] = 80 self.requests_mock.register_uri( 'GET', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT, port=80), text=self.RESPONSE_TEMPLATE % {'json_text': 'abc123'}) response = elcm.elcm_request( irmc_info, method='GET', path=elcm.URL_PATH_PROFILE_MGMT) self.assertEqual(200, response.status_code) expected = self.RESPONSE_TEMPLATE % {'json_text': 'abc123'} self.assertEqual(expected, response.text) def test_elcm_request_protocol_https_ok(self): irmc_info = dict(self.irmc_info) irmc_info['irmc_port'] = 443 self.requests_mock.register_uri( 'GET', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT, port=443), text=self.RESPONSE_TEMPLATE % {'json_text': 'abc123'}) response = elcm.elcm_request( irmc_info, method='GET', path=elcm.URL_PATH_PROFILE_MGMT) self.assertEqual(200, response.status_code) expected = self.RESPONSE_TEMPLATE % {'json_text': 'abc123'} self.assertEqual(expected, response.text) def test_elcm_request_unsupported_port(self): irmc_info = dict(self.irmc_info) irmc_info['irmc_port'] = 22 e = self.assertRaises(scci.SCCIInvalidInputError, elcm.elcm_request, irmc_info, method='GET', path=elcm.URL_PATH_PROFILE_MGMT) auth_method = self.irmc_info['irmc_auth_method'] self.assertEqual((("Invalid port %(port)d or " "auth_method for method %(auth_method)s") % {'port': 22, 'auth_method': auth_method}), str(e)) def test_elcm_request_auth_method_basic(self): irmc_info = dict(self.irmc_info) irmc_info['irmc_auth_method'] = 'basic' self.requests_mock.register_uri( 'GET', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT), status_code=200, text='ok') response = elcm.elcm_request( irmc_info, method='GET', path=elcm.URL_PATH_PROFILE_MGMT) self.assertEqual(200, response.status_code) self.assertEqual('ok', response.text) def test_elcm_request_auth_method_digest(self): irmc_info = dict(self.irmc_info) irmc_info['irmc_auth_method'] = 'digest' self.requests_mock.register_uri( 'GET', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT), status_code=200, text='ok') response = elcm.elcm_request( irmc_info, method='GET', path=elcm.URL_PATH_PROFILE_MGMT) self.assertEqual(200, response.status_code) self.assertEqual('ok', response.text) def test_elcm_request_unsupported_auth_method(self): irmc_info = dict(self.irmc_info) irmc_info['irmc_auth_method'] = 'unknown' e = self.assertRaises(scci.SCCIInvalidInputError, elcm.elcm_request, irmc_info, method='GET', path=elcm.URL_PATH_PROFILE_MGMT) port = self.irmc_info['irmc_port'] self.assertEqual((("Invalid port %(port)d or " "auth_method for method %(auth_method)s") % {'port': port, 'auth_method': 'unknown'}), str(e)) def test_elcm_request_auth_failed(self): self.requests_mock.register_uri( 'GET', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT), status_code=401, text='401 Unauthorized') e = self.assertRaises(scci.SCCIClientError, elcm.elcm_request, self.irmc_info, method='GET', path=elcm.URL_PATH_PROFILE_MGMT) self.assertEqual('UNAUTHORIZED', str(e)) def test_elcm_profile_get_versions_failed(self): self.requests_mock.register_uri( 'GET', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT) + 'version', status_code=503) self.assertRaises(scci.SCCIClientError, elcm.elcm_profile_get_versions, self.irmc_info) def test_elcm_profile_get_versions_ok(self): self.requests_mock.register_uri( 'GET', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT) + 'version', text=(self.RESPONSE_TEMPLATE % { 'json_text': '"Server":{' ' "@Version": "1.01",' ' "AdapterConfigIrmc": {' ' "@Version": "1.00"' ' },' ' "SystemConfig": {' ' "BiosConfig": {' ' "@Version": "1.02"' ' }' ' }' '}'})) result = elcm.elcm_profile_get_versions(self.irmc_info) expected = { "Server": { "@Version": "1.01", "AdapterConfigIrmc": { "@Version": "1.00" }, "SystemConfig": { "BiosConfig": { "@Version": "1.02" } } } } self.assertEqual(expected, result) def test_elcm_profile_get_not_found(self): profile_name = elcm.PROFILE_BIOS_CONFIG self.requests_mock.register_uri( 'GET', self._create_server_url((elcm.URL_PATH_PROFILE_MGMT + profile_name)), status_code=404) self.assertRaises(elcm.ELCMProfileNotFound, elcm.elcm_profile_get, self.irmc_info, profile_name=profile_name) def test_elcm_profile_list_failed(self): self.requests_mock.register_uri( 'GET', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT), status_code=503) self.assertRaises(scci.SCCIClientError, elcm.elcm_profile_list, self.irmc_info) def test_elcm_profile_list_ok(self): self.requests_mock.register_uri( 'GET', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT), text=(self.RESPONSE_TEMPLATE % { 'json_text': '"Links":{' ' "profileStore":[' ' {"@odata.id": "id1"},' ' {"@odata.id": "id2"}' ' ]' '}'})) result = elcm.elcm_profile_list(self.irmc_info) expected = { "Links": { "profileStore": [ {"@odata.id": "id1"}, {"@odata.id": "id2"} ] } } self.assertEqual(expected, result) def test_elcm_profile_get_failed(self): profile_name = elcm.PROFILE_BIOS_CONFIG self.requests_mock.register_uri( 'GET', self._create_server_url((elcm.URL_PATH_PROFILE_MGMT + profile_name)), status_code=500) self.assertRaises(scci.SCCIClientError, elcm.elcm_profile_get, self.irmc_info, profile_name=profile_name) def test_elcm_profile_get_ok(self): profile_name = elcm.PROFILE_BIOS_CONFIG self.requests_mock.register_uri( 'GET', self._create_server_url((elcm.URL_PATH_PROFILE_MGMT + profile_name)), text=(self.RESPONSE_TEMPLATE % { 'json_text': '"Server":{' ' "SystemConfig":{' ' "BiosConfig":{' ' "key":"val"' ' }' ' }' '}'})) result = elcm.elcm_profile_get( self.irmc_info, profile_name=profile_name) expected = { "Server": { "SystemConfig": { "BiosConfig": { "key": "val" } } } } self.assertEqual(expected, result) def test_elcm_profile_create_failed(self): param_path = elcm.PARAM_PATH_BIOS_CONFIG self.requests_mock.register_uri( 'POST', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT + 'get'), status_code=200) # Success code is 202 self.assertRaises(scci.SCCIClientError, elcm.elcm_profile_create, self.irmc_info, param_path=param_path) def test_elcm_profile_create_ok(self): param_path = elcm.PARAM_PATH_BIOS_CONFIG self.requests_mock.register_uri( 'POST', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT + 'get'), status_code=202, # Success code is 202 text=(self.RESPONSE_TEMPLATE % { 'json_text': '"Session":{' ' "Id": 123,' ' "Status": "activated"' '}'})) result = elcm.elcm_profile_create(self.irmc_info, param_path=param_path) expected = { "Session": { "Id": 123, "Status": "activated", } } self.assertEqual(expected, result) def test_elcm_profile_set_failed(self): input_data = { "Server": { "SystemConfig": { "BiosConfig": { "key": "val" } } } } self.requests_mock.register_uri( 'POST', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT + 'set'), status_code=200) # Success code is 202 self.assertRaises(scci.SCCIClientError, elcm.elcm_profile_set, self.irmc_info, input_data=input_data) def test_elcm_profile_set_ok(self): input_data = { "Server": { "SystemConfig": { "BiosConfig": { "key": "val" } } } } self.requests_mock.register_uri( 'POST', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT + 'set'), status_code=202, # Success code is 202 text=(self.RESPONSE_TEMPLATE % { 'json_text': '"Session":{' ' "Id": 123,' ' "Status": "activated"' '}'})) result = elcm.elcm_profile_set(self.irmc_info, input_data=input_data) expected = { "Session": { "Id": 123, "Status": "activated", } } self.assertEqual(expected, result) def test_elcm_profile_set_with_raid_config_failed(self): input_data = { "Server": { "HWConfigurationIrmc": { "Adapters": { "RAIDAdapter": [ { "key": "val" } ] } } } } self.requests_mock.register_uri( 'POST', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT + 'set'), status_code=400) # Success code is 202 self.assertRaises(scci.SCCIClientError, elcm.elcm_profile_set, self.irmc_info, input_data=input_data) def test_elcm_profile_set_with_raid_config_ok(self): input_data = { "Server": { "HWConfigurationIrmc": { "Adapters": { "RAIDAdapter": [ { "key": "val" } ] } } } } self.requests_mock.register_uri( 'POST', self._create_server_url(elcm.URL_PATH_PROFILE_MGMT + 'set'), status_code=202, # Success code is 202 text=(self.RESPONSE_TEMPLATE % { 'json_text': '"Session":{' ' "Id": 123,' ' "Status": "activated"' '}'})) result = elcm.elcm_profile_set(self.irmc_info, input_data=input_data) expected = { "Session": { "Id": 123, "Status": "activated", } } self.assertEqual(expected, result) def test_elcm_profile_delete_not_found(self): profile_name = elcm.PROFILE_BIOS_CONFIG self.requests_mock.register_uri( 'DELETE', self._create_server_url((elcm.URL_PATH_PROFILE_MGMT + profile_name)), status_code=404) self.assertRaises(elcm.ELCMProfileNotFound, elcm.elcm_profile_delete, self.irmc_info, profile_name=profile_name) def test_elcm_profile_delete_failed(self): profile_name = elcm.PROFILE_BIOS_CONFIG self.requests_mock.register_uri( 'DELETE', self._create_server_url((elcm.URL_PATH_PROFILE_MGMT + profile_name)), status_code=500) self.assertRaises(scci.SCCIClientError, elcm.elcm_profile_delete, self.irmc_info, profile_name=profile_name) def test_elcm_profile_delete_ok(self): profile_name = elcm.PROFILE_BIOS_CONFIG self.requests_mock.register_uri( 'DELETE', self._create_server_url((elcm.URL_PATH_PROFILE_MGMT + profile_name)), text='ok') result = elcm.elcm_profile_delete(self.irmc_info, profile_name=profile_name) self.assertIsNone(result) def test_elcm_session_list_failed(self): self.requests_mock.register_uri( 'GET', self._create_server_url('/sessionInformation/'), status_code=500) self.assertRaises(scci.SCCIClientError, elcm.elcm_session_list, self.irmc_info) def test_elcm_session_list_empty(self): self.requests_mock.register_uri( 'GET', self._create_server_url('/sessionInformation/'), text=(self.RESPONSE_TEMPLATE % { 'json_text': '"SessionList":{' ' "Contains":[' ' ]' '}'})) result = elcm.elcm_session_list(self.irmc_info) expected = { "SessionList": { "Contains": [ ] } } self.assertEqual(expected, result) def test_elcm_session_list_ok(self): self.requests_mock.register_uri( 'GET', self._create_server_url('/sessionInformation/'), text=(self.RESPONSE_TEMPLATE % { 'json_text': '"SessionList":{' ' "Contains":[' ' { "Id": 1, "Name": "name1" },' ' { "Id": 2, "Name": "name2" },' ' { "Id": 3, "Name": "name3" }' ' ]' '}'})) result = elcm.elcm_session_list(self.irmc_info) expected = { "SessionList": { "Contains": [ {"Id": 1, "Name": "name1"}, {"Id": 2, "Name": "name2"}, {"Id": 3, "Name": "name3"} ] } } self.assertEqual(expected, result) def test_elcm_session_get_status_not_found(self): session_id = 123 self.requests_mock.register_uri( 'GET', self._create_server_url(('/sessionInformation/%s/status' % session_id)), status_code=404) self.assertRaises(elcm.ELCMSessionNotFound, elcm.elcm_session_get_status, self.irmc_info, session_id=session_id) def test_elcm_session_get_status_failed(self): session_id = 123 self.requests_mock.register_uri( 'GET', self._create_server_url(('/sessionInformation/%s/status' % session_id)), status_code=500) self.assertRaises(scci.SCCIClientError, elcm.elcm_session_get_status, self.irmc_info, session_id=session_id) def test_elcm_session_get_status_ok(self): session_id = 123 self.requests_mock.register_uri( 'GET', self._create_server_url(('/sessionInformation/%s/status' % session_id)), text=(self.RESPONSE_TEMPLATE % { 'json_text': '"Session":{' ' "Id": 123,' ' "Status": "abc123"' '}'})) result = elcm.elcm_session_get_status(self.irmc_info, session_id=session_id) expected = { "Session": { "Id": 123, "Status": "abc123", } } self.assertEqual(expected, result) def test_elcm_session_get_log_not_found(self): session_id = 123 self.requests_mock.register_uri( 'GET', self._create_server_url(('/sessionInformation/%s/log' % session_id)), status_code=404) self.assertRaises(elcm.ELCMSessionNotFound, elcm.elcm_session_get_log, self.irmc_info, session_id=session_id) def test_elcm_session_get_log_failed(self): session_id = 123 self.requests_mock.register_uri( 'GET', self._create_server_url(('/sessionInformation/%s/log' % session_id)), status_code=500) self.assertRaises(scci.SCCIClientError, elcm.elcm_session_get_log, self.irmc_info, session_id=session_id) def test_elcm_session_get_log_ok(self): session_id = 123 self.requests_mock.register_uri( 'GET', self._create_server_url(('/sessionInformation/%s/log' % session_id)), text=(self.RESPONSE_TEMPLATE % { 'json_text': '"Session":{' ' "Id": 123,' ' "A_Param": "abc123"' '}'})) result = elcm.elcm_session_get_log(self.irmc_info, session_id=session_id) expected = { "Session": { "Id": 123, "A_Param": "abc123", } } self.assertEqual(expected, result) def test_elcm_session_terminate_not_found(self): session_id = 123 self.requests_mock.register_uri( 'DELETE', self._create_server_url(('/sessionInformation/%s/terminate' % session_id)), status_code=404) self.assertRaises(elcm.ELCMSessionNotFound, elcm.elcm_session_terminate, self.irmc_info, session_id=session_id) def test_elcm_session_terminate_failed(self): session_id = 123 self.requests_mock.register_uri( 'DELETE', self._create_server_url(('/sessionInformation/%s/terminate' % session_id)), status_code=500) self.assertRaises(scci.SCCIClientError, elcm.elcm_session_terminate, self.irmc_info, session_id=session_id) def test_elcm_session_terminate_ok(self): session_id = 123 self.requests_mock.register_uri( 'DELETE', self._create_server_url(('/sessionInformation/%s/terminate' % session_id)), text='ok') result = elcm.elcm_session_terminate(self.irmc_info, session_id=session_id) self.assertIsNone(result) def test_elcm_session_delete_not_found(self): session_id = 123 self.requests_mock.register_uri( 'DELETE', self._create_server_url(('/sessionInformation/%s/remove' % session_id)), status_code=404) self.assertRaises(elcm.ELCMSessionNotFound, elcm.elcm_session_delete, self.irmc_info, session_id=session_id) def test_elcm_session_delete_failed(self): session_id = 123 self.requests_mock.register_uri( 'DELETE', self._create_server_url(('/sessionInformation/%s/remove' % session_id)), status_code=500) self.assertRaises(scci.SCCIClientError, elcm.elcm_session_delete, self.irmc_info, session_id=session_id) def test_elcm_session_delete_ok(self): session_id = 123 self.requests_mock.register_uri( 'DELETE', self._create_server_url(('/sessionInformation/%s/remove' % session_id)), text='ok') result = elcm.elcm_session_delete(self.irmc_info, session_id=session_id) self.assertIsNone(result) @mock.patch.object(elcm, 'elcm_profile_delete') @mock.patch.object(elcm, 'elcm_profile_get') @mock.patch.object(elcm, 'elcm_session_delete') @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm.time, 'sleep') def test__process_session_data_get_ok(self, mock_sleep, mock_session_get, mock_session_delete, mock_profile_get, mock_profile_delete): session_id = 123 expected_bios_cfg = { 'Server': { 'SystemConfig': { 'BiosConfig': { 'key1': 'val1' } } } } mock_session_get.side_effect = [ {'Session': {'Id': session_id, 'Status': 'activated'}}, {'Session': {'Id': session_id, 'Status': 'running'}}, {'Session': {'Id': session_id, 'Status': 'terminated regularly'}}] mock_profile_get.return_value = expected_bios_cfg result = elcm._process_session_data(irmc_info=self.irmc_info, operation='BACKUP_BIOS', session_id=session_id) self.assertEqual(expected_bios_cfg, result['bios_config']) mock_session_get.assert_has_calls([ mock.call(irmc_info=self.irmc_info, session_id=session_id), mock.call(irmc_info=self.irmc_info, session_id=session_id), mock.call(irmc_info=self.irmc_info, session_id=session_id)]) mock_profile_get.assert_called_once_with( irmc_info=self.irmc_info, profile_name=elcm.PROFILE_BIOS_CONFIG) self.assertEqual(2, mock_sleep.call_count) self.assertEqual(1, mock_session_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') @mock.patch.object(elcm, 'elcm_session_delete') @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm.time, 'sleep') def test__process_session_data_set_ok(self, mock_sleep, mock_session_get, mock_session_delete, mock_profile_get, mock_profile_delete): session_id = 123 mock_session_get.side_effect = [ {'Session': {'Id': session_id, 'Status': 'activated'}}, {'Session': {'Id': session_id, 'Status': 'running'}}, {'Session': {'Id': session_id, 'Status': 'terminated regularly'}}] elcm._process_session_data(irmc_info=self.irmc_info, operation='RESTORE_BIOS', session_id=session_id) mock_session_get.assert_has_calls([ mock.call(irmc_info=self.irmc_info, session_id=session_id), mock.call(irmc_info=self.irmc_info, session_id=session_id), mock.call(irmc_info=self.irmc_info, session_id=session_id)]) mock_profile_get.assert_not_called() self.assertEqual(2, mock_sleep.call_count) self.assertEqual(1, mock_session_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') @mock.patch.object(elcm, 'elcm_session_delete') @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm.time, 'sleep') def test__process_session_data_timeout(self, mock_sleep, mock_session_get, mock_session_delete, mock_profile_get, mock_profile_delete): session_id = 123 mock_session_get.return_value = {'Session': {'Id': session_id, 'Status': 'running'}} self.assertRaises(elcm.ELCMSessionTimeout, elcm._process_session_data, irmc_info=self.irmc_info, operation='BACKUP_BIOS', session_id=session_id, session_timeout=0.5) self.assertEqual(True, mock_sleep.called) self.assertEqual(True, mock_session_get.called) mock_profile_get.assert_not_called() mock_session_delete.assert_not_called() mock_profile_delete.assert_not_called() @mock.patch.object(elcm, 'elcm_profile_delete') @mock.patch.object(elcm, 'elcm_session_delete') @mock.patch.object(elcm, 'elcm_session_get_log') @mock.patch.object(elcm, 'elcm_session_get_status') def test__process_session_data_error(self, mock_session_get, mock_session_get_log, mock_session_delete, mock_profile_delete): session_id = 123 mock_session_get.return_value = {'Session': {'Id': session_id, 'Status': 'error'}} self.assertRaises(scci.SCCIClientError, elcm._process_session_data, irmc_info=self.irmc_info, operation='RESTORE_BIOS', session_id=session_id, session_timeout=0.5) self.assertEqual(True, mock_session_get.called) self.assertEqual(True, mock_session_get_log.called) mock_session_delete.assert_not_called() mock_profile_delete.assert_not_called() @mock.patch.object(elcm, 'elcm_profile_delete') @mock.patch.object(elcm, 'elcm_profile_create') @mock.patch.object(elcm, 'elcm_profile_get') @mock.patch.object(elcm, 'elcm_session_delete') @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm.time, 'sleep') def test_backup_bios_config_ok(self, mock_sleep, mock_session_get, mock_session_delete, mock_profile_get, mock_profile_create, mock_profile_delete): session_id = 123 expected_bios_cfg = { 'Server': { 'SystemConfig': { 'BiosConfig': { 'key1': 'val1' } } } } mock_session_get.side_effect = [ {'Session': {'Id': session_id, 'Status': 'activated'}}, {'Session': {'Id': session_id, 'Status': 'running'}}, {'Session': {'Id': session_id, 'Status': 'terminated regularly'}}] mock_profile_get.return_value = expected_bios_cfg mock_profile_create.return_value = {'Session': {'Id': session_id, 'Status': 'activated'}} result = elcm.backup_bios_config(irmc_info=self.irmc_info) self.assertEqual(expected_bios_cfg, result['bios_config']) 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') @mock.patch.object(elcm, 'elcm_profile_set') @mock.patch.object(elcm, 'elcm_session_delete') @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm.time, 'sleep') def _test_restore_bios_config_ok(self, mock_sleep, mock_session_get, mock_session_delete, mock_profile_set, mock_profile_get, mock_profile_delete, bios_cfg): session_id = 123 mock_session_get.side_effect = [ {'Session': {'Id': session_id, 'Status': 'activated'}}, {'Session': {'Id': session_id, 'Status': 'running'}}, {'Session': {'Id': session_id, 'Status': 'terminated regularly'}}] mock_profile_set.return_value = {'Session': {'Id': session_id, 'Status': 'activated'}} elcm.restore_bios_config(irmc_info=self.irmc_info, bios_config=bios_cfg) self.assertEqual(2, mock_sleep.call_count) self.assertEqual(True, mock_session_get.called) self.assertEqual(1, mock_session_delete.call_count) self.assertEqual(0, mock_profile_get.call_count) self.assertEqual(1, mock_profile_set.call_count) self.assertEqual(0, mock_profile_delete.call_count) def test_restore_bios_config_ok_with_dict(self): bios_cfg = { 'Server': { 'SystemConfig': { 'BiosConfig': { 'key1': 'val1' } } } } self._test_restore_bios_config_ok(bios_cfg=bios_cfg) def test_restore_bios_config_ok_with_str(self): bios_cfg = ('{"Server":' ' {"SystemConfig":' ' {"BiosConfig":' ' {' ' "key1": "val1"' ' }' ' }' ' }' '}') self._test_restore_bios_config_ok(bios_cfg=bios_cfg) def _test_restore_bios_config_invalid_input(self, bios_cfg): self.assertRaises(scci.SCCIInvalidInputError, elcm.restore_bios_config, irmc_info=self.irmc_info, bios_config=bios_cfg) def test_restore_bios_config_invalid_input_dict(self): bios_cfg = { 'Server': { 'SystemConfig': { } } } self._test_restore_bios_config_invalid_input(bios_cfg=bios_cfg) def test_restore_bios_config_invalid_input_str(self): bios_cfg = '{"key": "val"}' self._test_restore_bios_config_invalid_input(bios_cfg=bios_cfg) @mock.patch.object(elcm, 'backup_bios_config') def test_get_secure_boot_mode_true(self, backup_bios_config_mock): backup_bios_config_mock.return_value = { 'bios_config': { 'Server': { 'SystemConfig': { 'BiosConfig': { 'SecurityConfig': { 'SecureBootControlEnabled': True } } } } } } result = elcm.get_secure_boot_mode(irmc_info=self.irmc_info) self.assertEqual(True, result) backup_bios_config_mock.assert_called_once_with( irmc_info=self.irmc_info) @mock.patch.object(elcm, 'backup_bios_config') def test_get_secure_boot_mode_false(self, backup_bios_config_mock): backup_bios_config_mock.return_value = { 'bios_config': { 'Server': { 'SystemConfig': { 'BiosConfig': { 'SecurityConfig': { 'SecureBootControlEnabled': False } } } } } } result = elcm.get_secure_boot_mode(irmc_info=self.irmc_info) self.assertEqual(False, result) backup_bios_config_mock.assert_called_once_with( irmc_info=self.irmc_info) @mock.patch.object(elcm, 'backup_bios_config') def test_get_secure_boot_mode_fail(self, backup_bios_config_mock): backup_bios_config_mock.return_value = { 'bios_config': { 'Server': { 'SystemConfig': { 'BiosConfig': { 'SecurityConfig': { 'FlashWriteEnabled': False } } } } } } self.assertRaises(elcm.SecureBootConfigNotFound, elcm.get_secure_boot_mode, irmc_info=self.irmc_info) backup_bios_config_mock.assert_called_once_with( irmc_info=self.irmc_info) @mock.patch.object(elcm, 'restore_bios_config') def test_set_secure_boot_mode_true(self, restore_bios_config_mock): elcm.set_secure_boot_mode(irmc_info=self.irmc_info, enable=True) bios_config_data = { 'Server': { '@Version': '1.01', 'SystemConfig': { 'BiosConfig': { '@Version': '1.01', 'SecurityConfig': { 'SecureBootControlEnabled': True } } } } } restore_bios_config_mock.assert_called_once_with( irmc_info=self.irmc_info, bios_config=bios_config_data) @mock.patch.object(elcm, 'restore_bios_config') def test_set_secure_boot_mode_false(self, restore_bios_config_mock): elcm.set_secure_boot_mode(irmc_info=self.irmc_info, enable=False) bios_config_data = { 'Server': { '@Version': '1.01', 'SystemConfig': { 'BiosConfig': { '@Version': '1.01', 'SecurityConfig': { 'SecureBootControlEnabled': False } } } } } restore_bios_config_mock.assert_called_once_with( irmc_info=self.irmc_info, bios_config=bios_config_data) @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): elcm_profile_set_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } session_id = 1 session_timeout = 1800 operation = 'CONFIG_RAID' raid_info_mock.return_value = self.raid_info 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' } } target_raid_config = { 'logical_disks': [ { 'size_gb': 100, 'raid_level': '1', } ] } 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_with_arrays_info_and_without_physical_disks( self, session_mock, elcm_profile_set_mock, raid_info_mock): raid_info_mock.return_value = self.raid_info expected_input = { 'Server': { 'HWConfigurationIrmc': { '@Processing': 'execute', 'Adapters': { 'RAIDAdapter': [ { 'Arrays': { 'Array': [] }, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': 'Create', 'RaidLevel': '0', 'InitMode': 'fast', 'Size': { '@Unit': 'GB', '#text': 100 }, }, { '@Number': 1, '@Action': 'Create', 'RaidLevel': '1', 'InitMode': 'fast', 'Size': { '@Unit': 'GB', '#text': 100 }, } ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } target_raid_config = { 'logical_disks': [ { 'size_gb': 100, 'raid_level': '0', }, { 'size_gb': 100, 'raid_level': '1', } ] } elcm_profile_set_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } session_id = 1 session_timeout = 1800 operation = 'CONFIG_RAID' 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 elcm_profile_set_mock.assert_called_once_with( self.irmc_info, expected_input) raid_info_mock.assert_called_once_with(self.irmc_info) @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_with_physical_disks_and_without_array_info( self, session_mock, elcm_profile_set_mock, raid_info_mock): raid_info_mock.return_value = self.raid_info expected_input = { 'Server': { 'HWConfigurationIrmc': { '@Processing': 'execute', 'Adapters': { 'RAIDAdapter': [ { 'Arrays': { 'Array': [ { '@Number': 0, '@ConfigurationType': 'Setting', 'PhysicalDiskRefs': { 'PhysicalDiskRef': [ { '@Number': '0' }, { '@Number': '1' } ] } } ] }, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': 'Create', 'RaidLevel': '1', 'InitMode': 'fast', 'Size': { '@Unit': 'GB', '#text': 100 }, 'ArrayRefs': { 'ArrayRef': [ { '@Number': 0 } ] } } ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } target_raid_config = { "logical_disks": [ { 'size_gb': 100, "raid_level": "1", "physical_disks": [ "0", "1" ], }, ] } elcm_profile_set_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } session_id = 1 session_timeout = 1800 operation = 'CONFIG_RAID' 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 elcm_profile_set_mock.assert_called_once_with( self.irmc_info, expected_input) raid_info_mock.assert_called_once_with(self.irmc_info) @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_along_with_physical_disks_and_array_info( self, session_mock, elcm_profile_set_mock, raid_info_mock): raid_info_mock.return_value = self.raid_info expected_input = { 'Server': { 'HWConfigurationIrmc': { '@Processing': 'execute', 'Adapters': { 'RAIDAdapter': [ { 'Arrays': { 'Array': [ { '@Number': 0, '@ConfigurationType': 'Setting', 'PhysicalDiskRefs': { 'PhysicalDiskRef': [ { '@Number': '0' }, { '@Number': '1' } ] } }, { '@Number': 1, '@ConfigurationType': 'Setting', 'PhysicalDiskRefs': { 'PhysicalDiskRef': [ { '@Number': '4' }, { '@Number': '5' } ] } }, ] }, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': 'Create', 'RaidLevel': '0', 'InitMode': 'fast', 'Size': { '@Unit': 'GB', '#text': 100 }, 'ArrayRefs': { 'ArrayRef': [ { '@Number': 0 } ] } }, { '@Number': 1, '@Action': 'Create', 'RaidLevel': '1', 'InitMode': 'fast', 'Size': { '@Unit': 'GB', '#text': 100 }, 'ArrayRefs': { 'ArrayRef': [ { '@Number': 1 } ] } } ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } target_raid_config = { 'logical_disks': [ { 'size_gb': 100, 'raid_level': '0', 'physical_disks': [ '0', '1' ] }, { 'size_gb': 100, 'raid_level': '1', 'physical_disks': [ '4', '5' ] }, ] } elcm_profile_set_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } session_id = 1 session_timeout = 1800 operation = 'CONFIG_RAID' 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 elcm_profile_set_mock.assert_called_once_with( self.irmc_info, expected_input) raid_info_mock.assert_called_once_with(self.irmc_info) @mock.patch.object(elcm, 'delete_raid_configuration') @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_with_exist_raid_config( self, session_mock, elcm_profile_set_mock, raid_info_mock, delete_raid_mock): raid_info_mock.return_value = { 'Server': { 'HWConfigurationIrmc': { 'Adapters': { 'RAIDAdapter': [ { 'Arrays': None, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': None, 'RaidLevel': '1' }, ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } elcm_profile_set_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } session_id = 1 session_timeout = 1800 operation = 'CONFIG_RAID' expected_raid_call = { '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' } } target_raid_config = { 'logical_disks': [ { 'size_gb': 100, 'raid_level': '1' }, ] } elcm.create_raid_configuration(self.irmc_info, target_raid_config) elcm_profile_set_mock.assert_called_once_with(self.irmc_info, expected_raid_call) delete_raid_mock.assert_called_once_with(self.irmc_info) session_mock.assert_has_calls([mock.call(self.irmc_info, operation, session_id, session_timeout)]) raid_info_mock.assert_has_calls([mock.call(self.irmc_info)]) def test_create_raid_config_without_logical_disk(self): target_raid_config = { 'logical_disks': [] } self.assertRaises(elcm.ELCMValueError, elcm.create_raid_configuration, irmc_info=self.irmc_info, target_raid_config=target_raid_config) @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_with_raid_level_is_max( self, session_mock, elcm_profile_set_mock, raid_info_mock): raid_info_mock.return_value = self.raid_info expected_input = { 'Server': { 'HWConfigurationIrmc': { '@Processing': 'execute', 'Adapters': { 'RAIDAdapter': [ { 'Arrays': { 'Array': [] }, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': 'Create', 'RaidLevel': '0', 'InitMode': 'fast' } ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } 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': 'MAX', 'raid_level': '0' }, ] } elcm.create_raid_configuration(self.irmc_info, target_raid_config) elcm_profile_set_mock.assert_called_once_with(self.irmc_info, expected_input) session_mock.assert_called_once_with(self.irmc_info, operation, session_id, session_timeout) @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_hybrid_in_target_raid_config( self, session_mock, elcm_profile_set_mock, raid_info_mock): raid_info_mock.return_value = self.raid_info expected_input = { 'Server': { 'HWConfigurationIrmc': { '@Processing': 'execute', 'Adapters': { 'RAIDAdapter': [ { 'Arrays': { 'Array': [ { '@Number': 1, '@ConfigurationType': 'Setting', 'PhysicalDiskRefs': { 'PhysicalDiskRef': [ { '@Number': '0' }, { '@Number': '1' } ] } }, ] }, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': 'Create', 'RaidLevel': '0', 'InitMode': 'fast', 'Size': { '@Unit': 'GB', '#text': 100 }, }, { '@Number': 1, '@Action': 'Create', 'RaidLevel': '1', 'InitMode': 'fast', 'Size': { '@Unit': 'GB', '#text': 100 }, 'ArrayRefs': { 'ArrayRef': [ { '@Number': 1 } ] } } ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } target_raid_config = { 'logical_disks': [ { 'size_gb': 100, 'raid_level': '0', }, { 'size_gb': 100, 'raid_level': '1', 'physical_disks': [ '0', '1' ] }, ] } elcm_profile_set_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } session_id = 1 session_timeout = 1800 operation = 'CONFIG_RAID' 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 elcm_profile_set_mock.assert_called_once_with( self.irmc_info, expected_input) raid_info_mock.assert_called_once_with(self.irmc_info) @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_10_in_target_raid_config( self, session_mock, elcm_profile_set_mock, raid_info_mock): raid_info_mock.return_value = self.raid_info expected_input = { 'Server': { 'HWConfigurationIrmc': { '@Processing': 'execute', 'Adapters': { 'RAIDAdapter': [ { 'Arrays': { 'Array': [] }, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': 'Create', 'RaidLevel': '10', 'InitMode': 'fast', 'Size': { '@Unit': 'GB', '#text': 100 } } ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } target_raid_config = { 'logical_disks': [ { 'size_gb': 100, 'raid_level': '10', } ] } elcm_profile_set_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } session_id = 1 session_timeout = 1800 operation = 'CONFIG_RAID' 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 elcm_profile_set_mock.assert_called_once_with( self.irmc_info, expected_input) raid_info_mock.assert_called_once_with(self.irmc_info) @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_50_in_target_raid_config( self, session_mock, elcm_profile_set_mock, raid_info_mock): raid_info_mock.return_value = self.raid_info expected_input = { 'Server': { 'HWConfigurationIrmc': { '@Processing': 'execute', 'Adapters': { 'RAIDAdapter': [ { 'Arrays': { 'Array': [] }, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': 'Create', 'RaidLevel': '50', 'InitMode': 'fast', 'Size': { '@Unit': 'GB', '#text': 100 } } ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } target_raid_config = { 'logical_disks': [ { 'size_gb': 100, 'raid_level': '50', } ] } elcm_profile_set_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } session_id = 1 session_timeout = 1800 operation = 'CONFIG_RAID' 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 elcm_profile_set_mock.assert_called_once_with( self.irmc_info, expected_input) raid_info_mock.assert_called_once_with(self.irmc_info) @mock.patch.object(elcm, 'elcm_profile_get') @mock.patch.object(elcm, '_create_raid_adapter_profile') def test_get_raid_config_with_logical_drives( self, create_raid_adapter_mock, elcm_profile_get_mock): profile_name = 'RAIDAdapter' elcm_profile_get_mock.return_value = { 'Server': { 'HWConfigurationIrmc': { 'Adapters': { 'RAIDAdapter': [ { '@AdapterId': 'RAIDAdapter0', '@ConfigurationType': 'Addressing', 'Arrays': { 'Array': [ { '@Number': 0, '@ConfigurationType': 'Addressing', 'PhysicalDiskRefs': { 'PhysicalDiskRef': [ { '@Number': '1' } ] } } ] }, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': 'None', 'RaidLevel': '0', 'InitMode': 'fast', 'Size': { '@Unit': 'GB', '#text': 100 }, 'ArrayRefs': { 'ArrayRef': [ { '@Number': 0 } ] } } ] }, 'PhysicalDisks': { 'PhysicalDisk': [ { '@Number': '0', '@Action': 'None', 'Slot': 0, 'PDStatus': 'Operational' } ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } elcm.get_raid_adapter(irmc_info=self.irmc_info) elcm_profile_get_mock.assert_called_once_with( self.irmc_info, profile_name) create_raid_adapter_mock.assert_called_once_with(self.irmc_info) @mock.patch.object(elcm, 'get_raid_adapter') @mock.patch.object(elcm, 'elcm_profile_set') @mock.patch.object(elcm, 'elcm_profile_delete') @mock.patch.object(elcm, '_process_session_data') def test_delete_raid_adapter( self, session_mock, elcm_profile_delete_mock, elcm_profile_set_mock, raid_info_mock): raid_info_mock.return_value = { 'Server': { 'HWConfigurationIrmc': { 'Adapters': { 'RAIDAdapter': [ { '@AdapterId': 'RAIDAdapter0', '@ConfigurationType': 'Addressing', 'Arrays': { 'Array': [ { '@Number': 0, '@ConfigurationType': 'Addressing', 'PhysicalDiskRefs': { 'PhysicalDiskRef': [ { '@Number': '1' }, { '@Number': '4' } ] } } ] }, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': 'None', 'RaidLevel': '0', 'ArrayRefs': { 'ArrayRef': [ { '@Number': 0 } ] } } ] }, 'PhysicalDisks': { 'PhysicalDisk': [ { '@Number': '1', '@Action': 'None', 'Slot': 1, }, { '@Number': '4', '@Action': 'None', 'Slot': 4, } ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } expected_input = { 'Server': { 'HWConfigurationIrmc': { '@Processing': 'execute', 'Adapters': { 'RAIDAdapter': [ { '@AdapterId': 'RAIDAdapter0', '@ConfigurationType': 'Addressing', 'Arrays': { 'Array': [ { '@Number': 0, '@ConfigurationType': 'Addressing', 'PhysicalDiskRefs': { 'PhysicalDiskRef': [ { '@Number': '1' }, { '@Number': '4' } ] } } ] }, 'LogicalDrives': { 'LogicalDrive': [ { '@Number': 0, '@Action': 'Delete', 'RaidLevel': '0', 'ArrayRefs': { 'ArrayRef': [ { '@Number': 0 } ] } } ] }, 'PhysicalDisks': { 'PhysicalDisk': [ { '@Number': '1', '@Action': 'None', 'Slot': 1, }, { '@Number': '4', '@Action': 'None', 'Slot': 4, } ] } } ] }, '@Version': '1.00' }, '@Version': '1.01' } } profile_name = 'RAIDAdapter' elcm_profile_set_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } session_id = 1 session_timeout = 1800 operation = 'CONFIG_RAID' elcm.delete_raid_configuration(irmc_info=self.irmc_info) session_mock.assert_called_once_with(self.irmc_info, operation, session_id, session_timeout) # Check raid_adapter data elcm_profile_set_mock.assert_called_once_with( self.irmc_info, expected_input) raid_info_mock.assert_called_once_with(self.irmc_info) elcm_profile_delete_mock.assert_called_once_with(self.irmc_info, profile_name) @mock.patch.object(elcm, 'get_raid_adapter') @mock.patch.object(elcm, '_get_existing_logical_drives') @mock.patch.object(elcm, 'elcm_profile_set') @mock.patch.object(elcm, '_process_session_data') def test_delete_raid_adapter_without_existing_logical_drive( self, process_session_data_mock, elcm_profile_set_mock, existing_logical_drives_mock, raid_info_mock): raid_info_mock.return_value = { 'Server': { 'HWConfigurationIrmc': { 'Adapters': { 'RAIDAdapter': [ { 'key': 'value' } ] } } } } existing_logical_drives_mock.return_value = None elcm.delete_raid_configuration(self.irmc_info) process_session_data_mock.assert_not_called() elcm_profile_set_mock.assert_not_called() @mock.patch.object(elcm, 'elcm_profile_delete') @mock.patch.object(elcm, 'elcm_profile_create') @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm, 'elcm_session_delete') @mock.patch.object(elcm, 'elcm_profile_get') def test_success_session_monitoring(self, elcm_profile_get_mock, elcm_session_delete_mock, elcm_session_mock, elcm_profile_create_mock, elcm_profile_delete_mock): profile_name = 'RAIDAdapter' param_path = 'Server/HWConfigurationIrmc/Adapters/RAIDAdapter' session_id = 1 elcm_profile_create_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } elcm_session_mock.return_value = { "Session": { "Id": 1, "Tag": "", "WorkSequence": "obtainProfileParameters", "Start": "2018\/03\/19 12:28:03", "Duration": 249, "Status": "terminated regularly" } } elcm._create_raid_adapter_profile(irmc_info=self.irmc_info) elcm_profile_get_mock.assert_called_once_with(self.irmc_info, profile_name) elcm_session_delete_mock.assert_called_once_with( irmc_info=self.irmc_info, session_id=session_id, terminate=True) elcm_session_mock.assert_called_once_with(irmc_info=self.irmc_info, session_id=session_id) elcm_profile_create_mock.assert_called_once_with(self.irmc_info, param_path) elcm_profile_delete_mock.assert_called_once_with(self.irmc_info, profile_name) @mock.patch.object(elcm, 'elcm_profile_delete') @mock.patch.object(elcm, 'elcm_profile_create') @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm, 'elcm_session_get_log') def test_fail_session_monitoring(self, elcm_session_get_log_mock, elcm_session_mock, elcm_profile_create_mock, elcm_profile_delete_mock): profile_name = 'RAIDAdapter' param_path = 'Server/HWConfigurationIrmc/Adapters/RAIDAdapter' session_id = 1 elcm_profile_create_mock.return_value = { "Session": { "Id": 1, "A_Param": "abc123" } } elcm_session_mock.return_value = { "Session": { "Id": 1, "Tag": "", "WorkSequence": "obtainProfileParameters", "Start": "", "Duration": 0, "Status": "terminated - conflict with another running eLCM " "activity" } } elcm_session_get_log_mock.return_value = { 'SessionLog': { 'Id': 1, 'Tag': '', 'WorkSequence': 'obtainProfileParameters', 'Entries': { 'Entry': [ { '@date': '2018\/03\/12 15:10:00', '#text': 'createRaidDatabase: ' 'RAID Controller check start' }, { '@date': '2018\/03\/19 09:40:03', '#text': 'LCMScheduler: Executing of ' 'obtainProfileParameters prohibited as ' 'obtainProfileParameters currently ' 'running' } ] } } } self.assertRaises(scci.SCCIClientError, elcm._create_raid_adapter_profile, self.irmc_info) elcm_session_get_log_mock.assert_called_once_with( irmc_info=self.irmc_info, session_id=session_id) elcm_session_mock.assert_called_once_with(irmc_info=self.irmc_info, session_id=session_id) elcm_profile_create_mock.assert_called_once_with(self.irmc_info, param_path) elcm_profile_delete_mock.assert_called_once_with(self.irmc_info, profile_name) @mock.patch.object(elcm, 'elcm_profile_delete') @mock.patch.object(elcm, 'elcm_profile_create') @mock.patch.object(elcm, '_process_session_data') def test_pass_raised_elcm_profile_not_found( self, _process_session_data_mock, elcm_profile_create_mock, elcm_profile_delete_mock): elcm_profile_delete_mock.side_effect = \ elcm.ELCMProfileNotFound('not found') session_id = 1 elcm_profile_create_mock.return_value = { 'Session': {'Id': session_id, 'Status': 'running'}} session_timeout = 1800 elcm._create_raid_adapter_profile(self.irmc_info) _process_session_data_mock.assert_called_once_with( self.irmc_info, 'CONFIG_RAID', session_id, session_timeout) elcm_profile_create_mock.assert_called_once_with( self.irmc_info, elcm.PARAM_PATH_RAID_CONFIG) elcm_profile_delete_mock.assert_called_once_with( self.irmc_info, elcm.PROFILE_RAID_CONFIG) @mock.patch.object(elcm, 'restore_bios_config') @mock.patch.object(elcm, 'elcm_profile_get_versions') def test_set_bios_configuration_without_versions(self, get_versions_mock, restore_bios_config_mock): settings = [{ "name": "single_root_io_virtualization_support_enabled", "value": "True" }, { "name": "hyper_threading_enabled", "value": "True" }] get_versions_mock.return_value = { "Server": { "AdapterConfigIrmc": { "@Version": "1.00" }, "SystemConfig": { "BiosConfig": { } } } } bios_config_data = { 'Server': { 'SystemConfig': { 'BiosConfig': { 'PciConfig': { 'SingleRootIOVirtualizationSupportEnabled': True }, 'CpuConfig': { 'HyperThreadingEnabled': True, } } } } } elcm.set_bios_configuration(self.irmc_info, settings) restore_bios_config_mock.assert_called_once_with(self.irmc_info, bios_config_data) @mock.patch.object(elcm, 'restore_bios_config') @mock.patch.object(elcm, 'elcm_profile_get_versions') def test_set_bios_configuration_with_versions(self, get_versions_mock, restore_bios_config_mock): settings = [{ "name": "single_root_io_virtualization_support_enabled", "value": "True" }, { "name": "hyper_threading_enabled", "value": "True" }] get_versions_mock.return_value = { "Server": { "@Version": "1.01", "AdapterConfigIrmc": { "@Version": "1.00" }, "SystemConfig": { "BiosConfig": { "@Version": "1.02" } } } } bios_config = { 'Server': { 'SystemConfig': { 'BiosConfig': { 'PciConfig': { 'SingleRootIOVirtualizationSupportEnabled': True }, 'CpuConfig': { 'HyperThreadingEnabled': True, }, "@Version": "1.02" } }, "@Version": "1.01" } } elcm.set_bios_configuration(self.irmc_info, settings) restore_bios_config_mock.assert_called_once_with(self.irmc_info, bios_config) @mock.patch.object(elcm, 'elcm_profile_get_versions') def test_set_bios_configuration_not_found(self, get_versions_mock): settings = [{ "name": "single_root_io_virtualization_support_enabled", "value": "True" }, { "name": "setting1", "value": "True" }] get_versions_mock.return_value = { "Server": { "@Version": "1.01", "AdapterConfigIrmc": { "@Version": "1.00" }, "SystemConfig": { "BiosConfig": { "@Version": "1.02" } } } } self.assertRaises(elcm.BiosConfigNotFound, elcm.set_bios_configuration, self.irmc_info, settings) @mock.patch.object(elcm, 'restore_bios_config') @mock.patch.object(elcm, 'elcm_profile_get_versions') def test_set_bios_configuration_with_boolean_input( self, get_versions_mock, restore_bios_config_mock): settings = [{ "name": "single_root_io_virtualization_support_enabled", "value": True }, { "name": "hyper_threading_enabled", "value": False }] get_versions_mock.return_value = { "Server": { "@Version": "1.01", "AdapterConfigIrmc": { "@Version": "1.00" }, "SystemConfig": { "BiosConfig": { "@Version": "1.02" } } } } bios_config = { 'Server': { 'SystemConfig': { 'BiosConfig': { 'PciConfig': { 'SingleRootIOVirtualizationSupportEnabled': True }, 'CpuConfig': { 'HyperThreadingEnabled': False, }, "@Version": "1.02" } }, "@Version": "1.01" } } elcm.set_bios_configuration(self.irmc_info, settings) restore_bios_config_mock.assert_called_once_with(self.irmc_info, bios_config) @mock.patch.object(elcm, 'backup_bios_config') def test_get_bios_settings(self, backup_bios_config_mock): backup_bios_config_mock.return_value = { 'bios_config': { "Server": { "SystemConfig": { "BiosConfig": { "PciConfig": { "SingleRootIOVirtualizationSupportEnabled": True, }, "CpuConfig": { "HyperThreadingEnabled": True, } } } } } } result = elcm.get_bios_settings(self.irmc_info) expect_settings = [{ "name": "single_root_io_virtualization_support_enabled", "value": "True" }, { "name": "hyper_threading_enabled", "value": "True" }] self.assertCountEqual(expect_settings, result) backup_bios_config_mock.assert_called_once_with( self.irmc_info) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/irmc/test_ipmi.py0000664000175000017500000001341100000000000024042 0ustar00zuulzuul00000000000000# # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Test class for IPMI Module. """ 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 @mock.patch.object(ipmi_command, 'Command', new=mock.Mock()) class IpmiTestCase(testtools.TestCase): """Tests for IPMI Unit Test Cases for getting information via ipmi raw command """ def setUp(self): super(IpmiTestCase, self).setUp() self.info = {'irmc_address': "10.0.0.10", 'irmc_username': "admin", 'irmc_password': "admin", } @mock.patch.object(ipmi, '_send_raw_command') def test_get_tpm_status_true(self, exec_mock): exec_mock.return_value = {'command': 0xF5, 'code': 0x00, 'netfn': 0x2F, 'data': [0x80, 0x28, 0x00, 0xC0, 0xC0]} cmd = "0x2E 0xF5 0x80 0x28 0x00 0x81 0xC0" actual_out = ipmi.get_tpm_status(self.info) self.assertEqual(True, actual_out) exec_mock.assert_called_once_with(mock.ANY, cmd) @mock.patch.object(ipmi, '_send_raw_command') def test_get_tpm_status_false(self, exec_mock): exec_mock.return_value = {'command': 0xF5, 'code': 0x00, 'netfn': 0x2F, 'data': [0x80, 0x28, 0x00, 0x80, 0x01]} cmd = "0x2E 0xF5 0x80 0x28 0x00 0x81 0xC0" actual_out = ipmi.get_tpm_status(self.info) self.assertEqual(False, actual_out) exec_mock.assert_called_once_with(mock.ANY, cmd) @mock.patch.object(ipmi, '_send_raw_command') def test_get_tpm_status_error_code(self, exec_mock): exec_mock.return_value = {'command': 0xF5, 'code': 0x01, 'netfn': 0x2F, 'data': [0x80, 0x28, 0x00, 0x80, 0x01]} cmd = "0x2E 0xF5 0x80 0x28 0x00 0x81 0xC0" self.assertRaises(ipmi.IPMIFailure, ipmi.get_tpm_status, self.info) exec_mock.assert_called_once_with(mock.ANY, cmd) @mock.patch.object(ipmi, '_send_raw_command') def test_get_tpm_status_exception(self, exec_mock): exec_mock.side_effect = ipmi_exception.IpmiException cmd = "0x2E 0xF5 0x80 0x28 0x00 0x81 0xC0" self.assertRaises(ipmi.IPMIFailure, ipmi.get_tpm_status, self.info) exec_mock.assert_called_once_with(mock.ANY, cmd) @mock.patch.object(ipmi, '_send_raw_command') def test_get_pci(self, exec_mock): pci_device_ids = ['0x1000/0x0079', '0x2100/0x0080'] exec_mock.side_effect = ({'command': 0xF1, 'code': 0x00, 'netfn': 0x2F, 'data': [0x80, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x10, 0x79, 0x00, 0x34, 0x17, 0x76, 0x11, 0x00, 0x04, 0x01]}, {'command': 0xF1, 'code': 0xC9, 'netfn': 0x2F, 'error': 'Parameter out of range', 'data': [0x80, 0x28, 0x00]}) cmd1 = "0x2E 0xF1 0x80 0x28 0x00 0x1A 0x1 0x00" cmd2 = "0x2E 0xF1 0x80 0x28 0x00 0x1A 0x2 0x00" actual_out = ipmi.get_pci_device(self.info, pci_device_ids) self.assertEqual(1, actual_out) exec_mock.assert_has_calls([mock.call(mock.ANY, cmd1), mock.call(mock.ANY, cmd2)]) @mock.patch.object(ipmi, '_send_raw_command') def test_get_pci_blank(self, exec_mock): pci_device_ids = [] actual_out = ipmi.get_pci_device(self.info, pci_device_ids) self.assertEqual(0, actual_out) self.assertTrue(exec_mock.called) @mock.patch.object(ipmi, '_send_raw_command') def test_get_pci_not_found(self, exec_mock): pci_device_ids = ['0x1111/0x1179', '0x2100/0x0080'] exec_mock.side_effect = ({'command': 0xF1, 'code': 0x00, 'netfn': 0x2F, 'data': [0x80, 0x28, 0x00, 0x00, 0x00, 0x05, 0x00, 0x10, 0x79, 0x00, 0x34, 0x17, 0x76, 0x11, 0x00, 0x04, 0x01]}, {'command': 0xF1, 'code': 0xC9, 'netfn': 0x2F, 'error': 'Parameter out of range', 'data': [0x80, 0x28, 0x00]}) cmd1 = "0x2E 0xF1 0x80 0x28 0x00 0x1A 0x1 0x00" cmd2 = "0x2E 0xF1 0x80 0x28 0x00 0x1A 0x2 0x00" actual_out = ipmi.get_pci_device(self.info, pci_device_ids) self.assertEqual(0, actual_out) exec_mock.assert_has_calls([mock.call(mock.ANY, cmd1), mock.call(mock.ANY, cmd2)]) @mock.patch.object(ipmi, '_send_raw_command') def test_get_pci_exception(self, exec_mock): pci_device_ids = ['0x1111/0x1179', '0x2100/0x0080'] exec_mock.side_effect = ipmi_exception.IpmiException('Error') cmd = "0x2E 0xF1 0x80 0x28 0x00 0x1A 0x1 0x00" e = self.assertRaises(ipmi.IPMIFailure, ipmi.get_pci_device, self.info, pci_device_ids) exec_mock.assert_called_once_with(mock.ANY, cmd) self.assertEqual('IPMI operation \'GET PCI device quantity\' ' 'failed: Error', str(e)) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/irmc/test_scci.py0000664000175000017500000016065000000000000024035 0ustar00zuulzuul00000000000000# # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Test class for iRMC Power Driver """ import os import time from unittest import mock import xml.etree.ElementTree as ET 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 = """ 10.124.196.156 0 0 0 0 1 0 /srv/nfs 0 virtual-media.img 0 1 0 1 0 10.124.196.156 0 0 0 0 1 0 /srv/nfs 0 virtual-media.iso 0 1 0 1 0 """ class SCCITestCase(testtools.TestCase): """Tests for SCCI Unit Test Cases for power on/off/reset, and mount cd/fd """ def setUp(self): super(SCCITestCase, self).setUp() self.requests_mock = self.useFixture(rm_fixture.Fixture()) with open(os.path.join( os.path.dirname(__file__), 'fixtures/irmc_report_ok.xml'), "r") as report_ok: self.report_ok_txt = report_ok.read() 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 = dET.fromstring(self.report_ng_txt) self.irmc_address = '10.124.196.159' self.irmc_username = 'admin' self.irmc_password = 'admin0' self.irmc_port = 80 self.irmc_auth_method = 'basic' self.irmc_client_timeout = 60 self.irmc_info = {'irmc_address': self.irmc_address, 'irmc_username': self.irmc_username, 'irmc_password': self.irmc_password, 'irmc_snmp_port': 161, 'irmc_snmp_version': 'v2c', 'irmc_snmp_community': 'public', 'irmc_snmp_security': None, 'irmc_client_timeout': self.irmc_client_timeout, 'irmc_sensor_method': 'ipmitool', 'irmc_auth_method': self.irmc_auth_method, 'irmc_port': 443, 'irmc_tempdir': "/tmp" } self.irmc_remote_image_server = '10.33.110.49' self.irmc_remote_image_user_domain = 'example.local' self.irmc_remote_image_share_type = scci.ShareType.nfs self.irmc_remote_image_share_name = 'share' self.irmc_remote_image_deploy_iso = 'ubuntu-14.04.1-server-amd64.iso' self.irmc_remote_image_username = 'deployer' self.irmc_remote_image_user_password = 'password' def test_get_share_type_ok(self): nfs_result = scci.get_share_type("nfs") self.assertEqual(scci.ShareType.nfs, nfs_result) cifs_result = scci.get_share_type("cifs") self.assertEqual(scci.ShareType.cifs, cifs_result) NFS_result = scci.get_share_type("NFS") self.assertEqual(scci.ShareType.nfs, NFS_result) CIFS_result = scci.get_share_type("CIFS") self.assertEqual(scci.ShareType.cifs, CIFS_result) def test_get_share_type_ng(self): self.assertRaises(KeyError, scci.get_share_type, "abc") @mock.patch('scciclient.irmc.scci.requests') def test_scci_cmd_protocol_https_ok(self, mock_requests): https_port = 443 mock_requests.post.return_value = mock.Mock( return_value='ok', status_code=200, text=""" 0 Information No Error """) returned_mock_requests_post = scci.scci_cmd( self.irmc_address, self.irmc_username, self.irmc_password, scci.POWER_ON, port=https_port, auth_method=self.irmc_auth_method, client_timeout=self.irmc_client_timeout) mock_requests.post.assert_called_with( 'https://' + self.irmc_address + '/config', data=scci.POWER_ON, headers={'Content-type': 'application/x-www-form-urlencoded'}, verify=False, timeout=self.irmc_client_timeout, allow_redirects=False, auth=mock_requests.auth.HTTPBasicAuth(self.irmc_username, self.irmc_password)) self.assertEqual('ok', returned_mock_requests_post.return_value) def test_scci_cmd_protocol_http_and_auth_basic_ok(self): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) r = scci.scci_cmd(self.irmc_address, self.irmc_username, self.irmc_password, scci.POWER_ON, port=self.irmc_port, auth_method=self.irmc_auth_method, client_timeout=self.irmc_client_timeout) self.assertEqual(r.status_code, 200) def test_scci_cmd_protocol_http_and_auth_digest_ok(self): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) auth_digest = 'digest' r = scci.scci_cmd(self.irmc_address, self.irmc_username, self.irmc_password, scci.POWER_ON, port=self.irmc_port, auth_method=auth_digest, client_timeout=self.irmc_client_timeout) self.assertEqual(r.status_code, 200) def test_scci_cmd_authentication_failure(self): self.requests_mock.post("http://" + self.irmc_address + "/config", text="401 Unauthorized", status_code=401) e = self.assertRaises(scci.SCCIClientError, scci.scci_cmd, self.irmc_address, self.irmc_username, self.irmc_password, scci.POWER_ON, port=self.irmc_port, auth_method=self.irmc_auth_method, client_timeout=self.irmc_client_timeout) self.assertEqual( 'HTTP PROTOCOL ERROR, STATUS CODE = 401', str(e)) def test_scci_cmd_protocol_ng(self): ssh_port = 22 e = self.assertRaises(scci.SCCIInvalidInputError, scci.scci_cmd, self.irmc_address, self.irmc_username, self.irmc_password, scci.POWER_ON, port=ssh_port, auth_method=self.irmc_auth_method, client_timeout=self.irmc_client_timeout) self.assertEqual((("Invalid port %(port)d or " "auth_method for method %(auth_method)s") % {'port': ssh_port, 'auth_method': self.irmc_auth_method}), str(e)) def test_scci_cmd_auth_method_ng(self): unknown_auth_method = 'unknown' e = self.assertRaises(scci.SCCIInvalidInputError, scci.scci_cmd, self.irmc_address, self.irmc_username, self.irmc_password, scci.POWER_ON, port=self.irmc_port, auth_method=unknown_auth_method, client_timeout=self.irmc_client_timeout) self.assertEqual(("Invalid port %(port)d or " "auth_method for method %(auth_method)s") % {'port': self.irmc_port, 'auth_method': unknown_auth_method}, str(e)) def test_power_on_scci_xml_parse_failed(self): self.requests_mock.post( "http://" + self.irmc_address + "/config", text=""" 31 Error Error 31 (Import of settings in WinSCU XML format failed) occurred XML parser creation failed (Error parsing: attribute value should start with a quote SEQ> """) 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) e = self.assertRaises(scci.SCCIClientError, client, scci.POWER_ON) self.assertEqual( 'not well-formed (invalid token): line 10, column 41', str(e)) def test_power_on_http_failed(self): self.requests_mock.post("http://" + self.irmc_address + "/config", text="anything", status_code=302) 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) e = self.assertRaises(scci.SCCIClientError, client, scci.POWER_ON) self.assertEqual( 'HTTP PROTOCOL ERROR, STATUS CODE = 302', str(e)) @mock.patch.object(time, 'sleep') def test_power_on_ok(self, mock_sleep): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) 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) r = client(scci.POWER_ON) self.assertEqual(r.status_code, 200) mock_sleep.assert_called_once_with(3) @mock.patch.object(time, 'sleep') def test_power_off_ok(self, mock_sleep): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) 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) 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", text=""" 0 Information No Error """) 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) r = client(scci.POWER_CYCLE) self.assertEqual(r.status_code, 200) @mock.patch.object(time, 'sleep') def test_power_reset_ok(self, mock_sleep): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) 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) 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", text=""" 0 Information No Error """) 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) r = client(scci.POWER_RAISE_NMI) self.assertEqual(r.status_code, 200) def test_power_soft_off_ok(self): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) 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) r = client(scci.POWER_SOFT_OFF) self.assertEqual(r.status_code, 200) def test_power_soft_off_ng(self): self.requests_mock.post( "http://" + self.irmc_address + "/config", text=""" 31 Error Error 31 (Import of settings in WinSCU""" """ XML format failed) occurred ServerView Agent not connected """) 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) e = self.assertRaises(scci.SCCIClientError, client, scci.POWER_SOFT_OFF) self.assertEqual( 'SCCI PROTOCOL ERROR, STATUS CODE = 31,' ' ERROR = ServerView Agent not connected, MESSAGE = Error 31' ' (Import of settings in WinSCU XML format failed) occurred', str(e)) def test_power_soft_cycle_ok(self): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) 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) r = client(scci.POWER_SOFT_CYCLE) self.assertEqual(r.status_code, 200) def test_power_soft_cycle_ng(self): self.requests_mock.post( "http://" + self.irmc_address + "/config", text=""" 31 Error Error 31 (Import of settings in WinSCU""" """ XML format failed) occurred ServerView Agent not connected """) 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) e = self.assertRaises(scci.SCCIClientError, client, scci.POWER_SOFT_CYCLE) self.assertEqual( 'SCCI PROTOCOL ERROR, STATUS CODE = 31,' ' ERROR = ServerView Agent not connected, MESSAGE = Error 31' ' (Import of settings in WinSCU XML format failed) occurred', str(e)) def test_power_cancel_shutdown_ok(self): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) 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) r = client(scci.POWER_CANCEL_SHUTDOWN) self.assertEqual(r.status_code, 200) def test_power_cancel_shutdown_ng(self): self.requests_mock.post( "http://" + self.irmc_address + "/config", text=""" 31 Error Error 31 (Import of settings in WinSCU""" """ XML format failed) occurred ServerView Agent not connected """) 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) e = self.assertRaises(scci.SCCIClientError, client, scci.POWER_CANCEL_SHUTDOWN) self.assertEqual( 'SCCI PROTOCOL ERROR, STATUS CODE = 31,' ' ERROR = ServerView Agent not connected, MESSAGE = Error 31' ' (Import of settings in WinSCU XML format failed) occurred', str(e)) def test_get_sensor_data_records_ok(self): sensor = scci.get_sensor_data_records(self.report_ok_xml) self.assertEqual(len(sensor), 10) def test_get_sensor_data_records_ng(self): sensor = scci.get_sensor_data_records(self.report_ng_xml) self.assertIsNone(sensor) def test_get_irmc_version_ok(self): version = scci.get_irmc_version(self.report_ok_xml) self.assertEqual(version.attrib['Name'], "iRMC S4") def test_get_irmc_version_ng(self): version = scci.get_irmc_version(self.report_ng_xml) self.assertIsNone(version) def test_get_report_ok(self): self.requests_mock.get( "http://" + self.irmc_address + "/report.xml", text=self.report_ok_txt, headers={'Content-Type': "application/x-www-form-urlencoded"}) root = scci.get_report(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) self.assertEqual(root.tag, 'Root') sensor = scci.get_sensor_data_records(root) self.assertEqual(sensor.tag, 'SensorDataRecords') def test_get_report_http_failed(self): self.requests_mock.get( "http://" + self.irmc_address + "/report.xml", text=self.report_ok_txt, headers={'Content-Type': "application/x-www-form-urlencoded"}, status_code=302) e = self.assertRaises(scci.SCCIClientError, scci.get_report, 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) self.assertEqual( 'HTTP PROTOCOL ERROR, STATUS CODE = 302', str(e)) @mock.patch.object(time, 'sleep') def test_virtual_media_cd_setting_ok(self, sleep_mock): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) cmd = scci.get_virtual_cd_set_params_cmd( self.irmc_remote_image_server, self.irmc_remote_image_user_domain, self.irmc_remote_image_share_type, self.irmc_remote_image_share_name, self.irmc_remote_image_deploy_iso, self.irmc_remote_image_username, self.irmc_remote_image_user_password) 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) r = client(cmd, do_async=False) self.assertEqual(r.status_code, 200) sleep_mock.assert_called_once_with(5) @mock.patch.object(time, 'sleep') def test_virtual_media_fd_setting_ok(self, sleep_mock): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) cmd = scci.get_virtual_fd_set_params_cmd( self.irmc_remote_image_server, self.irmc_remote_image_user_domain, self.irmc_remote_image_share_type, self.irmc_remote_image_share_name, 'floppy1.flp', self.irmc_remote_image_username, self.irmc_remote_image_user_password) 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) r = client(cmd, do_async=False) self.assertEqual(r.status_code, 200) sleep_mock.assert_called_once_with(5) @mock.patch.object(time, 'sleep') def test_mount_cd_ok(self, sleep_mock): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) 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) r = client(scci.MOUNT_CD) self.assertEqual(r.status_code, 200) self.assertFalse(sleep_mock.called) @mock.patch.object(time, 'sleep') def test_mount_fd_ok(self, sleep_mock): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) 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) r = client(scci.MOUNT_FD) self.assertEqual(r.status_code, 200) self.assertFalse(sleep_mock.called) def test_unmount_cd_ok(self): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) 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, port=self.irmc_port, auth_method=self.irmc_auth_method, client_timeout=self.irmc_client_timeout) r = client(scci.UNMOUNT_CD) self.assertEqual(r.status_code, 200) def test_unmount_fd_ok(self): self.requests_mock.post("http://" + self.irmc_address + "/config", text=""" 0 Information No Error """) 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) r = client(scci.MOUNT_FD) self.assertEqual(r.status_code, 200) def test_get_essential_properties(self): ESSENTIAL_PROPERTIES_KEYS = { 'memory_mb', 'local_gb', 'cpus', 'cpu_arch'} expected = {'memory_mb': 8192, 'local_gb': 185, 'cpus': 16, 'cpu_arch': 'x86_64'} result = scci.get_essential_properties( self.report_ok_xml, ESSENTIAL_PROPERTIES_KEYS) self.assertEqual(expected, result) def test_get_essential_properties_empty_cpu_socket(self): ESSENTIAL_PROPERTIES_KEYS = { 'memory_mb', 'local_gb', 'cpus', 'cpu_arch'} expected = {'memory_mb': 8192, 'local_gb': 185, 'cpus': 16, 'cpu_arch': 'x86_64'} result = scci.get_essential_properties( self.report_ng_xml, ESSENTIAL_PROPERTIES_KEYS) self.assertEqual(expected, result) @mock.patch.object(ipmi, 'get_pci_device') @mock.patch.object(snmp, 'get_server_model') @mock.patch.object(snmp, 'get_irmc_firmware_version') @mock.patch.object(snmp, 'get_bios_firmware_version') @mock.patch.object(ipmi, 'get_tpm_status') def test_get_capabilities_properties(self, tpm_mock, bios_mock, irmc_mock, server_mock, pci_device_mock): capabilities_properties = {'trusted_boot', 'irmc_firmware_version', 'rom_firmware_version', 'server_model', 'pci_gpu_devices'} gpu_ids = ['0x1000/0x0079', '0x2100/0x0080'] kwargs = {} kwargs['sleep_flag'] = True tpm_mock.return_value = False bios_mock.return_value = 'V4.6.5.4 R1.15.0 for D3099-B1x' irmc_mock.return_value = 'iRMC S4-7.82F' server_mock.return_value = 'TX2540M1F5' pci_device_mock.side_effect = [1] expected = {'irmc_firmware_version': 'iRMC S4-7.82F', 'pci_gpu_devices': 1, 'rom_firmware_version': 'V4.6.5.4 R1.15.0 for D3099-B1x', 'server_model': 'TX2540M1F5', 'trusted_boot': False} result = scci.get_capabilities_properties( self.irmc_info, capabilities_properties, gpu_ids, **kwargs) self.assertEqual(expected, result) tpm_mock.assert_called_once_with(self.irmc_info) bios_mock.assert_called_once_with(mock.ANY) irmc_mock.assert_called_once_with(mock.ANY) server_mock.assert_called_once_with(mock.ANY) pci_device_mock.assert_called_once_with(self.irmc_info, gpu_ids) @mock.patch.object(ipmi, 'get_pci_device') @mock.patch.object(snmp, 'get_server_model') @mock.patch.object(snmp, 'get_irmc_firmware_version') @mock.patch.object(snmp, 'get_bios_firmware_version') @mock.patch.object(ipmi, 'get_tpm_status') def test_get_capabilities_properties_with_cpu_fpga(self, tpm_mock, bios_mock, irmc_mock, server_mock, pci_device_mock): capabilities_properties = {'trusted_boot', 'irmc_firmware_version', 'rom_firmware_version', 'server_model', 'pci_gpu_devices', 'cpu_fpga'} gpu_ids = ['0x1000/0x0079', '0x2100/0x0080'] cpu_fpgas = ['0x1000/0x0179', '0x2100/0x0180'] kwargs = {} kwargs['sleep_flag'] = True tpm_mock.return_value = False bios_mock.return_value = 'V4.6.5.4 R1.15.0 for D3099-B1x' irmc_mock.return_value = 'iRMC S4-7.82F' server_mock.return_value = 'TX2540M1F5' pci_device_mock.side_effect = [1, 1] expected = {'irmc_firmware_version': 'iRMC S4-7.82F', 'pci_gpu_devices': 1, 'cpu_fpga': 1, 'rom_firmware_version': 'V4.6.5.4 R1.15.0 for D3099-B1x', 'server_model': 'TX2540M1F5', 'trusted_boot': False} result = scci.get_capabilities_properties( self.irmc_info, capabilities_properties, gpu_ids, cpu_fpgas, **kwargs) self.assertEqual(expected, result) tpm_mock.assert_called_once_with(self.irmc_info) bios_mock.assert_called_once_with(mock.ANY) irmc_mock.assert_called_once_with(mock.ANY) server_mock.assert_called_once_with(mock.ANY) pci_device_mock.assert_has_calls([ mock.call(self.irmc_info, gpu_ids), mock.call(self.irmc_info, cpu_fpgas)]) @mock.patch.object(ipmi, 'get_pci_device') @mock.patch.object(snmp, 'get_server_model') @mock.patch.object(snmp, 'get_irmc_firmware_version') @mock.patch.object(snmp, 'get_bios_firmware_version') @mock.patch.object(ipmi, 'get_tpm_status') def test_get_capabilities_properties_blank(self, tpm_mock, bios_mock, irmc_mock, server_mock, pci_device_mock): capabilities_properties = {} gpu_ids = ['0x1000/0x0079', '0x2100/0x0080'] cpu_fpgas = ['0x1000/0x0179', '0x2100/0x0180'] kwargs = {} kwargs['sleep_flag'] = True tpm_mock.return_value = False bios_mock.return_value = 'V4.6.5.4 R1.15.0 for D3099-B1x' irmc_mock.return_value = 'iRMC S4-7.82F' server_mock.return_value = 'TX2540M1F5' pci_device_mock.side_effect = [1, 1] expected = {} result = scci.get_capabilities_properties( self.irmc_info, capabilities_properties, gpu_ids, cpu_fpgas, **kwargs) self.assertEqual(expected, result) @mock.patch.object(ipmi, '_send_raw_command') @mock.patch.object(snmp.SNMPClient, 'get') def test_get_capabilities_properties_scci_client_error(self, snmp_mock, ipmiraw_mock): capabilities_properties = {'trusted_boot', 'irmc_firmware_version', 'rom_firmware_version', 'server_model', 'pci_gpu_devices', 'cpu_fpga'} gpu_ids = ['0x1000/0x0079', '0x2100/0x0080'] cpu_fpgas = ['0x1000/0x0179', '0x2100/0x0180'] kwargs = {} kwargs['sleep_flag'] = True ipmiraw_mock.return_value = None snmp_mock.side_effect = snmp.SNMPFailure("error") e = self.assertRaises(scci.SCCIClientError, scci.get_capabilities_properties, self.irmc_info, capabilities_properties, gpu_ids, cpu_fpgas, **kwargs) self.assertEqual('Capabilities inspection failed: SNMP operation \'' 'GET BIOS FIRMWARE VERSION\' failed: error', str(e)) @mock.patch.object(ipmi, 'get_pci_device') @mock.patch.object(snmp.SNMPClient, 'get') def test_get_capabilities_properties_scci_client_error_ipmi(self, snmp_mock, ipmi_mock): capabilities_properties = {'trusted_boot', 'irmc_firmware_version', 'rom_firmware_version', 'server_model', 'pci_gpu_devices', 'cpu_fpga'} gpu_ids = ['0x1000/0x0079', '0x2100/0x0080'] cpu_fpgas = ['0x1000/0x0179', '0x2100/0x0180'] kwargs = {} kwargs['sleep_flag'] = True ipmi_mock.side_effect = ipmi.IPMIFailure("IPMI error") snmp_mock.return_value = None e = self.assertRaises(scci.SCCIClientError, scci.get_capabilities_properties, self.irmc_info, capabilities_properties, gpu_ids, cpu_fpgas, **kwargs) self.assertEqual('Capabilities inspection failed: IPMI error', str(e)) def test_fail_get_raid_fgi_status(self): report_fake = self.report_ok_xml report_fake.find("./Software/ServerView/ServerViewRaid").clear() self.assertRaises(scci.SCCIInvalidInputError, scci.get_raid_fgi_status, report=report_fake) def test_fail_get_raid_fgi_status_1(self): report_fake = self.report_ok_xml report_fake.find("./Software/ServerView/ServerViewRaid/amEMSV" "/System/Adapter").clear() self.assertRaises(scci.SCCIRAIDNotReady, scci.get_raid_fgi_status, report=report_fake) def test_get_raid_fgi_status_ok(self): # Fake activity status of FGI in xml report url = "./Software/ServerView/ServerViewRaid/amEMSV/System/Adapter" report_fake = self.report_ok_xml report_input = report_fake.find(url) element_1 = ET.Element("LogicalDrive", name="LogicalDrive") element_2 = ET.Element("LogDriveNumber", name="LogDriveNumber") element_3 = ET.Element("Activity", name="Activity") report_input.append(element_1) report_input.find("./LogicalDrive").append(element_2) report_fake.find(url + "/LogicalDrive/LogDriveNumber").text = '0' report_input.find("./LogicalDrive").append(element_3) report_fake.find(url + "/LogicalDrive/Activity").text = 'Idle' 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="""
File not found
""") 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=""" 0 Information No Error """) 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="""
File not found
""") 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=""" 0 Information No Error """) 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=""" 0 Information No Error """) 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=""" 6 Error File not provided """) # 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=""" 0 Information No Error """) 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=""" 6 Error File not provided """) # 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) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/irmc/test_snmp.py0000664000175000017500000003621100000000000024064 0ustar00zuulzuul00000000000000# # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Test class for snmp module. """ from unittest import mock from pysnmp import error as snmp_error from pysnmp import hlapi as pysnmp import testtools from scciclient.irmc import snmp class IRMCSnmpTestCase(testtools.TestCase): """Tests for SNMP module Unit Test Cases for getting information via snmp module """ def setUp(self): super(IRMCSnmpTestCase, self).setUp() def test_get_irmc_firmware_version(self): snmp_client = mock.Mock() snmp_client.get.side_effect = ['iRMC S4', '7.82F'] cmd1 = snmp.BMC_NAME_OID cmd2 = snmp.IRMC_FW_VERSION_OID actual_out = snmp.get_irmc_firmware_version(snmp_client) self.assertEqual('iRMC S4-7.82F', actual_out) snmp_client.get.assert_has_calls([mock.call(cmd1), mock.call(cmd2)]) def test_get_irmc_firmware_version_BMC_only(self): snmp_client = mock.Mock() snmp_client.get.side_effect = ['iRMC S4', ''] cmd1 = snmp.BMC_NAME_OID cmd2 = snmp.IRMC_FW_VERSION_OID actual_out = snmp.get_irmc_firmware_version(snmp_client) self.assertEqual('iRMC S4', actual_out) snmp_client.get.assert_has_calls([mock.call(cmd1), mock.call(cmd2)]) def test_get_irmc_firmware_version_FW_only(self): snmp_client = mock.Mock() snmp_client.get.side_effect = ['', '7.82F'] cmd1 = snmp.BMC_NAME_OID cmd2 = snmp.IRMC_FW_VERSION_OID actual_out = snmp.get_irmc_firmware_version(snmp_client) self.assertEqual('7.82F', actual_out) snmp_client.get.assert_has_calls([mock.call(cmd1), mock.call(cmd2)]) def test_get_irmc_firmware_version_blank(self): snmp_client = mock.Mock() snmp_client.get.side_effect = ['', ''] cmd1 = snmp.BMC_NAME_OID cmd2 = snmp.IRMC_FW_VERSION_OID actual_out = snmp.get_irmc_firmware_version(snmp_client) self.assertEqual('', actual_out) snmp_client.get.assert_has_calls([mock.call(cmd1), mock.call(cmd2)]) def test_get_irmc_firmware_version_exception(self): snmp_client = mock.Mock() snmp_client.get.side_effect = snmp.SNMPFailure('Error') cmd1 = snmp.BMC_NAME_OID e = self.assertRaises(snmp.SNMPIRMCFirmwareFailure, snmp.get_irmc_firmware_version, snmp_client) snmp_client.get.assert_has_calls([mock.call(cmd1)]) self.assertEqual('SNMP operation \'GET IRMC FIRMWARE VERSION\'' ' failed: Error', str(e)) def test_get_bios_firmware_version(self): snmp_client = mock.Mock() snmp_client.return_value = 'V4.6.5.4 R1.15.0 for D3099-B1x' snmp_client.get.return_value = 'V4.6.5.4 R1.15.0 for D3099-B1x' cmd = snmp.BIOS_FW_VERSION_OID actual_out = snmp.get_bios_firmware_version(snmp_client) self.assertEqual('V4.6.5.4 R1.15.0 for D3099-B1x', actual_out) snmp_client.get.assert_called_once_with(cmd) def test_get_bios_firmware_version_exception(self): snmp_client = mock.Mock() snmp_client.get.side_effect = snmp.SNMPFailure('Error') cmd = snmp.BIOS_FW_VERSION_OID e = self.assertRaises(snmp.SNMPBIOSFirmwareFailure, snmp.get_bios_firmware_version, snmp_client) snmp_client.get.assert_called_once_with(cmd) self.assertEqual('SNMP operation \'GET BIOS FIRMWARE VERSION\'' ' failed: Error', str(e)) def test_get_server_model(self): snmp_client = mock.Mock() snmp_client.return_value = 'TX2540M1F5' snmp_client.get.return_value = 'TX2540M1F5' cmd = snmp.SERVER_MODEL_OID actual_out = snmp.get_server_model(snmp_client) self.assertEqual('TX2540M1F5', actual_out) snmp_client.get.assert_called_once_with(cmd) def test_get_server_model_exception(self): snmp_client = mock.Mock() snmp_client.get.side_effect = snmp.SNMPFailure('Error') cmd = snmp.SERVER_MODEL_OID e = self.assertRaises(snmp.SNMPServerModelFailure, snmp.get_server_model, snmp_client) snmp_client.get.assert_called_once_with(cmd) self.assertEqual('SNMP operation \'GET SERVER MODEL\'' ' failed: Error', str(e)) class SNMPClientTestCase(testtools.TestCase): def setUp(self): super(SNMPClientTestCase, self).setUp() self.address = '1.2.3.4' self.port = '6700' self.oid = 'oid' self.value = 'value' @mock.patch.object(pysnmp, 'SnmpEngine', authspec=True) def test___init__(self, mock_snmpengine): client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1) 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.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_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(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_community.assert_called_once_with(client.read_community, mpModel=1) @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_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(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_transport.assert_called_once_with((client.address, client.port)) @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_transport.assert_called_once_with((client.address, client.port)) @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) mock_getcmd.return_value = iter([("", 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) self.assertEqual(1, mock_getcmd.call_count) @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_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) self.assertEqual(1, mock_nextcmd.call_count) @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 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_getcmd.called) @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 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_nextcmd.called) @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_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.assertEqual(1, mock_getcmd.call_count) @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) 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.assertEqual(1, mock_nextcmd.call_count) @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_setcmd.return_value = iter([("", None, 0, [var_bind])]) client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) client.set(self.oid, self.value) self.assertEqual(1, mock_setcmd.call_count) @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 client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp.SNMPFailure, client.set, self.oid, self.value) self.assertFalse(mock_setcmd.called) @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) 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) self.assertEqual(1, mock_setcmd.call_count) ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1692971673.122654 python-scciclient-0.15.0/scciclient/tests/irmc/viom/0000775000175000017500000000000000000000000022445 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/irmc/viom/__init__.py0000664000175000017500000000000000000000000024544 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/irmc/viom/test_client.py0000664000175000017500000010356000000000000025341 0ustar00zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from unittest import mock import testtools from scciclient.irmc import scci from scciclient.irmc.viom import client as viom_client from scciclient.irmc.viom import elcm as viom_elcm class VIOMConfigurationTestCase(testtools.TestCase): def setUp(self): super(VIOMConfigurationTestCase, self).setUp() self.irmc_info = { 'irmc_address': '10.124.196.159', 'irmc_username': 'admin', 'irmc_password': 'admin0', 'irmc_port': 80, 'irmc_auth_method': 'basic', 'irmc_client_timeout': 60, } self.identification = 'viom_identification' self.configurator = viom_client.VIOMConfiguration( self.irmc_info, self.identification) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def _test_terminate(self, mock_set, reboot=None): if reboot is None: self.configurator.terminate() reboot = False else: self.configurator.terminate(reboot=reboot) expected_json = { 'VIOMManage': { 'Manage': False, 'Identification': 'viom_identification', }, 'InitBoot': reboot, 'Mode': 'delete', '@Version': '1.00', } mock_set.assert_called_once_with(expected_json) def test_terminate(self): self._test_terminate() def test_terminate_reboot_true(self): self._test_terminate(reboot=True) def test_terminate_reboot_false(self): self._test_terminate(reboot=False) @staticmethod def _create_json_for_apply(slot_json, init_boot=False): return { 'UseVirtualAddresses': True, 'Mode': 'new', 'InitBoot': init_boot, 'VIOMManage': { 'Manage': True, 'Identification': 'viom_identification' }, 'Slots': { 'Slot': [slot_json] }, '@Version': '1.00', } @staticmethod def _create_json_before_apply(slot_json): return { 'VIOMManage': { 'Identification': 'viom_identification' }, 'Slots': { 'Slot': [slot_json] }, '@Version': '1.00', } @staticmethod def _create_json_slot_onbaord_lan(lan_port): lan_ports = [] for port_idx in range(1, lan_port['@PortIdx']): lan_ports.append( {'@PortIdx': port_idx, 'BootPriority': 1, 'BootProtocol': 'None', 'PortEnable': True, 'UseVirtualAddresses': False}) lan_ports.append(lan_port) return { '@SlotIdx': 0, 'OnboardControllers': { 'OnboardController': [ {'@OnboardControllerIdx': 1, 'LANAdapter': { 'Ports': { 'Port': lan_ports } }} ] } } @staticmethod def _create_json_slot_with_cna_lan(card_idx, port_idx, lan_function): return { '@SlotIdx': 0, 'AddOnCards': { 'AddOnCard': [ {'@AddOnCardIdx': card_idx, 'CNAAdapter': { 'Ports': { 'Port': [ {'@PortIdx': port_idx, 'PortEnable': True, 'Functions': { 'Function': [ {'@FunctionIdx': 1, 'LANFunction': lan_function}, ] }} ] } }} ] } } @staticmethod def _create_json_slot_with_cna_iscsi(card_idx, port_idx, iscsi_function, lan_function=None): if not lan_function: lan_function = { 'FunctionEnable': False, 'BootProtocol': 'None', 'BootPriority': 1, } return { '@SlotIdx': 0, 'AddOnCards': { 'AddOnCard': [ {'@AddOnCardIdx': card_idx, 'CNAAdapter': { 'Ports': { 'Port': [ {'@PortIdx': port_idx, 'PortEnable': True, 'Functions': { 'Function': [ {'@FunctionIdx': 1, 'LANFunction': lan_function}, {'@FunctionIdx': 3, 'ISCSIFunction': iscsi_function} ] }} ] } }} ] } } @staticmethod def _create_json_slot_with_fc(card_idx, fc_port): return { '@SlotIdx': 0, 'AddOnCards': { 'AddOnCard': [ {'@AddOnCardIdx': card_idx, 'FCAdapter': { 'Ports': { 'Port': [ fc_port ] } }} ] } } @staticmethod def _create_json_slot_with_cna_fcoe(card_idx, port_idx, fcoe_function, lan_function=None): if not lan_function: lan_function = { 'FunctionEnable': False, 'BootProtocol': 'None', 'BootPriority': 1, } return { '@SlotIdx': 0, 'AddOnCards': { 'AddOnCard': [ {'@AddOnCardIdx': card_idx, 'CNAAdapter': { 'Ports': { 'Port': [ {'@PortIdx': port_idx, 'PortEnable': True, 'Functions': { 'Function': [ {'@FunctionIdx': 1, 'LANFunction': lan_function}, {'@FunctionIdx': 2, 'FCoEFunction': fcoe_function} ] }} ] } }} ] } } @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_lan_port_to_onboard(self, mock_set): self.configurator.set_lan_port('LAN0-1') port = { '@PortIdx': 1, 'PortEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, 'UseVirtualAddresses': False, } slot = VIOMConfigurationTestCase._create_json_slot_onbaord_lan(port) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_lan_port_to_onboard_with_virtual_mac(self, mock_set): self.configurator.set_lan_port('LAN0-9', mac='aa:bb:cc:dd:ee') port = { '@PortIdx': 9, 'PortEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, 'UseVirtualAddresses': True, 'VirtualAddress': { 'MAC': 'aa:bb:cc:dd:ee' } } slot = VIOMConfigurationTestCase._create_json_slot_onbaord_lan(port) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply(reboot=True) mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot, init_boot=True)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_lan_port_to_cna(self, mock_set): self.configurator.set_lan_port('CNA5-6') function = { 'FunctionEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, 'UseVirtualAddresses': False, } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_lan( 5, 6, function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_lan_port_to_cna_with_virtual_mac(self, mock_set): self.configurator.set_lan_port('CNA9-1', mac='12:34:56:78:90') function = { 'FunctionEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, 'UseVirtualAddresses': True, 'VirtualAddress': { 'MAC': '12:34:56:78:90' } } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_lan( 9, 1, function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_iscsi_volume_to_onboard_lan(self, mock_set): self.configurator.set_iscsi_volume( 'LAN0-9', 'iqn-2017-04.com.fujitsu:01', initiator_ip='192.168.11.11', initiator_netmask=24, target_iqn='iqn-2017-04.com.fujitsu:11', target_ip='192.168.22.22') port = { '@PortIdx': 9, 'PortEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 1, 'ISCSIBootEnvironment': { 'ISCSIInitiator': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:01', 'IPv4Address': '192.168.11.11', 'SubnetMask': '255.255.255.0', 'VLANId': 0, }, 'ISCSITarget': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:11', 'IPv4Address': '192.168.22.22', 'PortNumber': 3260, 'BootLUN': 0, 'AuthenticationMethod': 'None' } } } slot = VIOMConfigurationTestCase._create_json_slot_onbaord_lan(port) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_iscsi_volume_to_cna_card(self, mock_set): self.configurator.set_iscsi_volume( 'CNA1-2', 'iqn-2017-04.com.fujitsu:01', initiator_ip='192.168.11.11', initiator_netmask=16, target_iqn='iqn-2017-04.com.fujitsu:11', target_ip='192.168.22.22') iscsi_function = { 'FunctionEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 1, 'ISCSIBootEnvironment': { 'ISCSIInitiator': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:01', 'IPv4Address': '192.168.11.11', 'SubnetMask': '255.255.0.0', 'VLANId': 0, }, 'ISCSITarget': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:11', 'IPv4Address': '192.168.22.22', 'PortNumber': 3260, 'BootLUN': 0, 'AuthenticationMethod': 'None' } } } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi( 1, 2, iscsi_function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_iscsi_volume_to_cna_card_chap(self, mock_set): self.configurator.set_iscsi_volume( 'CNA9-9', 'iqn-2017-04.com.fujitsu:01', initiator_ip='192.168.11.11', initiator_netmask=30, target_iqn='iqn-2017-04.com.fujitsu:11', target_ip='192.168.22.22', chap_user='chap-user', chap_secret='chap-secret') iscsi_function = { 'FunctionEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 1, 'ISCSIBootEnvironment': { 'ISCSIInitiator': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:01', 'IPv4Address': '192.168.11.11', 'SubnetMask': '255.255.255.252', 'VLANId': 0, }, 'ISCSITarget': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:11', 'IPv4Address': '192.168.22.22', 'PortNumber': 3260, 'BootLUN': 0, 'AuthenticationMethod': 'CHAP', 'ChapUserName': 'chap-user', 'ChapSecret': 'chap-secret' } } } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi( 9, 9, iscsi_function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_iscsi_volume_to_cna_card_mutual_chap(self, mock_set): self.configurator.set_iscsi_volume( 'CNA2-1', 'iqn-2017-04.com.fujitsu:01', initiator_ip='192.168.11.11', initiator_netmask=8, target_iqn='iqn-2017-04.com.fujitsu:11', target_ip='192.168.22.22', boot_prio=2, target_lun=3, chap_user='chap-user', chap_secret='chap-secret', mutual_chap_secret='mutual-secret') iscsi_function = { 'FunctionEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 2, 'ISCSIBootEnvironment': { 'ISCSIInitiator': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:01', 'IPv4Address': '192.168.11.11', 'SubnetMask': '255.0.0.0', 'VLANId': 0, }, 'ISCSITarget': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:11', 'IPv4Address': '192.168.22.22', 'PortNumber': 3260, 'BootLUN': 3, 'AuthenticationMethod': 'MutualCHAP', 'ChapUserName': 'chap-user', 'ChapSecret': 'chap-secret', 'MutualChapSecret': 'mutual-secret', } } } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi( 2, 1, iscsi_function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_iscsi_volume_to_cna_card_initiator_dhcp(self, mock_set): self.configurator.set_iscsi_volume( 'CNA1-2', 'iqn-2017-04.com.fujitsu:01', initiator_dhcp=True, target_iqn='iqn-2017-04.com.fujitsu:11', target_ip='192.168.22.22') iscsi_function = { 'FunctionEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 1, 'ISCSIBootEnvironment': { 'ISCSIInitiator': { 'DHCPUsage': True, 'Name': 'iqn-2017-04.com.fujitsu:01', }, 'ISCSITarget': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:11', 'IPv4Address': '192.168.22.22', 'PortNumber': 3260, 'BootLUN': 0, 'AuthenticationMethod': 'None' } } } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi( 1, 2, iscsi_function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_iscsi_volume_to_cna_card_target_dhcp(self, mock_set): self.configurator.set_iscsi_volume( 'CNA1-2', 'iqn-2017-04.com.fujitsu:01', initiator_ip='192.168.11.11', initiator_netmask=16, target_dhcp=True) iscsi_function = { 'FunctionEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 1, 'ISCSIBootEnvironment': { 'ISCSIInitiator': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:01', 'IPv4Address': '192.168.11.11', 'SubnetMask': '255.255.0.0', 'VLANId': 0, }, 'ISCSITarget': { 'DHCPUsage': True, 'AuthenticationMethod': 'None' } } } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi( 1, 2, iscsi_function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_lan_and_iscsi_volume_to_cna_card(self, mock_set): self.configurator.set_lan_port('CNA1-2') self.configurator.set_iscsi_volume( 'CNA1-2', 'iqn-2017-04.com.fujitsu:01', initiator_ip='192.168.11.11', initiator_netmask=1, target_iqn='iqn-2017-04.com.fujitsu:11', target_ip='192.168.22.22') lan_function = { 'FunctionEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, 'UseVirtualAddresses': False, } iscsi_function = { 'FunctionEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 1, 'ISCSIBootEnvironment': { 'ISCSIInitiator': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:01', 'IPv4Address': '192.168.11.11', 'SubnetMask': '128.0.0.0', 'VLANId': 0, }, 'ISCSITarget': { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:11', 'IPv4Address': '192.168.22.22', 'PortNumber': 3260, 'BootLUN': 0, 'AuthenticationMethod': 'None' } } } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi( 1, 2, iscsi_function, lan_function=lan_function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_fc_volume_to_fc_card(self, mock_set): self.configurator.set_fc_volume('FC1-1', '11:22:33:44:55') port = { '@PortIdx': 1, 'UseVirtualAddresses': False, 'PortEnable': True, 'BootProtocol': 'FC', 'BootPriority': 1, 'FCBootEnvironment': { 'FCTargets': { 'FCTarget': [ {'@FCTargetIdx': 1, 'TargetWWPN': '11:22:33:44:55', 'TargetLUN': 0} ] }, 'FCLinkSpeed': 'auto', 'FCTopology': 'auto_loop', 'SANBootEnable': True, } } slot = VIOMConfigurationTestCase._create_json_slot_with_fc(1, port) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_fc_volume_to_fc_card_with_virtual_wwn(self, mock_set): self.configurator.set_fc_volume('FC2-1', '11:22:33:44:55', boot_prio=3, target_lun=2, initiator_wwnn='aa:bb:cc:dd:ee', initiator_wwpn='12:34:56:78:90') port = { '@PortIdx': 1, 'UseVirtualAddresses': True, 'VirtualAddress': { 'WWNN': 'aa:bb:cc:dd:ee', 'WWPN': '12:34:56:78:90' }, 'PortEnable': True, 'BootProtocol': 'FC', 'BootPriority': 3, 'FCBootEnvironment': { 'FCTargets': { 'FCTarget': [ {'@FCTargetIdx': 1, 'TargetWWPN': '11:22:33:44:55', 'TargetLUN': 2} ] }, 'FCLinkSpeed': 'auto', 'FCTopology': 'auto_loop', 'SANBootEnable': True, } } slot = VIOMConfigurationTestCase._create_json_slot_with_fc(2, port) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_fc_volume_to_cna_card(self, mock_set): self.configurator.set_fc_volume('CNA2-1', '11:22:33:44:55') fcoe_function = { 'UseVirtualAddresses': False, 'FunctionEnable': True, 'BootProtocol': 'FC', 'BootPriority': 1, 'FCBootEnvironment': { 'FCTargets': { 'FCTarget': [ {'@FCTargetIdx': 1, 'TargetWWPN': '11:22:33:44:55', 'TargetLUN': 0} ] }, 'FCLinkSpeed': 'auto', 'FCTopology': 'auto_loop', 'SANBootEnable': True, } } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_fcoe( 2, 1, fcoe_function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_fc_volume_to_cna_card_with_virtual_wwn(self, mock_set): self.configurator.set_fc_volume('CNA9-9', '11:22:33:44:55', boot_prio=2, target_lun=3, initiator_wwnn='aa:bb:cc:dd:ee', initiator_wwpn='12:34:56:78:90') fcoe_function = { 'UseVirtualAddresses': True, 'VirtualAddress': { 'WWNN': 'aa:bb:cc:dd:ee', 'WWPN': '12:34:56:78:90' }, 'FunctionEnable': True, 'BootProtocol': 'FC', 'BootPriority': 2, 'FCBootEnvironment': { 'FCTargets': { 'FCTarget': [ {'@FCTargetIdx': 1, 'TargetWWPN': '11:22:33:44:55', 'TargetLUN': 3} ] }, 'FCLinkSpeed': 'auto', 'FCTopology': 'auto_loop', 'SANBootEnable': True, } } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_fcoe( 9, 9, fcoe_function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) @mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile') def test_set_lan_and_fc_volume_to_cna_card(self, mock_set): self.configurator.set_lan_port('CNA2-1') self.configurator.set_fc_volume('CNA2-1', '11:22:33:44:55') lan_function = { 'FunctionEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, 'UseVirtualAddresses': False, } fcoe_function = { 'UseVirtualAddresses': False, 'FunctionEnable': True, 'BootProtocol': 'FC', 'BootPriority': 1, 'FCBootEnvironment': { 'FCTargets': { 'FCTarget': [ {'@FCTargetIdx': 1, 'TargetWWPN': '11:22:33:44:55', 'TargetLUN': 0} ] }, 'FCLinkSpeed': 'auto', 'FCTopology': 'auto_loop', 'SANBootEnable': True, } } slot = VIOMConfigurationTestCase._create_json_slot_with_cna_fcoe( 2, 1, fcoe_function, lan_function=lan_function) self.assertEqual( VIOMConfigurationTestCase._create_json_before_apply(slot), self.configurator.dump_json()) self.configurator.apply() mock_set.assert_called_once_with( VIOMConfigurationTestCase._create_json_for_apply(slot)) def test_set_lan_port_to_onboard_overwrite(self): self.configurator.set_lan_port('LAN0-9') self.test_set_lan_port_to_onboard_with_virtual_mac() def test_set_lan_port_to_cna_overwrite(self): self.configurator.set_lan_port('CNA5-6', mac='12:34:56:78:90') self.test_set_lan_port_to_cna() def test_set_iscsi_volume_to_onboard_lan_overwrite(self): self.configurator.set_iscsi_volume( 'LAN0-9', 'iqn-initiator', initiator_ip='192.168.99.99', initiator_netmask=32, target_iqn='iqn-target', target_ip='192.168.88.88') self.test_set_iscsi_volume_to_onboard_lan() def test_set_iscsi_volume_to_cna_card_overwrite(self): self.configurator.set_iscsi_volume( 'CNA1-2', 'iqn-initiator', initiator_ip='192.168.99.99', initiator_netmask=16, target_iqn='iqn-target', target_ip='192.168.88.88') self.test_set_iscsi_volume_to_cna_card() def test_set_fc_volume_to_fc_card_overwrite(self): self.configurator.set_fc_volume('FC2-1', '11:22:33:44:55') self.test_set_fc_volume_to_fc_card_with_virtual_wwn() def test_set_fc_volume_to_cna_card_overwrite(self): self.configurator.set_fc_volume('CNA2-1', '11:22:33:44:55', boot_prio=2, target_lun=3, initiator_wwnn='aa:bb:cc:dd:ee', initiator_wwpn='12:34:56:78:90') self.test_set_fc_volume_to_cna_card() class PhysicalPortIDParseTestCase(testtools.TestCase): def _validate_handler(self, handler, handler_class, slot_type, card_type, slot_idx, card_idx, port_idx): self.assertTrue(isinstance(handler, handler_class)) self.assertEqual(slot_type, handler.slot_type) self.assertEqual(card_type, handler.card_type) self.assertEqual(slot_idx, handler.slot_idx) self.assertEqual(card_idx, handler.card_idx) self.assertEqual(port_idx, handler.port_idx) def test_lan_onboard(self): handler = viom_client._parse_physical_port_id('LAN0-1') self._validate_handler(handler, viom_client._LANPortHandler, viom_client.ONBOARD, viom_client.LAN, 0, 1, 1) def test_lan_onboard_lower(self): handler = viom_client._parse_physical_port_id('lan0-2') self._validate_handler(handler, viom_client._LANPortHandler, viom_client.ONBOARD, viom_client.LAN, 0, 1, 2) def test_lan_onboard_cammel(self): handler = viom_client._parse_physical_port_id('Lan0-9') self._validate_handler(handler, viom_client._LANPortHandler, viom_client.ONBOARD, viom_client.LAN, 0, 1, 9) def test_lan_addon(self): handler = viom_client._parse_physical_port_id('LAN1-3') self._validate_handler(handler, viom_client._LANPortHandler, viom_client.ADDON, viom_client.LAN, 0, 1, 3) def test_fc_addon(self): handler = viom_client._parse_physical_port_id('FC2-5') self._validate_handler(handler, viom_client._FCPortHandler, viom_client.ADDON, viom_client.FC, 0, 2, 5) def test_cna_addon(self): handler = viom_client._parse_physical_port_id('CNA9-2') self._validate_handler(handler, viom_client._CNAPortHandler, viom_client.ADDON, viom_client.CNA, 0, 9, 2) def test_unkown_card(self): self.assertRaises(scci.SCCIInvalidInputError, viom_client._parse_physical_port_id, 'HCA1-1') def test_slot_out_of_range(self): self.assertRaises(scci.SCCIInvalidInputError, viom_client._parse_physical_port_id, 'CNA10-9') def test_port_out_of_range_min(self): self.assertRaises(scci.SCCIInvalidInputError, viom_client._parse_physical_port_id, 'FC0-0') def test_port_out_of_range_max(self): self.assertRaises(scci.SCCIInvalidInputError, viom_client._parse_physical_port_id, 'FC9-10') def test_public_validation(self): self.assertIsNone(viom_client.validate_physical_port_id('LAN0-2')) def test_public_validation_error(self): self.assertRaises(scci.SCCIInvalidInputError, viom_client.validate_physical_port_id, 'CNA1-0') class ConvertNetMaskTestCase(testtools.TestCase): def test_convert_zero(self): self.assertEqual('0.0.0.0', viom_client._convert_netmask(0)) def test_convert_max(self): self.assertEqual('255.255.255.255', viom_client._convert_netmask(32)) def test_convert_nagative(self): self.assertRaises(scci.SCCIInvalidInputError, viom_client._convert_netmask, -1) def test_convert_too_large(self): self.assertRaises(scci.SCCIInvalidInputError, viom_client._convert_netmask, 33) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/scciclient/tests/irmc/viom/test_elcm.py0000664000175000017500000013547200000000000025012 0ustar00zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Test class for iRMC eLCM functionality. """ import time from unittest import mock import testtools from scciclient.irmc import elcm from scciclient.irmc import scci from scciclient.irmc.viom import elcm as viom_elcm class ELCMVIOMClientTestCase(testtools.TestCase): """Test for ELCMViomClient.""" def setUp(self): super(ELCMVIOMClientTestCase, self).setUp() self.irmc_info = { 'irmc_address': '10.124.196.159', 'irmc_username': 'admin', 'irmc_password': 'admin0', 'irmc_port': 80, 'irmc_auth_method': 'basic', 'irmc_client_timeout': 60, } self.client = viom_elcm.ELCMVIOMClient(self.irmc_info) self.session_id = '10' @staticmethod def _session_status_resp(session_id, status): return {'Session': {'Id': session_id, 'Status': status}} @staticmethod def _session_log_resp(session_id): return {'Sessionlog': {'Id': session_id, 'Entries': {'Entry': {'@date': '2017/04/24 18:06:27', '#text': 'CreateSession: create'}}}} @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(time, 'sleep') def test__wait_session(self, mock_sleep, mock_get_session): mock_get_session.side_effect = [ self._session_status_resp(self.session_id, 'running'), self._session_status_resp(self.session_id, 'activated'), self._session_status_resp(self.session_id, 'terminated regularly')] self.assertEqual({}, self.client._wait_session(self.session_id)) mock_get_session.assert_has_calls( [mock.call(self.irmc_info, self.session_id) for i in range(0, 3)]) self.assertEqual(3, mock_get_session.call_count) self.assertEqual(2, mock_sleep.call_count) @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm, 'elcm_session_get_log') def test__wait_session_error(self, mock_get_log, mock_get_session): mock_get_session.return_value = ( self._session_status_resp(self.session_id, 'terminated with error')) mock_get_log.return_value = self._session_log_resp(self.session_id) self.assertRaises(scci.SCCIClientError, self.client._wait_session, self.session_id) mock_get_session.assert_called_once_with(self.irmc_info, self.session_id) mock_get_log.assert_called_once_with(irmc_info=self.irmc_info, session_id=self.session_id) @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm, 'elcm_session_get_log') def test__wait_session_error_log_error(self, mock_get_log, mock_get_session): mock_get_session.return_value = ( self._session_status_resp(self.session_id, 'terminated with error')) mock_get_log.side_effect = scci.SCCIClientError( 'got an error') self.assertRaises(scci.SCCIClientError, self.client._wait_session, self.session_id) mock_get_session.assert_called_once_with(self.irmc_info, self.session_id) mock_get_log.assert_called_once_with(irmc_info=self.irmc_info, session_id=self.session_id) @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm, 'elcm_session_get_log') @mock.patch.object(time, 'time') @mock.patch.object(time, 'sleep') def test__wait_session_timeout(self, mock_sleep, mock_time, mock_get_log, mock_get_session): timeout = 1800 mock_time.side_effect = [100, 101 + timeout] mock_get_session.return_value = ( self._session_status_resp(self.session_id, 'running')) mock_get_log.return_value = self._session_log_resp(self.session_id) self.assertRaises(elcm.ELCMSessionTimeout, self.client._wait_session, self.session_id) mock_get_session.assert_called_once_with(self.irmc_info, self.session_id) mock_get_log.assert_called_once_with(irmc_info=self.irmc_info, session_id=self.session_id) @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm, 'elcm_session_get_log') @mock.patch.object(time, 'time') @mock.patch.object(time, 'sleep') def test__wait_session_timeout_specified(self, mock_sleep, mock_time, mock_get_log, mock_get_session): timeout = 60 mock_time.side_effect = [100, 101 + timeout] mock_get_session.return_value = ( self._session_status_resp(self.session_id, 'running')) mock_get_log.return_value = self._session_log_resp(self.session_id) self.assertRaises(elcm.ELCMSessionTimeout, self.client._wait_session, self.session_id, timeout=timeout) mock_get_session.assert_called_once_with(self.irmc_info, self.session_id) mock_get_log.assert_called_once_with(irmc_info=self.irmc_info, session_id=self.session_id) @mock.patch.object(elcm, 'elcm_session_get_status') @mock.patch.object(elcm, 'elcm_session_get_log') @mock.patch.object(time, 'time') @mock.patch.object(time, 'sleep') def test__wait_session_timeout_log_error(self, mock_sleep, mock_time, mock_get_log, mock_get_session): timeout = 1800 mock_time.side_effect = [100, 101 + timeout] mock_get_session.return_value = ( self._session_status_resp(self.session_id, 'running')) mock_get_log.side_effect = scci.SCCIClientError('got an error') self.assertRaises(elcm.ELCMSessionTimeout, self.client._wait_session, self.session_id) mock_get_session.assert_called_once_with(self.irmc_info, self.session_id) mock_get_log.assert_called_once_with(irmc_info=self.irmc_info, session_id=self.session_id) @mock.patch.object(elcm, 'elcm_profile_set') @mock.patch.object(viom_elcm.ELCMVIOMClient, '_wait_session', return_value={}) def test_set_profile(self, mock_wait, mock_set): adapter_config = { 'ViomManage': {'Manage': True}, 'InitBoot': True} mock_set.return_value = self._session_status_resp(self.session_id, 'activated') self.assertIsNone(self.client.set_profile(adapter_config)) mock_wait.assert_called_once_with(self.session_id) mock_set.assert_called_once_with( self.irmc_info, {'Server': {'AdapterConfigIrmc': {'ViomManage': {'Manage': True}, 'InitBoot': True, '@Processing': 'execute'}, '@Version': '1.01'}}) @mock.patch.object(elcm, 'elcm_profile_create') @mock.patch.object(viom_elcm.ELCMVIOMClient, '_wait_session', return_value={}) @mock.patch.object(elcm, 'elcm_profile_get') def _test_get_profile(self, mock_get, mock_wait, mock_create): mock_create.return_value = self._session_status_resp(self.session_id, 'activated') adapter_data = { 'Server': { 'AdapterConfigIrmc': {'ViomManage': {'Manage': True}, 'InitBoot': True}}} mock_get.return_value = adapter_data self.assertEqual(adapter_data, self.client.get_profile()) mock_create.assert_called_once_with(self.irmc_info, 'Server/AdapterConfigIrmc') mock_wait.assert_called_once_with(self.session_id) mock_get.assert_called_once_with(self.irmc_info, 'AdapterConfigIrmc') @mock.patch.object(elcm, 'elcm_profile_delete') def test_get_profile_with_delete(self, mock_delete): self._test_get_profile() mock_delete.assert_called_once_with(self.irmc_info, 'AdapterConfigIrmc') @mock.patch.object(elcm, 'elcm_profile_delete') def test_get_profile_without_delete(self, mock_delete): mock_delete.side_effect = elcm.ELCMProfileNotFound('not found') self._test_get_profile() mock_delete.assert_called_once_with(self.irmc_info, 'AdapterConfigIrmc') class VIOMTableTestCase(testtools.TestCase): """Test for VIOM table.""" def setUp(self): super(VIOMTableTestCase, self).setUp() @staticmethod def _sample_manage_table(): return viom_elcm.ManageTable( manage=True, identification='identity', force=True) @staticmethod def _sample_manage_table_json(): return { 'Manage': True, 'Identification': 'identity', 'Force': True, } @staticmethod def _add_sample_cards_to_slot(slot): slot.add_card(VIOMTableTestCase._sample_onboard_card()) slot.add_card(VIOMTableTestCase._sample_addon_card()) @staticmethod def _sample_slot_json(): return { '@SlotIdx': 0, 'OnboardControllers': { 'OnboardController': [ VIOMTableTestCase._sample_onboard_card_json() ] }, 'AddOnCards': { 'AddOnCard': [ VIOMTableTestCase._sample_addon_card_json() ] } } @staticmethod def _sample_onboard_card(): onboard_card = viom_elcm.OnboardCard(1, viom_elcm.LANAdapter()) onboard_card.add_port(VIOMTableTestCase._sample_lan_port(1)) return onboard_card @staticmethod def _sample_onboard_card_json(): return { '@OnboardControllerIdx': 1, 'LANAdapter': { 'Ports': { 'Port': [ VIOMTableTestCase._sample_lan_port_json(1), ] } } } @staticmethod def _sample_addon_card(): addon_card = viom_elcm.AddOnCard(2, viom_elcm.FCAdapter()) addon_card.add_port(VIOMTableTestCase._sample_fc_port(1)) return addon_card @staticmethod def _sample_addon_card_json(): return { '@AddOnCardIdx': 2, 'FCAdapter': { 'Ports': { 'Port': [ VIOMTableTestCase._sample_fc_port_json(1), ] } } } @staticmethod def _sample_lan_port(port_id=1): return viom_elcm.LANPort(port_id) @staticmethod def _sample_lan_port_json(port_id=1): return { '@PortIdx': port_id, 'PortEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, } @staticmethod def _sample_fc_port(port_id=1): return viom_elcm.FCPort( port_id, boot=VIOMTableTestCase._sample_fc_boot()) @staticmethod def _sample_fc_port_json(port_id=1): sample = { '@PortIdx': port_id, 'PortEnable': True, 'BootProtocol': 'FC', 'BootPriority': 1, } sample.update( VIOMTableTestCase._sample_fc_boot_json()) return sample @staticmethod def _sample_cna_port(port_id=1): cna_port = viom_elcm.CNAPort(port_id) cna_port.add_function( VIOMTableTestCase._sample_lan_function()) cna_port.add_function( VIOMTableTestCase._sample_iscsi_function()) return cna_port @staticmethod def _sample_cna_port_json(port_id=1): return { '@PortIdx': port_id, 'PortEnable': True, 'Functions': { 'Function': [ VIOMTableTestCase._sample_lan_function_json(), VIOMTableTestCase._sample_iscsi_function_json() ] } } @staticmethod def _sample_lan_function(): return viom_elcm.LANFunction(1, function_enable=False) @staticmethod def _sample_lan_function_json(): return { '@FunctionIdx': 1, 'LANFunction': { 'FunctionEnable': False, 'BootProtocol': 'None', 'BootPriority': 1, } } @staticmethod def _sample_fcoe_function(): return viom_elcm.FCoEFunction( 2, boot=VIOMTableTestCase._sample_fc_boot()) @staticmethod def _sample_fcoe_function_json(): sample = { '@FunctionIdx': 2, 'FCoEFunction': { 'FunctionEnable': True, 'BootProtocol': 'FC', 'BootPriority': 1, }, } sample['FCoEFunction'].update( VIOMTableTestCase._sample_fc_boot_json()) return sample @staticmethod def _sample_iscsi_function(): return viom_elcm.ISCSIFunction( 3, boot=VIOMTableTestCase._sample_iscsi_boot()) @staticmethod def _sample_iscsi_function_json(): sample = { '@FunctionIdx': 3, 'ISCSIFunction': { 'FunctionEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 1, }, } sample['ISCSIFunction'].update( VIOMTableTestCase._sample_iscsi_boot_json()) return sample @staticmethod def _sample_fc_boot(boot_prio=None): if boot_prio: fc_boot = viom_elcm.FCBoot(boot_prio=boot_prio) else: fc_boot = viom_elcm.FCBoot() fc_boot.add_target(VIOMTableTestCase._sample_fc_target()) return fc_boot @staticmethod def _sample_fc_boot_json(): return { 'FCBootEnvironment': { 'FCTargets': { 'FCTarget': [VIOMTableTestCase._sample_fc_target_json()] }, 'FCLinkSpeed': 'auto', 'FCTopology': 'auto_loop', } } @staticmethod def _sample_fc_target(wwpn='11:22:33:44:55'): return viom_elcm.FCTarget(wwpn) @staticmethod def _sample_fc_target_json(target_idx=1, wwpn='11:22:33:44:55'): return {'@FCTargetIdx': target_idx, 'TargetWWPN': wwpn, 'TargetLUN': 0} @staticmethod def _sample_iscsi_boot(boot_prio=None): if boot_prio: return viom_elcm.ISCSIBoot( VIOMTableTestCase._sample_iscsi_initiator(), VIOMTableTestCase._sample_iscsi_target(), boot_prio=boot_prio) else: return viom_elcm.ISCSIBoot( VIOMTableTestCase._sample_iscsi_initiator(), VIOMTableTestCase._sample_iscsi_target()) @staticmethod def _sample_iscsi_boot_json(): return { 'ISCSIBootEnvironment': { 'ISCSIInitiator': VIOMTableTestCase._sample_iscsi_initiator_json(), 'ISCSITarget': VIOMTableTestCase._sample_iscsi_target_json() } } @staticmethod def _sample_iscsi_initiator(): return viom_elcm.ISCSIInitiator( iqn='iqn-2017-04.com.fujitsu:001', ip='192.168.1.11', subnet='255.255.255.0', gateway='192.168.1.1') @staticmethod def _sample_iscsi_initiator_json(): return { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:001', 'IPv4Address': '192.168.1.11', 'SubnetMask': '255.255.255.0', 'GatewayIPv4Address': '192.168.1.1', 'VLANId': 0, } @staticmethod def _sample_iscsi_target(): return viom_elcm.ISCSITarget( iqn='iqn-2017-04.com.fujitsu:101', ip='192.168.2.22', auth_method='CHAP', chap_user='chap_user', chap_secret='chap_secret') @staticmethod def _sample_iscsi_target_json(): return { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:101', 'IPv4Address': '192.168.2.22', 'PortNumber': 3260, 'BootLUN': 0, 'AuthenticationMethod': 'CHAP', 'ChapUserName': 'chap_user', 'ChapSecret': 'chap_secret', } def test_root(self): root = viom_elcm.VIOMTable( viom_boot_enable=True, init_boot=True, processing='execute', mode='new') root.set_manage_table(VIOMTableTestCase._sample_manage_table()) 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)) expected_json = { 'VIOMManage': VIOMTableTestCase._sample_manage_table_json(), 'InitBoot': True, 'VIOMBootEnable': True, '@Processing': 'execute', 'Mode': 'new', 'Slots': { 'Slot': [ VIOMTableTestCase._sample_slot_json() ] }, '@Version': '1.00', } self.assertEqual(expected_json, root.get_json()) def test_root_empty(self): root = viom_elcm.VIOMTable() self.assertEqual({'@Version': '1.00'}, root.get_json()) def test_root_detail(self): root = viom_elcm.VIOMTable( use_virtual_addresses=True, viom_boot_enable=True, boot_menu_enable=False, sriov=False, smux='None', init_boot=True, processing='execute', mode='modify') root.set_manage_table(VIOMTableTestCase._sample_manage_table()) VIOMTableTestCase._add_sample_cards_to_slot(root.get_slot(0)) expected_json = { 'VIOMManage': VIOMTableTestCase._sample_manage_table_json(), 'UseVirtualAddresses': True, 'VIOMBootEnable': True, 'BootMenuEnable': False, 'SRIOV': False, 'Smux': 'None', 'InitBoot': True, '@Processing': 'execute', 'Mode': 'modify', 'Slots': { 'Slot': [ VIOMTableTestCase._sample_slot_json() ] }, '@Version': '1.00', } self.assertEqual(expected_json, root.get_json()) def test_manage_table(self): manage_table = viom_elcm.ManageTable( manage=True, identification='identity', force=True) expected_json = { 'Manage': True, 'Identification': 'identity', 'Force': True, } self.assertEqual(expected_json, manage_table.get_json()) def test_manage_table_detail(self): manage_table = viom_elcm.ManageTable( manage=True, identification='identity', force=False, trap_destination='192.168.3.33', preferred_version='2.6') expected_json = { 'Manage': True, 'Identification': 'identity', 'Force': False, 'TrapDestination': '192.168.3.33', 'PreferredInventoryVersion': '2.6', } self.assertEqual(expected_json, manage_table.get_json()) def test_slot(self): slot = viom_elcm.Slot(0) onboard_card = VIOMTableTestCase._sample_onboard_card() slot.add_card(onboard_card) addon_card = VIOMTableTestCase._sample_addon_card() slot.add_card(addon_card) expected_json = { '@SlotIdx': 0, 'OnboardControllers': { 'OnboardController': [ VIOMTableTestCase._sample_onboard_card_json() ] }, 'AddOnCards': { 'AddOnCard': [ VIOMTableTestCase._sample_addon_card_json() ] } } self.assertEqual(expected_json, slot.get_json()) self.assertEqual(onboard_card, slot.get_onboard_card(1)) self.assertEqual(addon_card, slot.get_addon_card(2)) def test_slot_only_onboard(self): slot = viom_elcm.Slot(1) card = VIOMTableTestCase._sample_onboard_card() slot.add_card(card) expected_json = { '@SlotIdx': 1, 'OnboardControllers': { 'OnboardController': [ VIOMTableTestCase._sample_onboard_card_json() ] }, } self.assertEqual(expected_json, slot.get_json()) self.assertEqual(card, slot.get_onboard_card(1)) def test_slot_only_addon(self): slot = viom_elcm.Slot(2) card = VIOMTableTestCase._sample_addon_card() slot.add_card(card) expected_json = { '@SlotIdx': 2, 'AddOnCards': { 'AddOnCard': [ VIOMTableTestCase._sample_addon_card_json() ] } } self.assertEqual(expected_json, slot.get_json()) self.assertEqual(card, slot.get_addon_card(2)) def test_onboard_card(self): onboard_card = viom_elcm.OnboardCard(1, viom_elcm.LANAdapter()) port1 = VIOMTableTestCase._sample_lan_port(1) port2 = VIOMTableTestCase._sample_lan_port(2) onboard_card.add_port(port1) onboard_card.add_port(port2) expected_json = { '@OnboardControllerIdx': 1, 'LANAdapter': { 'Ports': { 'Port': [ VIOMTableTestCase._sample_lan_port_json(1), VIOMTableTestCase._sample_lan_port_json(2) ] } } } self.assertEqual(expected_json, onboard_card.get_json()) self.assertEqual(port1, onboard_card.get_port(1)) self.assertEqual(port2, onboard_card.get_port(2)) def test_addon_card(self): addon_card = viom_elcm.AddOnCard(2, viom_elcm.FCAdapter()) port1 = VIOMTableTestCase._sample_fc_port(1) port2 = VIOMTableTestCase._sample_fc_port(2) addon_card.add_port(port1) addon_card.add_port(port2) expected_json = { '@AddOnCardIdx': 2, 'FCAdapter': { 'Ports': { 'Port': [ VIOMTableTestCase._sample_fc_port_json(1), VIOMTableTestCase._sample_fc_port_json(2) ] } } } self.assertEqual(expected_json, addon_card.get_json()) self.assertEqual(port1, addon_card.get_port(1)) self.assertEqual(port2, addon_card.get_port(2)) def test_lan_adapter(self): lan_adapter = viom_elcm.LANAdapter() port1 = VIOMTableTestCase._sample_lan_port(1) port2 = VIOMTableTestCase._sample_lan_port(2) lan_adapter.add_port(port1) lan_adapter.add_port(port2) expected_json = { 'LANAdapter': { 'Ports': { 'Port': [ VIOMTableTestCase._sample_lan_port_json(1), VIOMTableTestCase._sample_lan_port_json(2) ] } } } self.assertEqual(expected_json, lan_adapter.get_json()) self.assertEqual(port1, lan_adapter.get_port(1)) self.assertEqual(port2, lan_adapter.get_port(2)) def test_fc_adapter(self): fc_adapter = viom_elcm.FCAdapter() port1 = VIOMTableTestCase._sample_fc_port(1) port2 = VIOMTableTestCase._sample_fc_port(2) fc_adapter.add_port(port1) fc_adapter.add_port(port2) expected_json = { 'FCAdapter': { 'Ports': { 'Port': [ VIOMTableTestCase._sample_fc_port_json(1), VIOMTableTestCase._sample_fc_port_json(2) ] } } } self.assertEqual(expected_json, fc_adapter.get_json()) self.assertEqual(port1, fc_adapter.get_port(1)) self.assertEqual(port2, fc_adapter.get_port(2)) def test_cna_adapter(self): cna_adapter = viom_elcm.CNAAdapter() port1 = VIOMTableTestCase._sample_cna_port(1) port2 = VIOMTableTestCase._sample_cna_port(2) cna_adapter.add_port(port1) cna_adapter.add_port(port2) expected_json = { 'CNAAdapter': { 'Ports': { 'Port': [ VIOMTableTestCase._sample_cna_port_json(1), VIOMTableTestCase._sample_cna_port_json(2) ] } } } self.assertEqual(expected_json, cna_adapter.get_json()) self.assertEqual(port1, cna_adapter.get_port(1)) self.assertEqual(port2, cna_adapter.get_port(2)) def test_lan_port(self): lan_port = viom_elcm.LANPort(1) expected_json = { '@PortIdx': 1, 'PortEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, } self.assertEqual(expected_json, lan_port.get_json()) def test_lan_port_pxe_boot(self): lan_port = viom_elcm.LANPort( 2, boot=viom_elcm.PXEBoot(boot_prio=3)) expected_json = { '@PortIdx': 2, 'PortEnable': True, 'BootProtocol': 'PXE', 'BootPriority': 3, } self.assertEqual(expected_json, lan_port.get_json()) def test_lan_port_virtualize_mac(self): lan_port = viom_elcm.LANPort( 3, use_virtual_addresses=True, mac='11:22:33:44:55') expected_json = { '@PortIdx': 3, 'PortEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, 'UseVirtualAddresses': True, 'VirtualAddress': { 'MAC': '11:22:33:44:55' } } self.assertEqual(expected_json, lan_port.get_json()) def test_lan_port_detail(self): lan_port = viom_elcm.LANPort(4, port_enable=False, sriov=True) expected_json = { '@PortIdx': 4, 'PortEnable': False, 'BootProtocol': 'None', 'BootPriority': 1, 'SRIOV': True, } self.assertEqual(expected_json, lan_port.get_json()) def test_fc_port(self): fc_port = viom_elcm.FCPort( 1, boot=VIOMTableTestCase._sample_fc_boot()) expected_json = { '@PortIdx': 1, 'PortEnable': True, 'BootProtocol': 'FC', 'BootPriority': 1, } expected_json.update( VIOMTableTestCase._sample_fc_boot_json()) self.assertEqual(expected_json, fc_port.get_json()) def test_fc_port_boot_priority(self): fc_port = viom_elcm.FCPort( 2, boot=VIOMTableTestCase._sample_fc_boot(boot_prio=3)) expected_json = { '@PortIdx': 2, 'PortEnable': True, 'BootProtocol': 'FC', 'BootPriority': 3, } expected_json.update( VIOMTableTestCase._sample_fc_boot_json()) self.assertEqual(expected_json, fc_port.get_json()) def test_fc_port_virtualize_wwn(self): fc_port = viom_elcm.FCPort( 3, boot=VIOMTableTestCase._sample_fc_boot(), use_virtual_addresses=True, wwnn='11:22:33:44:55', wwpn='66:77:88:99:00') expected_json = { '@PortIdx': 3, 'PortEnable': True, 'BootProtocol': 'FC', 'BootPriority': 1, 'UseVirtualAddresses': True, 'VirtualAddress': { 'WWNN': '11:22:33:44:55', 'WWPN': '66:77:88:99:00' }, } expected_json.update( VIOMTableTestCase._sample_fc_boot_json()) self.assertEqual(expected_json, fc_port.get_json()) def test_fc_port_detail(self): fc_port = viom_elcm.FCPort( 4, boot=VIOMTableTestCase._sample_fc_boot(), port_enable=False, sriov=True) expected_json = { '@PortIdx': 4, 'PortEnable': False, 'BootProtocol': 'FC', 'BootPriority': 1, 'SRIOV': True, } expected_json.update( VIOMTableTestCase._sample_fc_boot_json()) self.assertEqual(expected_json, fc_port.get_json()) def test_cna_port_fcoe(self): cna_port = viom_elcm.CNAPort(1) lan_function = VIOMTableTestCase._sample_lan_function() fcoe_function = VIOMTableTestCase._sample_fcoe_function() cna_port.add_function(lan_function) cna_port.add_function(fcoe_function) expected_json = { '@PortIdx': 1, 'PortEnable': True, 'Functions': { 'Function': [ VIOMTableTestCase._sample_lan_function_json(), VIOMTableTestCase._sample_fcoe_function_json() ] } } self.assertEqual(expected_json, cna_port.get_json()) self.assertEqual(lan_function, cna_port.get_function(1)) self.assertEqual(fcoe_function, cna_port.get_function(2)) def test_cna_port_iscsi(self): cna_port = viom_elcm.CNAPort(2) cna_port.add_function( VIOMTableTestCase._sample_lan_function()) cna_port.add_function( VIOMTableTestCase._sample_iscsi_function()) expected_json = { '@PortIdx': 2, 'PortEnable': True, 'Functions': { 'Function': [ VIOMTableTestCase._sample_lan_function_json(), VIOMTableTestCase._sample_iscsi_function_json() ] } } self.assertEqual(expected_json, cna_port.get_json()) def test_cna_port_disable(self): cna_port = viom_elcm.CNAPort(3, port_enable=False) cna_port.add_function( VIOMTableTestCase._sample_lan_function()) cna_port.add_function( VIOMTableTestCase._sample_iscsi_function()) expected_json = { '@PortIdx': 3, 'PortEnable': False, 'Functions': { 'Function': [ VIOMTableTestCase._sample_lan_function_json(), VIOMTableTestCase._sample_iscsi_function_json() ] } } self.assertEqual(expected_json, cna_port.get_json()) def test_lan_function(self): lan_function = viom_elcm.LANFunction(1) expected_json = { '@FunctionIdx': 1, 'LANFunction': { 'FunctionEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, } } self.assertEqual(expected_json, lan_function.get_json()) def test_lan_function_pxe_boot(self): lan_function = viom_elcm.LANFunction( 2, boot=viom_elcm.PXEBoot(boot_prio=3)) expected_json = { '@FunctionIdx': 2, 'LANFunction': { 'FunctionEnable': True, 'BootProtocol': 'PXE', 'BootPriority': 3, } } self.assertEqual(expected_json, lan_function.get_json()) def test_lan_function_virtualize_mac(self): lan_function = viom_elcm.LANFunction( 3, use_virtual_addresses=True, mac='11:22:33:44:55') expected_json = { '@FunctionIdx': 3, 'LANFunction': { 'FunctionEnable': True, 'BootProtocol': 'None', 'BootPriority': 1, 'UseVirtualAddresses': True, 'VirtualAddress': { 'MAC': '11:22:33:44:55' }, } } self.assertEqual(expected_json, lan_function.get_json()) def test_lan_function_detail(self): lan_function = viom_elcm.LANFunction( 4, function_enable=False, vlan_id=123, bandwidth=50, rate_limit=100, sriov=True) expected_json = { '@FunctionIdx': 4, 'LANFunction': { 'FunctionEnable': False, 'BootProtocol': 'None', 'BootPriority': 1, 'VLANId': 123, 'Bandwidth': 50, 'RateLimit': 100, 'SRIOV': True, } } self.assertEqual(expected_json, lan_function.get_json()) def test_fcoe_function(self): fcoe_function = viom_elcm.FCoEFunction( 1, boot=VIOMTableTestCase._sample_fc_boot()) expected_json = { '@FunctionIdx': 1, 'FCoEFunction': { 'FunctionEnable': True, 'BootProtocol': 'FC', 'BootPriority': 1, }, } expected_json['FCoEFunction'].update( VIOMTableTestCase._sample_fc_boot_json()) self.assertEqual(expected_json, fcoe_function.get_json()) def test_fcoe_function_boot_priority(self): fcoe_function = viom_elcm.FCoEFunction( 2, boot=VIOMTableTestCase._sample_fc_boot(boot_prio=3)) expected_json = { '@FunctionIdx': 2, 'FCoEFunction': { 'FunctionEnable': True, 'BootProtocol': 'FC', 'BootPriority': 3, }, } expected_json['FCoEFunction'].update( VIOMTableTestCase._sample_fc_boot_json()) self.assertEqual(expected_json, fcoe_function.get_json()) def test_fcoe_function_virtualize_wwn(self): fcoe_function = viom_elcm.FCoEFunction( 3, boot=VIOMTableTestCase._sample_fc_boot(), use_virtual_addresses=True, wwnn='11:22:33:44:55', wwpn='66:77:88:99:00') expected_json = { '@FunctionIdx': 3, 'FCoEFunction': { 'FunctionEnable': True, 'BootProtocol': 'FC', 'BootPriority': 1, 'UseVirtualAddresses': True, 'VirtualAddress': { 'WWNN': '11:22:33:44:55', 'WWPN': '66:77:88:99:00' }, }, } expected_json['FCoEFunction'].update( VIOMTableTestCase._sample_fc_boot_json()) self.assertEqual(expected_json, fcoe_function.get_json()) def test_fcoe_function_virtualize_mac(self): fcoe_function = viom_elcm.FCoEFunction( 4, boot=VIOMTableTestCase._sample_fc_boot(), use_virtual_addresses=True, mac='aa:bb:cc:dd:ee') expected_json = { '@FunctionIdx': 4, 'FCoEFunction': { 'FunctionEnable': True, 'BootProtocol': 'FC', 'BootPriority': 1, 'UseVirtualAddresses': True, 'VirtualAddress': { 'MAC': 'aa:bb:cc:dd:ee' }, }, } expected_json['FCoEFunction'].update( VIOMTableTestCase._sample_fc_boot_json()) self.assertEqual(expected_json, fcoe_function.get_json()) def test_fcoe_function_detail(self): fcoe_function = viom_elcm.FCoEFunction( 5, boot=VIOMTableTestCase._sample_fc_boot(), function_enable=False, vlan_id=123, bandwidth=50, rate_limit=100, sriov=True) expected_json = { '@FunctionIdx': 5, 'FCoEFunction': { 'FunctionEnable': False, 'BootProtocol': 'FC', 'BootPriority': 1, 'VLANId': 123, 'Bandwidth': 50, 'RateLimit': 100, 'SRIOV': True, }, } expected_json['FCoEFunction'].update( VIOMTableTestCase._sample_fc_boot_json()) self.assertEqual(expected_json, fcoe_function.get_json()) def test_iscsi_function(self): iscsi_function = viom_elcm.ISCSIFunction( 1, boot=VIOMTableTestCase._sample_iscsi_boot()) expected_json = { '@FunctionIdx': 1, 'ISCSIFunction': { 'FunctionEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 1, }, } expected_json['ISCSIFunction'].update( VIOMTableTestCase._sample_iscsi_boot_json()) self.assertEqual(expected_json, iscsi_function.get_json()) def test_iscsi_function_boot_priority(self): iscsi_function = viom_elcm.ISCSIFunction( 2, boot=VIOMTableTestCase._sample_iscsi_boot(boot_prio=3)) expected_json = { '@FunctionIdx': 2, 'ISCSIFunction': { 'FunctionEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 3, }, } expected_json['ISCSIFunction'].update( VIOMTableTestCase._sample_iscsi_boot_json()) self.assertEqual(expected_json, iscsi_function.get_json()) def test_iscsi_functon_virtulaize_mac(self): iscsi_function = viom_elcm.ISCSIFunction( 3, boot=VIOMTableTestCase._sample_iscsi_boot(), use_virtual_addresses=True, mac='12:34:56:78:90') expected_json = { '@FunctionIdx': 3, 'ISCSIFunction': { 'FunctionEnable': True, 'BootProtocol': 'ISCSI', 'BootPriority': 1, 'UseVirtualAddresses': True, 'VirtualAddress': { 'MAC': '12:34:56:78:90' }, }, } expected_json['ISCSIFunction'].update( VIOMTableTestCase._sample_iscsi_boot_json()) self.assertEqual(expected_json, iscsi_function.get_json()) def test_iscsi_functon_detail(self): iscsi_function = viom_elcm.ISCSIFunction( 4, boot=VIOMTableTestCase._sample_iscsi_boot(), function_enable=False, vlan_id=123, bandwidth=50, rate_limit=100, sriov=True) expected_json = { '@FunctionIdx': 4, 'ISCSIFunction': { 'FunctionEnable': False, 'BootProtocol': 'ISCSI', 'BootPriority': 1, 'VLANId': 123, 'Bandwidth': 50, 'RateLimit': 100, 'SRIOV': True, }, } expected_json['ISCSIFunction'].update( VIOMTableTestCase._sample_iscsi_boot_json()) self.assertEqual(expected_json, iscsi_function.get_json()) def test_none_boot(self): none_boot = viom_elcm.NoneBoot() self.assertEqual({}, none_boot.get_json()) def test_pxe_boot(self): pxe_boot = viom_elcm.PXEBoot() self.assertEqual({}, pxe_boot.get_json()) def test_fc_boot(self): fc_boot = viom_elcm.FCBoot() fc_boot.add_target(VIOMTableTestCase._sample_fc_target()) expected_json = { 'FCBootEnvironment': { 'FCTargets': { 'FCTarget': [VIOMTableTestCase._sample_fc_target_json()] }, 'FCLinkSpeed': 'auto', 'FCTopology': 'auto_loop', } } self.assertEqual(expected_json, fc_boot.get_json()) def test_fc_boot_detail(self): fc_boot = viom_elcm.FCBoot( link_speed='auto', topology='auto_PtP', boot_enable=False) fc_boot.add_target(VIOMTableTestCase._sample_fc_target()) expected_json = { 'FCBootEnvironment': { 'FCTargets': { 'FCTarget': [VIOMTableTestCase._sample_fc_target_json()] }, 'FCLinkSpeed': 'auto', 'FCTopology': 'auto_PtP', 'SANBootEnable': False, } } self.assertEqual(expected_json, fc_boot.get_json()) def test_fc_boot_mulit_targets(self): fc_boot = viom_elcm.FCBoot() fc_boot.add_target(VIOMTableTestCase._sample_fc_target()) fc_boot.add_target( VIOMTableTestCase._sample_fc_target('aa:bb:cc:dd:ee:ff')) expected_json = { 'FCBootEnvironment': { 'FCTargets': { 'FCTarget': [ VIOMTableTestCase._sample_fc_target_json(), VIOMTableTestCase._sample_fc_target_json( target_idx=2, wwpn='aa:bb:cc:dd:ee:ff') ] }, 'FCLinkSpeed': 'auto', 'FCTopology': 'auto_loop', } } self.assertEqual(expected_json, fc_boot.get_json()) def test_fc_target(self): fc_target = viom_elcm.FCTarget('11:22:33:44:55') expected_json = { '@FCTargetIdx': 1, 'TargetWWPN': '11:22:33:44:55', 'TargetLUN': 0, } self.assertEqual(expected_json, fc_target.get_json()) def test_fc_target_lun(self): fc_target = viom_elcm.FCTarget('11:22:33:44:55', lun=1) expected_json = { '@FCTargetIdx': 1, 'TargetWWPN': '11:22:33:44:55', 'TargetLUN': 1, } self.assertEqual(expected_json, fc_target.get_json()) def test_iscsi_boot(self): iscsi_boot = viom_elcm.ISCSIBoot( VIOMTableTestCase._sample_iscsi_initiator(), VIOMTableTestCase._sample_iscsi_target()) expected_json = { 'ISCSIBootEnvironment': { 'ISCSIInitiator': VIOMTableTestCase._sample_iscsi_initiator_json(), 'ISCSITarget': VIOMTableTestCase._sample_iscsi_target_json() } } self.assertEqual(expected_json, iscsi_boot.get_json()) def test_iscsi_initiator(self): iscsi_initiator = viom_elcm.ISCSIInitiator( iqn='iqn-2017-04.com.fujitsu:001', 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', 'IPv4Address': '192.168.1.11', 'SubnetMask': '255.255.255.0', 'GatewayIPv4Address': '192.168.1.1', 'VLANId': 0, } self.assertEqual(expected_json, iscsi_initiator.get_json()) def test_iscsi_initiator_vlan(self): iscsi_initiator = viom_elcm.ISCSIInitiator( iqn='iqn-2017-04.com.fujitsu:001', ip='192.168.1.11', subnet='255.255.255.0', gateway='192.168.1.1', vlan_id=123 ) expected_json = { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:001', 'IPv4Address': '192.168.1.11', 'SubnetMask': '255.255.255.0', 'GatewayIPv4Address': '192.168.1.1', 'VLANId': 123, } self.assertEqual(expected_json, iscsi_initiator.get_json()) def test_iscsi_initiator_dhcp(self): iscsi_initiator = viom_elcm.ISCSIInitiator( dhcp_usage=True, 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', } self.assertEqual(expected_json, iscsi_initiator.get_json()) def test_iscsi_target_no_auth(self): iscsi_target = viom_elcm.ISCSITarget( iqn='iqn-2017-04.com.fujitsu:101', ip='192.168.2.22') expected_json = { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:101', 'IPv4Address': '192.168.2.22', 'PortNumber': 3260, 'BootLUN': 0, 'AuthenticationMethod': 'None', } self.assertEqual(expected_json, iscsi_target.get_json()) def test_iscsi_target_chap(self): iscsi_target = viom_elcm.ISCSITarget( iqn='iqn-2017-04.com.fujitsu:101', ip='192.168.2.22', port=12345, lun=3, auth_method='CHAP', chap_user='chap_user', chap_secret='chap_secret') expected_json = { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:101', 'IPv4Address': '192.168.2.22', 'PortNumber': 12345, 'BootLUN': 3, 'AuthenticationMethod': 'CHAP', 'ChapUserName': 'chap_user', 'ChapSecret': 'chap_secret', } self.assertEqual(expected_json, iscsi_target.get_json()) def test_iscsi_target_mutualchap(self): iscsi_target = viom_elcm.ISCSITarget( iqn='iqn-2017-04.com.fujitsu:101', ip='192.168.2.22', auth_method='MutualCHAP', chap_user='chap_user', chap_secret='chap_secret', mutual_chap_secret='chap_secret_second') expected_json = { 'DHCPUsage': False, 'Name': 'iqn-2017-04.com.fujitsu:101', 'IPv4Address': '192.168.2.22', 'PortNumber': 3260, 'BootLUN': 0, 'AuthenticationMethod': 'MutualCHAP', 'ChapUserName': 'chap_user', 'ChapSecret': 'chap_secret', 'MutualChapSecret': 'chap_secret_second', } self.assertEqual(expected_json, iscsi_target.get_json()) def test_iscsi_target_dhcp(self): iscsi_target = viom_elcm.ISCSITarget( dhcp_usage=True, iqn='iqn-2017-04.com.fujitsu:101', ip='192.168.2.22', auth_method='CHAP', chap_user='chap_user', chap_secret='chap_secret') expected_json = { 'DHCPUsage': True, 'AuthenticationMethod': 'CHAP', 'ChapUserName': 'chap_user', 'ChapSecret': 'chap_secret', } self.assertEqual(expected_json, iscsi_target.get_json()) ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1692971673.122654 python-scciclient-0.15.0/setup.cfg0000664000175000017500000000220600000000000017100 0ustar00zuulzuul00000000000000[metadata] name = python-scciclient summary = Python ServerView Common Command Interface (SCCI) Client Library description-file = README.rst author = FUJITSU LIMITED 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 [build_sphinx] source-dir = doc/source build-dir = doc/build all_files = 1 [upload_sphinx] upload-dir = doc/build/html [compile_catalog] directory = scciclient/locale domain = python-scciclient [update_catalog] domain = python-scciclient output_dir = scciclient/locale input_file = scciclient/locale/python-scciclient.pot [extract_messages] keywords = _ gettext ngettext l_ lazy_gettext mapping_file = babel.cfg output_file = scciclient/locale/python-scciclient.pot [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/setup.py0000664000175000017500000000200600000000000016767 0ustar00zuulzuul00000000000000# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT import setuptools # In python < 2.7.4, a lazy loading of package `pbr` will break # setuptools if some other modules registered functions in `atexit`. # solution from: http://bugs.python.org/issue15881#msg170215 try: import multiprocessing # noqa except ImportError: pass setuptools.setup( setup_requires=['pbr>=2.0.0'], pbr=True) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/test-requirements.txt0000664000175000017500000000074200000000000021523 0ustar00zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. coverage!=4.4,>=4.0 # Apache-2.0 fixtures>=3.0.0 # Apache-2.0/BSD python-subunit>=1.0.0 # Apache-2.0/BSD oslotest>=3.2.0 # 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1692971646.0 python-scciclient-0.15.0/tox.ini0000664000175000017500000000303700000000000016575 0ustar00zuulzuul00000000000000[tox] minversion = 3.9.0 envlist = py3,pep8 skipsdist = True ignore_basepython_conflict=true [testenv] usedevelop = True install_command = pip install {opts} {packages} deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = stestr run --slowest {posargs} [testenv:pep8] 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 scciclient --parallel-mode commands = stestr run {posargs} coverage combine coverage html -d cover coverage xml -o cover/coverage.xml coverage report [testenv:docs] basepython = python3 deps = -r{toxinidir}/requirements.txt -r{toxinidir}/doc/requirements.txt commands = sphinx-build -b html doc/source doc/build/html [flake8] ignore = W503,W504,W605 show-source = True builtins = _ exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build # [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