python-scciclient-0.8.0/0000775000175000017500000000000013342004351015173 5ustar zuulzuul00000000000000python-scciclient-0.8.0/babel.cfg0000666000175000017500000000002113342004045016714 0ustar zuulzuul00000000000000[python: **.py] python-scciclient-0.8.0/.coveragerc0000666000175000017500000000017013342004045017314 0ustar zuulzuul00000000000000[run] branch = True source = scciclient omit = scciclient/tests/*,scciclient/openstack/* [report] ignore_errors = True python-scciclient-0.8.0/LICENSE0000666000175000017500000002363713342004045016215 0ustar zuulzuul00000000000000 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. python-scciclient-0.8.0/requirements.txt0000666000175000017500000000067613342004045020472 0ustar zuulzuul00000000000000# 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.22 # Apache-2.0 pysnmp>=4.2.3 # BSD requests>=2.14.2 # Apache-2.0 six>=1.10.0 # MIT oslo.utils>=3.33.0 # Apache-2.0 oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 python-scciclient-0.8.0/.stestr.conf0000666000175000017500000000006213342004045017444 0ustar zuulzuul00000000000000[DEFAULT] test_path=./scciclient/tests top_dir=./ python-scciclient-0.8.0/CONTRIBUTING.rst0000666000175000017500000000104613342004045017637 0ustar zuulzuul00000000000000If 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 python-scciclient-0.8.0/setup.py0000666000175000017500000000200613342004045016705 0ustar zuulzuul00000000000000# 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) python-scciclient-0.8.0/README.rst0000666000175000017500000000047713342004045016674 0ustar zuulzuul00000000000000=============================== 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 - integrated Remote Management Controller python-scciclient-0.8.0/HACKING.rst0000666000175000017500000000024713342004045016776 0ustar zuulzuul00000000000000python-scciclient Style Commandments =============================================== Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ python-scciclient-0.8.0/tox.ini0000666000175000017500000000212113342004045016504 0ustar zuulzuul00000000000000[tox] minversion = 2.0 envlist = py35,py34,py27,pep8 skipsdist = True [testenv] usedevelop = True install_command = pip install {opts} {packages} deps = -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = stestr run --slowest {posargs} [testenv:pep8] commands = flake8 [testenv:venv] commands = {posargs} [testenv:cover] setenv = PYTHON=coverage run --source $project --parallel-mode commands = stestr run '{posargs}' coverage combine coverage html -d cover coverage xml -o cover/coverage.xml coverage report [testenv:docs] commands = python setup.py build_sphinx [flake8] # E123, E125 skipped as they are invalid PEP-8. show-source = True ignore = E123,E125 builtins = _ exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build [testenv:lower-constraints] basepython = python3 deps = -c{toxinidir}/lower-constraints.txt -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt python-scciclient-0.8.0/openstack-common.conf0000666000175000017500000000021113342004045021313 0ustar zuulzuul00000000000000[DEFAULT] # The list of modules to copy from oslo-incubator.git # The base module to hold the copy of openstack.common base=scciclient python-scciclient-0.8.0/test-requirements.txt0000666000175000017500000000114713342004045021441 0ustar zuulzuul00000000000000# 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. hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0 fixtures>=3.0.0 # Apache-2.0/BSD mock>=2.0.0 # BSD python-subunit>=1.0.0 # Apache-2.0/BSD oslotest>=3.2.0 # Apache-2.0 stestr>=2.0.0 # Apache-2.0 testscenarios>=0.4 # Apache-2.0/BSD testtools>=2.2.0 # MIT requests-mock>=1.2.0 # Apache-2.0 # Doc requirements sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD oslosphinx>=4.7.0 # Apache-2.0 python-scciclient-0.8.0/python_scciclient.egg-info/0000775000175000017500000000000013342004351022406 5ustar zuulzuul00000000000000python-scciclient-0.8.0/python_scciclient.egg-info/SOURCES.txt0000664000175000017500000000245513342004351024300 0ustar zuulzuul00000000000000.coveragerc .mailmap .stestr.conf .zuul.yaml AUTHORS CONTRIBUTING.rst ChangeLog HACKING.rst LICENSE MANIFEST.in README.rst babel.cfg lower-constraints.txt openstack-common.conf requirements.txt setup.cfg setup.py test-requirements.txt tox.ini 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.pypython-scciclient-0.8.0/python_scciclient.egg-info/top_level.txt0000664000175000017500000000001313342004350025131 0ustar zuulzuul00000000000000scciclient python-scciclient-0.8.0/python_scciclient.egg-info/dependency_links.txt0000664000175000017500000000000113342004350026453 0ustar zuulzuul00000000000000 python-scciclient-0.8.0/python_scciclient.egg-info/pbr.json0000664000175000017500000000005613342004350024064 0ustar zuulzuul00000000000000{"git_version": "d8f1f1c", "is_release": true}python-scciclient-0.8.0/python_scciclient.egg-info/requires.txt0000664000175000017500000000023113342004350025001 0ustar zuulzuul00000000000000pbr!=2.1.0,>=2.0.0 Babel!=2.4.0,>=2.3.4 pyghmi>=1.0.22 pysnmp>=4.2.3 requests>=2.14.2 six>=1.10.0 oslo.utils>=3.33.0 oslo.serialization!=2.19.1,>=2.18.0 python-scciclient-0.8.0/python_scciclient.egg-info/not-zip-safe0000664000175000017500000000000113342004335024636 0ustar zuulzuul00000000000000 python-scciclient-0.8.0/python_scciclient.egg-info/PKG-INFO0000664000175000017500000000244413342004350023506 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: python-scciclient Version: 0.8.0 Summary: Python ServerView Common Command Interface (SCCI) Client Library Home-page: https://github.com/openstack/python-scciclient Author: FUJITSU LIMITED Author-email: lsoft-dev@ml.css.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 - 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 :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 python-scciclient-0.8.0/AUTHORS0000664000175000017500000000141713342004350016245 0ustar zuulzuul00000000000000Andreas Jaeger Dao Cong Tien Doug Hellmann Hironori Shiina Jamie Lennox Janonymous Luong Anh Tuan Naohiro Tamura Ngo Quoc Cuong Nguyen Hung Phuong Nguyen Van Trung Swapnil Kulkarni (coolsvap) Thomas Goirand Tony Breeds Vu Cong Tuan Yushiro FURUKAWA Zuul ricolin shangxiaobj shu-mutou python-scciclient-0.8.0/lower-constraints.txt0000666000175000017500000000167013342004045021437 0ustar zuulzuul00000000000000alabaster==0.7.10 appdirs==1.3.0 Babel==2.3.4 coverage==4.0 debtcollector==1.2.0 docutils==0.11 extras==1.0.0 fixtures==3.0.0 flake8==2.5.5 hacking==0.12.0 imagesize==0.7.1 iso8601==0.1.11 Jinja2==2.10 keystoneauth1==3.4.0 linecache2==1.0.0 MarkupSafe==1.0 mccabe==0.2.1 mock==2.0.0 monotonic==0.6 mox3==0.20.0 msgpack-python==0.4.0 netaddr==0.7.18 netifaces==0.10.4 os-client-config==1.28.0 oslo.i18n==3.15.3 oslo.serialization==2.18.0 oslo.utils==3.33.0 oslosphinx==4.7.0 oslotest==3.2.0 pbr==2.0.0 pep8==1.5.7 pyasn1==0.1.8 pycrypto==2.6 pyflakes==0.8.1 pyghmi==1.0.22 Pygments==2.2.0 pyparsing==2.1.0 pysnmp==4.2.3 python-mimeparse==1.6.0 python-subunit==1.0.0 pytz==2013.6 PyYAML==3.12 requests-mock==1.2.0 requests==2.14.2 requestsexceptions==1.2.0 six==1.10.0 snowballstemmer==1.2.1 Sphinx==1.6.2 sphinxcontrib-websupport==1.0.1 stevedore==1.20.0 stestr==2.0.0 testscenarios==0.4 testtools==2.2.0 traceback2==1.4.0 unittest2==1.1.0 wrapt==1.7.0 python-scciclient-0.8.0/PKG-INFO0000664000175000017500000000244413342004351016274 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: python-scciclient Version: 0.8.0 Summary: Python ServerView Common Command Interface (SCCI) Client Library Home-page: https://github.com/openstack/python-scciclient Author: FUJITSU LIMITED Author-email: lsoft-dev@ml.css.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 - 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 :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 python-scciclient-0.8.0/.mailmap0000666000175000017500000000013113342004045016611 0ustar zuulzuul00000000000000# Format is: # # python-scciclient-0.8.0/.zuul.yaml0000666000175000017500000000021413342004045017133 0ustar zuulzuul00000000000000- project: check: jobs: - openstack-tox-lower-constraints gate: jobs: - openstack-tox-lower-constraints python-scciclient-0.8.0/setup.cfg0000666000175000017500000000236713342004351017026 0ustar zuulzuul00000000000000[metadata] name = python-scciclient summary = Python ServerView Common Command Interface (SCCI) Client Library description-file = README.rst author = FUJITSU LIMITED author-email = lsoft-dev@ml.css.fujitsu.com home-page = https://github.com/openstack/python-scciclient classifier = Development Status :: 4 - Beta Environment :: Console Environment :: OpenStack Intended Audience :: Information Technology Intended Audience :: System Administrators License :: OSI Approved :: Apache Software License Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.4 [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 python-scciclient-0.8.0/ChangeLog0000664000175000017500000000701313342004350016745 0ustar zuulzuul00000000000000CHANGES ======= 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 python-scciclient-0.8.0/scciclient/0000775000175000017500000000000013342004351017313 5ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/__init__.py0000666000175000017500000000124113342004045021424 0ustar zuulzuul00000000000000# -*- 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() python-scciclient-0.8.0/scciclient/tests/0000775000175000017500000000000013342004351020455 5ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/tests/__init__.py0000666000175000017500000000000013342004045022556 0ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/tests/irmc/0000775000175000017500000000000013342004351021407 5ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/tests/irmc/test_snmp.py0000666000175000017500000003414113342004045024002 0ustar zuulzuul00000000000000# # 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. """ import mock from pysnmp.entity.rfc3413.oneliner import cmdgen from pysnmp import error as snmp_error 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)) @mock.patch.object(cmdgen, 'CommandGenerator', autospec=True) 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' def test___init__(self, mock_cmdgen): client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1) mock_cmdgen.assert_called_once_with() self.assertEqual(self.address, client.address) self.assertEqual(self.port, client.port) self.assertEqual(snmp.SNMP_V1, client.version) self.assertIsNone(client.community) self.assertNotIn('security', client.__dict__) self.assertEqual(mock_cmdgen.return_value, client.cmd_gen) def test_get(self, mock_cmdgen): var_bind = (self.oid, self.value) mock_cmdgenerator = mock_cmdgen.return_value mock_cmdgenerator.getCmd.return_value = ("", None, 0, [var_bind]) client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) val = client.get(self.oid) self.assertEqual(var_bind[1], val) mock_cmdgenerator.getCmd.assert_called_once_with(mock.ANY, mock.ANY, self.oid) @mock.patch.object(cmdgen, 'CommunityData', autospec=True) def test__get_auth_v1(self, mock_community, mock_cmdgen): client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V1) client._get_auth() mock_cmdgen.assert_called_once_with() mock_community.assert_called_once_with(client.community, mpModel=0) @mock.patch.object(cmdgen, 'CommunityData', autospec=True) def test__get_auth_v2c(self, mock_community, mock_cmdgen): client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V2C) client._get_auth() mock_cmdgen.assert_called_once_with() mock_community.assert_called_once_with(client.community, mpModel=1) @mock.patch.object(cmdgen, 'UsmUserData', autospec=True) def test__get_auth_v3(self, mock_user, mock_cmdgen): client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) client._get_auth() mock_cmdgen.assert_called_once_with() mock_user.assert_called_once_with(client.security) @mock.patch.object(cmdgen, 'UdpTransportTarget', autospec=True) def test__get_transport(self, mock_transport, mock_cmdgen): client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) client._get_transport() mock_cmdgen.assert_called_once_with() mock_transport.assert_called_once_with((client.address, client.port)) @mock.patch.object(cmdgen, 'UdpTransportTarget', autospec=True) def test__get_transport_err(self, mock_transport, mock_cmdgen): mock_transport.side_effect = snmp_error.PySnmpError() client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp_error.PySnmpError, client._get_transport) mock_cmdgen.assert_called_once_with() mock_transport.assert_called_once_with((client.address, client.port)) def test_get_pdu_err(self, mock_cmdgen): var_bind = (self.oid, self.value) error_status = mock.Mock() error_status.prettyPrint = lambda: "pdu error" mock_cmdgenerator = mock_cmdgen.return_value mock_cmdgenerator.getCmd.return_value = (None, error_status, 1, [var_bind]) client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp.SNMPFailure, client.get, self.oid) mock_cmdgenerator.getCmd.assert_called_once_with(mock.ANY, mock.ANY, self.oid) def test_get_next(self, mock_cmdgen): var_bind = (self.oid, self.value) mock_cmdgenerator = mock_cmdgen.return_value mock_cmdgenerator.nextCmd.return_value = ( "", None, 0, [[var_bind, var_bind]]) client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) val = client.get_next(self.oid) self.assertEqual([self.value, self.value], val) mock_cmdgenerator.nextCmd.assert_called_once_with(mock.ANY, mock.ANY, self.oid) @mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True) def test_get_err_transport(self, mock_transport, mock_cmdgen): mock_transport.side_effect = snmp_error.PySnmpError mock_cmdgenerator = mock_cmdgen.return_value client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp.SNMPFailure, client.get, self.oid) self.assertFalse(mock_cmdgenerator.getCmd.called) @mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True) def test_get_next_err_transport(self, mock_transport, mock_cmdgen): mock_transport.side_effect = snmp_error.PySnmpError mock_cmdgenerator = mock_cmdgen.return_value client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp.SNMPFailure, client.get_next, self.oid) self.assertFalse(mock_cmdgenerator.nextCmd.called) def test_get_err_engine(self, mock_cmdgen): var_bind = (self.oid, self.value) mock_cmdgenerator = mock_cmdgen.return_value mock_cmdgenerator.getCmd.return_value = ("engine error", None, 0, [var_bind]) client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp.SNMPFailure, client.get, self.oid) mock_cmdgenerator.getCmd.assert_called_once_with(mock.ANY, mock.ANY, self.oid) def test_get_next_err_engine(self, mock_cmdgen): var_bind = (self.oid, self.value) mock_cmdgenerator = mock_cmdgen.return_value mock_cmdgenerator.nextCmd.return_value = ("engine error", None, 0, [[var_bind, var_bind]]) client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp.SNMPFailure, client.get_next, self.oid) mock_cmdgenerator.nextCmd.assert_called_once_with(mock.ANY, mock.ANY, self.oid) def test_get_next_pdu_err(self, mock_cmdgen): var_bind = (self.oid, self.value) error_status = mock.Mock() error_status.prettyPrint = lambda: "pdu error" mock_cmdgenerator = mock_cmdgen.return_value mock_cmdgenerator.nextCmd.return_value = (None, error_status, 1, [var_bind]) client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp.SNMPFailure, client.get_next, self.oid) mock_cmdgenerator.nextCmd.assert_called_once_with(mock.ANY, mock.ANY, self.oid) def test_set(self, mock_cmdgen): var_bind = (self.oid, self.value) mock_cmdgenerator = mock_cmdgen.return_value mock_cmdgenerator.setCmd.return_value = ("", None, 0, [var_bind]) client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) client.set(self.oid, self.value) mock_cmdgenerator.setCmd.assert_called_once_with(mock.ANY, mock.ANY, var_bind) @mock.patch.object(snmp.SNMPClient, '_get_transport', autospec=True) def test_set_err_transport(self, mock_transport, mock_cmdgen): mock_transport.side_effect = snmp_error.PySnmpError mock_cmdgenerator = mock_cmdgen.return_value client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp.SNMPFailure, client.set, self.oid, self.value) self.assertFalse(mock_cmdgenerator.setCmd.called) def test_set_err_engine(self, mock_cmdgen): var_bind = (self.oid, self.value) mock_cmdgenerator = mock_cmdgen.return_value mock_cmdgenerator.setCmd.return_value = ("engine error", None, 0, [var_bind]) client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp.SNMPFailure, client.set, self.oid, self.value) mock_cmdgenerator.setCmd.assert_called_once_with(mock.ANY, mock.ANY, var_bind) def test_set_pdu_err(self, mock_cmdgen): var_bind = (self.oid, self.value) error_status = mock.Mock() error_status.prettyPrint = lambda: "pdu error" mock_cmdgenerator = mock_cmdgen.return_value mock_cmdgenerator.setCmd.return_value = (None, error_status, 1, [var_bind]) client = snmp.SNMPClient(self.address, self.port, snmp.SNMP_V3) self.assertRaises(snmp.SNMPFailure, client.set, self.oid, self.value) mock_cmdgenerator.setCmd.assert_called_once_with(mock.ANY, mock.ANY, var_bind) python-scciclient-0.8.0/scciclient/tests/irmc/__init__.py0000666000175000017500000000000013342004045023510 0ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/tests/irmc/test_ipmi.py0000666000175000017500000001337313342004045023767 0ustar zuulzuul00000000000000# # 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. """ import mock import testtools from pyghmi import exceptions as ipmi_exception from pyghmi.ipmi import command as ipmi_command 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)) python-scciclient-0.8.0/scciclient/tests/irmc/test_elcm.py0000666000175000017500000027766313342004045023767 0ustar zuulzuul00000000000000# 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. """ 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(1, 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(1, 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(2, mock_sleep.call_count) self.assertEqual(True, mock_session_get.called) self.assertEqual(1, mock_session_delete.call_count) self.assertEqual(2, mock_profile_get.call_count) self.assertEqual(1, mock_profile_create.call_count) self.assertEqual(2, mock_profile_delete.call_count) @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(1, mock_profile_get.call_count) self.assertEqual(1, mock_profile_set.call_count) self.assertEqual(2, 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_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': 'slow', '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': 'slow', 'Size': { '@Unit': 'GB', '#text': 100 }, }, { '@Number': 1, '@Action': 'Create', 'RaidLevel': '1', 'InitMode': 'slow', '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': 'slow', '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': 'slow', 'Size': { '@Unit': 'GB', '#text': 100 }, 'ArrayRefs': { 'ArrayRef': [ { '@Number': 0 } ] } }, { '@Number': 1, '@Action': 'Create', 'RaidLevel': '1', 'InitMode': 'slow', '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': 'slow', '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': 'slow' } ] } } ] }, '@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': 'slow', 'Size': { '@Unit': 'GB', '#text': 100 }, }, { '@Number': 1, '@Action': 'Create', 'RaidLevel': '1', 'InitMode': 'slow', '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': 'slow', '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': 'slow', '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': 'slow', '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.assertItemsEqual(expect_settings, result) backup_bios_config_mock.assert_called_once_with( self.irmc_info) python-scciclient-0.8.0/scciclient/tests/irmc/fixtures/0000775000175000017500000000000013342004351023260 5ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/tests/irmc/fixtures/irmc_report_ng.xml0000666000175000017500000007406413342004045027030 0ustar zuulzuul00000000000000 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 python-scciclient-0.8.0/scciclient/tests/irmc/fixtures/irmc_report_ok.xml0000666000175000017500000013570013342004045027030 0ustar zuulzuul00000000000000 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 python-scciclient-0.8.0/scciclient/tests/irmc/viom/0000775000175000017500000000000013342004351022361 5ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/tests/irmc/viom/test_client.py0000666000175000017500000010354113342004045025256 0ustar zuulzuul00000000000000# 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 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) python-scciclient-0.8.0/scciclient/tests/irmc/viom/__init__.py0000666000175000017500000000000013342004045024462 0ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/tests/irmc/viom/test_elcm.py0000666000175000017500000013547513342004045024733 0ustar zuulzuul00000000000000# 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 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.assertEqual(None, 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()) python-scciclient-0.8.0/scciclient/tests/irmc/test_scci.py0000666000175000017500000012102113342004045023740 0ustar zuulzuul00000000000000# # 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 import xml.etree.ElementTree as ET import mock from requests_mock.contrib import fixture as rm_fixture import testtools from scciclient.irmc import ipmi from scciclient.irmc import scci from scciclient.irmc import snmp 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 = ET.fromstring(self.report_ok_txt) with open(os.path.join( os.path.dirname(__file__), 'fixtures/irmc_report_ng.xml'), "r") as report_ng: self.report_ng_txt = report_ng.read() self.report_ng_xml = ET.fromstring(self.report_ng_txt) self.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)) def test_power_on_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_ON) self.assertEqual(r.status_code, 200) def test_power_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_OFF) self.assertEqual(r.status_code, 200) 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) def test_power_reset_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_RESET) self.assertEqual(r.status_code, 200) 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.assertEqual(sensor, None) 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.assertEqual(version, None) 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 """) 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) python-scciclient-0.8.0/scciclient/irmc/0000775000175000017500000000000013342004351020245 5ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/irmc/ipmi.py0000777000175000017500000001263113342004045021565 0ustar zuulzuul00000000000000# 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'], password=d_info['irmc_password']) 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'], password=d_info['irmc_password']) 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 python-scciclient-0.8.0/scciclient/irmc/scci.py0000777000175000017500000005075713342004045021563 0ustar zuulzuul00000000000000# 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 time import xml.etree.ElementTree as ET import requests import six from scciclient.irmc import ipmi from scciclient.irmc import snmp DEBUG = False 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) """ List of iRMC S4 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 ) 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, **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 :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'} r = requests.post(protocol + '://' + host + '/config', data=cmd, headers=header, verify=False, timeout=client_timeout, allow_redirects=False, auth=auth_obj) if not do_async: time.sleep(5) 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 ET.ParseError as parse_error: raise SCCIClientError(parse_error) except requests.exceptions.RequestException as requests_exception: raise SCCIClientError(requests_exception) def get_client(host, userid, password, port=443, auth_method='basic', client_timeout=60, **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 :returns: scci_cmd partial function which takes a SCCI command param """ return functools.partial(scci_cmd, host, userid, password, port=port, auth_method=auth_method, client_timeout=client_timeout, **kwargs) 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): """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 :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=False, 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") # ET.dump(sensor[0]) 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") # ET.dump(version[0]) return version 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(d_info['irmc_address'], d_info['irmc_snmp_port'], d_info['irmc_snmp_version'], d_info['irmc_snmp_community'], d_info['irmc_snmp_security']) 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 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 python-scciclient-0.8.0/scciclient/irmc/__init__.py0000666000175000017500000000117313342004045022362 0ustar zuulzuul00000000000000# 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 python-scciclient-0.8.0/scciclient/irmc/snmp.py0000666000175000017500000002201513342004045021576 0ustar zuulzuul00000000000000# 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 six from pysnmp.entity.rfc3413.oneliner import cmdgen from pysnmp import error as snmp_error BMC_NAME_OID = '1.3.6.1.4.1.231.2.10.2.2.10.3.4.1.3.1.1' IRMC_FW_VERSION_OID = '1.3.6.1.4.1.231.2.10.2.2.10.3.4.1.4.1.1' 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, community=None, security=None): self.address = address self.port = port self.version = version if self.version == SNMP_V3: self.security = security else: self.community = community self.cmd_gen = cmdgen.CommandGenerator() def _get_auth(self): """Return the authorization data for an SNMP request. :returns: A :class:`pysnmp.entity.rfc3413.oneliner.cmdgen.CommunityData` object. """ if self.version == SNMP_V3: # Handling auth/encryption credentials is not (yet) supported. # This version supports a security name analogous to community. return cmdgen.UsmUserData(self.security) else: mp_model = 1 if self.version == SNMP_V2C else 0 return cmdgen.CommunityData(self.community, mpModel=mp_model) def _get_transport(self): """Return the transport target for an SNMP request. :returns: A :class: `pysnmp.entity.rfc3413.oneliner.cmdgen.UdpTransportTarget` object. :raises: snmp_error.PySnmpError if the transport address is bad. """ # The transport target accepts timeout and retries parameters, which # default to 1 (second) and 5 respectively. These are deemed sensible # enough to allow for an unreliable network or slow device. return cmdgen.UdpTransportTarget((self.address, self.port)) 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: results = self.cmd_gen.getCmd(self._get_auth(), self._get_transport(), oid) except snmp_error.PySnmpError as e: raise SNMPFailure(SNMP_FAILURE_MSG % ("GET", e)) error_indication, error_status, error_index, var_binds = results 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: results = self.cmd_gen.nextCmd(self._get_auth(), self._get_transport(), oid) except snmp_error.PySnmpError as e: raise SNMPFailure(SNMP_FAILURE_MSG % ("GET_NEXT", e)) error_indication, error_status, error_index, var_binds = results 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 '?'}) return [val for row in var_binds for name, val in row] 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: results = self.cmd_gen.setCmd(self._get_auth(), self._get_transport(), (oid, value)) except snmp_error.PySnmpError as e: raise SNMPFailure(SNMP_FAILURE_MSG % ("SET", e)) error_indication, error_status, error_index, var_binds = results 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 '?'}) python-scciclient-0.8.0/scciclient/irmc/viom/0000775000175000017500000000000013342004351021217 5ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/irmc/viom/client.py0000666000175000017500000003753013342004045023061 0ustar zuulzuul00000000000000# 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 six import socket import struct 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) python-scciclient-0.8.0/scciclient/irmc/viom/__init__.py0000666000175000017500000000000013342004045023320 0ustar zuulzuul00000000000000python-scciclient-0.8.0/scciclient/irmc/viom/elcm.py0000666000175000017500000006723713342004045022532 0ustar zuulzuul00000000000000# 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 python-scciclient-0.8.0/scciclient/irmc/elcm.py0000666000175000017500000012021413342004045021541 0ustar zuulzuul00000000000000# 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 six import time from oslo_serialization import jsonutils import requests 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, ... } :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) # 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=False, 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 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': } """ # 1. Make sure there is no BiosConfig profile in the store try: # Get the profile first, if not found, then an exception # will be raised. elcm_profile_get(irmc_info=irmc_info, profile_name=PROFILE_BIOS_CONFIG) # 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 # 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) 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() # 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': 'slow'}) 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": "slow" } 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]['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 python-scciclient-0.8.0/doc/0000775000175000017500000000000013342004351015740 5ustar zuulzuul00000000000000python-scciclient-0.8.0/doc/source/0000775000175000017500000000000013342004351017240 5ustar zuulzuul00000000000000python-scciclient-0.8.0/doc/source/conf.py0000777000175000017500000000464113342004045020551 0ustar zuulzuul00000000000000# -*- 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', #'sphinx.ext.intersphinx', 'oslosphinx' ] # 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'] # 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} python-scciclient-0.8.0/doc/source/index.rst0000666000175000017500000000100513342004045021077 0ustar zuulzuul00000000000000.. 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` python-scciclient-0.8.0/doc/source/usage.rst0000666000175000017500000000013013342004045021072 0ustar zuulzuul00000000000000======== Usage ======== To use python-scciclient in a project:: import scciclient python-scciclient-0.8.0/doc/source/contributing.rst0000666000175000017500000000011313342004045022476 0ustar zuulzuul00000000000000============ Contributing ============ .. include:: ../../CONTRIBUTING.rst python-scciclient-0.8.0/doc/source/readme.rst0000666000175000017500000000003613342004045021230 0ustar zuulzuul00000000000000.. include:: ../../README.rst python-scciclient-0.8.0/doc/source/installation.rst0000666000175000017500000000033413342004045022475 0ustar zuulzuul00000000000000============ Installation ============ At the command line:: $ pip install python-scciclient Or, if you have virtualenvwrapper installed:: $ mkvirtualenv python-scciclient $ pip install python-scciclient python-scciclient-0.8.0/MANIFEST.in0000666000175000017500000000013613342004045016733 0ustar zuulzuul00000000000000include AUTHORS include ChangeLog exclude .gitignore exclude .gitreview global-exclude *.pyc