diff --git a/.zuul.yaml b/.zuul.yaml index b1e8dfddb2..c86da4d099 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -15,8 +15,6 @@ - controllerconfig-tox-flake8 - controllerconfig-tox-py27 - controllerconfig-tox-pylint - - configutilities-tox-flake8 - - configutilities-tox-pylint - cgtsclient-tox-py27 - cgtsclient-tox-pep8 - cgtsclient-tox-pylint @@ -35,8 +33,6 @@ - controllerconfig-tox-flake8 - controllerconfig-tox-py27 - controllerconfig-tox-pylint - - configutilities-tox-flake8 - - configutilities-tox-pylint - cgtsclient-tox-py27 - cgtsclient-tox-pep8 - cgtsclient-tox-pylint @@ -142,28 +138,6 @@ tox_envlist: pylint tox_extra_args: -c controllerconfig/controllerconfig/tox.ini -- job: - name: configutilities-tox-flake8 - parent: tox - description: Run flake8 tests for configutilities - files: - - configutilities/* - vars: - tox_envlist: flake8 - tox_extra_args: -c configutilities/configutilities/tox.ini - -- job: - name: configutilities-tox-pylint - parent: tox - description: Run pylint tests for configutilities - required-projects: - - openstack/stx-update - files: - - configutilities/* - vars: - tox_envlist: pylint - tox_extra_args: -c configutilities/configutilities/tox.ini - - job: name: flock-devstack-config parent: flock-devstack-base diff --git a/centos_iso_image.inc b/centos_iso_image.inc index cbf86b0f48..dcbd2a2b6a 100644 --- a/centos_iso_image.inc +++ b/centos_iso_image.inc @@ -10,9 +10,6 @@ workerconfig workerconfig-standalone workerconfig-subfunction -# configutilities -configutilities - # controllerconfig controllerconfig diff --git a/centos_pike_wheels.inc b/centos_pike_wheels.inc index e3e0c0b29c..e5bc269940 100644 --- a/centos_pike_wheels.inc +++ b/centos_pike_wheels.inc @@ -1,4 +1,3 @@ cgts-client-wheels -configutilities-wheels controllerconfig-wheels sysinv-wheels diff --git a/centos_pkg_dirs b/centos_pkg_dirs index 58b9cf7978..20467f16b3 100644 --- a/centos_pkg_dirs +++ b/centos_pkg_dirs @@ -1,7 +1,6 @@ kubernetes/applications/stx-openstack/stx-openstack-helm worker-utils workerconfig -configutilities controllerconfig storageconfig sysinv/cgts-client diff --git a/centos_stable_wheels.inc b/centos_stable_wheels.inc index e3e0c0b29c..e5bc269940 100644 --- a/centos_stable_wheels.inc +++ b/centos_stable_wheels.inc @@ -1,4 +1,3 @@ cgts-client-wheels -configutilities-wheels controllerconfig-wheels sysinv-wheels diff --git a/configutilities/.gitignore b/configutilities/.gitignore deleted file mode 100644 index ad7061c2ea..0000000000 --- a/configutilities/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -!.distro -.distro/centos7/rpmbuild/RPMS -.distro/centos7/rpmbuild/SRPMS -.distro/centos7/rpmbuild/BUILD -.distro/centos7/rpmbuild/BUILDROOT -.distro/centos7/rpmbuild/SOURCES/configutilities*tar.gz diff --git a/configutilities/PKG-INFO b/configutilities/PKG-INFO deleted file mode 100755 index 04153f1838..0000000000 --- a/configutilities/PKG-INFO +++ /dev/null @@ -1,13 +0,0 @@ -Metadata-Version: 1.1 -Name: configutilities -Version: 1.2.0 -Summary: Titanium Cloud configuration utilities -Home-page: -Author: Windriver -Author-email: info@windriver.com -License: Apache-2.0 - -Description: Titanium Cloud configuration utilities - - -Platform: UNKNOWN diff --git a/configutilities/centos/build_srpm.data b/configutilities/centos/build_srpm.data deleted file mode 100755 index 262bcfec5b..0000000000 --- a/configutilities/centos/build_srpm.data +++ /dev/null @@ -1,3 +0,0 @@ -SRC_DIR="configutilities" -COPY_LIST="$SRC_DIR/LICENSE" -TIS_PATCH_VER=2 diff --git a/configutilities/centos/configutilities.spec b/configutilities/centos/configutilities.spec deleted file mode 100755 index 3a7269af3d..0000000000 --- a/configutilities/centos/configutilities.spec +++ /dev/null @@ -1,78 +0,0 @@ -Summary: configutilities -Name: configutilities -Version: 3.1.0 -Release: %{tis_patch_ver}%{?_tis_dist} -License: Apache-2.0 -Group: base -Packager: Wind River -URL: unknown -Source0: %{name}-%{version}.tar.gz -Source1: LICENSE - -%define debug_package %{nil} - -BuildRequires: python-setuptools -BuildRequires: python2-pip -BuildRequires: python2-wheel -Requires: python-netaddr -#Requires: wxPython - -%description -Titanium Cloud Controller configuration utilities - -%package -n %{name}-cgts-sdk -Summary: configutilities sdk files -Group: devel - -%description -n %{name}-cgts-sdk -SDK files for configutilities - -%define local_bindir /usr/bin -%define pythonroot /usr/lib64/python2.7/site-packages -%define cgcs_sdk_deploy_dir /opt/deploy/cgcs_sdk -%define cgcs_sdk_tarball_name wrs-%{name}-%{version}.tgz - -%prep -%setup - -%build -%{__python} setup.py build -%py2_build_wheel - -%install -%{__python} setup.py install --root=$RPM_BUILD_ROOT \ - --install-lib=%{pythonroot} \ - --prefix=/usr \ - --install-data=/usr/share \ - --single-version-externally-managed -mkdir -p $RPM_BUILD_ROOT/wheels -install -m 644 dist/*.whl $RPM_BUILD_ROOT/wheels/ - -sed -i "s#xxxSW_VERSIONxxx#%{platform_release}#" %{name}/common/validator.py -tar czf %{cgcs_sdk_tarball_name} %{name} -mkdir -p $RPM_BUILD_ROOT%{cgcs_sdk_deploy_dir} -install -m 644 %{cgcs_sdk_tarball_name} $RPM_BUILD_ROOT%{cgcs_sdk_deploy_dir} - -%clean -rm -rf $RPM_BUILD_ROOT - -%files -%defattr(-,root,root,-) -%doc LICENSE -%{local_bindir}/* -%dir %{pythonroot}/%{name} -%{pythonroot}/%{name}/* -%dir %{pythonroot}/%{name}-%{version}-py2.7.egg-info -%{pythonroot}/%{name}-%{version}-py2.7.egg-info/* - -%files -n %{name}-cgts-sdk -%{cgcs_sdk_deploy_dir}/%{cgcs_sdk_tarball_name} - -%package wheels -Summary: %{name} wheels - -%description wheels -Contains python wheels for %{name} - -%files wheels -/wheels/* diff --git a/configutilities/configutilities/LICENSE b/configutilities/configutilities/LICENSE deleted file mode 100755 index d645695673..0000000000 --- a/configutilities/configutilities/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - 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. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/configutilities/configutilities/configutilities/LICENSE b/configutilities/configutilities/configutilities/LICENSE deleted file mode 100755 index d645695673..0000000000 --- a/configutilities/configutilities/configutilities/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - 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. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/configutilities/configutilities/configutilities/README b/configutilities/configutilities/configutilities/README deleted file mode 100755 index 4d36291e0b..0000000000 --- a/configutilities/configutilities/configutilities/README +++ /dev/null @@ -1,76 +0,0 @@ -Copyright © 2017 Wind River Systems, Inc. - -SPDX-License-Identifier: Apache-2.0 ------------------------------------------------------------------------ - - -Titanium Cloud Configuration Utilities ---------------------------------------- - -To facilitate various aspects of Titanium Cloud installation and -configuration, utilities have been created to generate and validate -configuration and setup files which are utilized by the system. - - -Installing the Configuration Utilities --------------------------------------- - -This tarball includes several utilities which can be used to aid in the -configuration of Titanium Cloud. Note that these are optional tools which are run prior -to installation, and not run on the target system. - -To install the utilities on a Linux machine follow these steps: - -1. Ensure you have the tools necessary to install new python packages (pip and setuptools) - If you do not, you must install them using the appropriate commands for - your version of linux, such as: - sudo apt-get install python-pip # e.g. for Ubuntu or Debian - -2. The config_gui tool makes use of external tools which must be - installed as follows: - - if using Ubuntu/Debian: - sudo apt-get install python-wxtools - - if using Fedora: - sudo yum install wxPython python-setuptools - - if using CentOS/RedHat, the appropriate rpm can be obtained from EPEL - sudo yum install epel-release - sudo yum install wxPython - - Note, if epel-release is not available, it can be obtained as such (specific to - your version) - wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm - sudo rpm -Uvh epel-release-6*.rpm - sudo yum install wxPython python-pip - -3. Copy wrs-configutilities-3.1.0.tgz to the python install directory - (i.e. /usr/lib/python2.7/dist-packages or /usr/lib/python2.7/site-packages) - -4. Cd to this python install directory - -5. Untar the file: - sudo tar xfv wrs-configutilities-3.1.0.tgz - -6. Cd configutilities - -7. Run setup: - sudo python setup.py install - - -Using the Configuration Utilities ---------------------------------- - -There are two tools installed: config_validator and config_gui. - -config_validator is a commandline tool which takes a 'controller configuration -input' file of the INI type and does preliminary analysis to ensure its validity. -It can be called as follows: - config_validator --system-config - -config_gui is a GUI-based tool which provides tools for creating a 'controller -configuration input' INI file and/or a 'bulk host' XML file. It can be launched -by calling 'config_gui' from the command line and will walk you through the process -of generating the desired configuration files. - diff --git a/configutilities/configutilities/configutilities/__init__.py b/configutilities/configutilities/configutilities/__init__.py deleted file mode 100755 index a694fc1a6c..0000000000 --- a/configutilities/configutilities/configutilities/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2015-2016 Wind River Systems, Inc. -# -# SPDX-License-Identifier: Apache-2.0 -# -# - -from configutilities.common.validator import validate # noqa: F401 -from configutilities.common.configobjects import Network # noqa: F401 -from configutilities.common.configobjects import DEFAULT_CONFIG # noqa: F401 -from configutilities.common.configobjects import REGION_CONFIG # noqa: F401 -from configutilities.common.configobjects import DEFAULT_NAMES # noqa: F401 -from configutilities.common.configobjects import HP_NAMES # noqa: F401 -from configutilities.common.configobjects import SUBCLOUD_CONFIG # noqa: F401 -from configutilities.common.configobjects import MGMT_TYPE # noqa: F401 -from configutilities.common.configobjects import INFRA_TYPE # noqa: F401 -from configutilities.common.configobjects import OAM_TYPE # noqa: F401 -from configutilities.common.configobjects import NETWORK_PREFIX_NAMES # noqa: F401 -from configutilities.common.configobjects import HOST_XML_ATTRIBUTES # noqa: F401 -from configutilities.common.configobjects import DEFAULT_DOMAIN_NAME # noqa: F401 -from configutilities.common.exceptions import ConfigError # noqa: F401 -from configutilities.common.exceptions import ConfigFail # noqa: F401 -from configutilities.common.exceptions import ValidateFail # noqa: F401 -from configutilities.common.utils import is_valid_vlan # noqa: F401 -from configutilities.common.utils import is_mtu_valid # noqa: F401 -from configutilities.common.utils import validate_network_str # noqa: F401 -from configutilities.common.utils import validate_address_str # noqa: F401 -from configutilities.common.utils import validate_address # noqa: F401 -from configutilities.common.utils import is_valid_url # noqa: F401 -from configutilities.common.utils import is_valid_domain_or_ip # noqa: F401 -from configutilities.common.utils import ip_version_to_string # noqa: F401 -from configutilities.common.utils import lag_mode_to_str # noqa: F401 -from configutilities.common.utils import validate_openstack_password # noqa: F401 -from configutilities.common.utils import validate_nameserver_address_str # noqa: F401 -from configutilities.common.utils import extract_openstack_password_rules_from_file # noqa: F401 diff --git a/configutilities/configutilities/configutilities/common/__init__.py b/configutilities/configutilities/configutilities/common/__init__.py deleted file mode 100644 index 1d58fc700e..0000000000 --- a/configutilities/configutilities/configutilities/common/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# -# Copyright (c) 2015 Wind River Systems, Inc. -# -# SPDX-License-Identifier: Apache-2.0 -# diff --git a/configutilities/configutilities/configutilities/common/exceptions.py b/configutilities/configutilities/configutilities/common/exceptions.py deleted file mode 100644 index 24e27264e4..0000000000 --- a/configutilities/configutilities/configutilities/common/exceptions.py +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright (c) 2015 Wind River Systems, Inc. -# -# SPDX-License-Identifier: Apache-2.0 -# - - -class ConfigError(Exception): - """Base class for configuration exceptions.""" - - def __init__(self, message=None): - self.message = message - - def __str__(self): - return self.message or "" - - -class ConfigFail(ConfigError): - """General configuration error.""" - pass - - -class ValidateFail(ConfigError): - """Validation of data failed.""" - pass diff --git a/configutilities/configutilities/configutilities/common/guicomponents.py b/configutilities/configutilities/configutilities/common/guicomponents.py deleted file mode 100755 index 443b677155..0000000000 --- a/configutilities/configutilities/configutilities/common/guicomponents.py +++ /dev/null @@ -1,295 +0,0 @@ -# -# Copyright (c) 2016 Wind River Systems, Inc. -# -# SPDX-License-Identifier: Apache-2.0 -# - -import wx - -from configutilities.common.exceptions import ValidateFail -from configutilities.common import wrs_ico - -TEXT_BOX_SIZE = (150, -1) -TEXT_WIDTH = 450 -DEBUG = False -VGAP = 5 -HGAP = 10 - - -def debug(msg): - if DEBUG: - print(msg) - - -# Tracks what type of controls will implement a config question -class TYPES(object): - string = 1 - int = 2 - radio = 3 - choice = 4 - checkbox = 5 - help = 6 - separator = 7 - - -class Field(object): - def __init__(self, text="", type=TYPES.string, transient=False, - initial="", choices=[], shows=[], reverse=False, - enabled=True): - """Represent a configuration question - - :param text: Question prompt text - - :param type: The type of wxWidgets control(s) used to implement this - field - - :param transient: Whether this field should be written automatically - to the INI file - - :param enabled: Whether this field should be enabled or - disabled (greyed-out) - - :param initial: Initial value used to populate the control - - :param choices: A string list of choices to populate selection-based - fields - - :param shows: A list of field key strings that this field should show - when checked. Only checkboxes implement this functionality atm - - :param reverse: Switches the 'shows' logic -> checked - will hide fields instead of showing them - - :return: the Field object - """ - - self.text = text - self.type = type - self.transient = transient - self.initial = initial - self.choices = choices - self.shows = shows - self.reverse = reverse - self.enabled = enabled - - # Controls used to implement this field - self.prompt = None - self.input = None - - if type is TYPES.help: - self.transient = True - - # Sanity to make sure fields are being utilized correctly - if self.shows and self.type is TYPES.help: - raise NotImplementedError() - - if not self.shows and self.reverse: - raise NotImplementedError() - - def get_value(self): - # Return value of the control (a string or int) - if not self.input: - value = None - elif not self.input.IsShown() or not self.input.IsEnabled(): - value = None - elif self.type is TYPES.string: - value = self.input.GetLineText(0) - elif self.type is TYPES.int: - try: - value = self.input.GetLineText(0) - int(value) - except ValueError: - raise ValidateFail( - "Invalid entry for %s. Must enter a numeric value" % - self.text) - elif self.type is TYPES.radio: - value = self.input.GetString(self.input.GetSelection()) - elif self.type is TYPES.choice: - value = self.input.GetString(self.input.GetSelection()) - elif self.type is TYPES.checkbox: - value = "N" - if self.input.GetValue(): - value = "Y" - else: - raise NotImplementedError() - - return value - - def set_value(self, value): - # Set value of the control (string or int) - if not self.input: - # Can't 'set' help text etc. - raise NotImplementedError() - elif self.type is TYPES.string or self.type is TYPES.int: - self.input.SetValue(value) - elif self.type is TYPES.radio or self.type is TYPES.choice: - index = self.input.FindString(value) - if index == wx.NOT_FOUND: - raise ValidateFail("Invalid value %s for field %s" % - (value, self.text)) - self.input.SetSelection(index) - elif self.type is TYPES.checkbox: - self.input.SetValue(value == "Y") - else: - raise NotImplementedError() - - def destroy(self): - if self.prompt: - self.prompt.Destroy() - if self.input: - self.input.Destroy() - - def show(self, visible): - debug("Setting visibility to %s for field %s prompt=%s" % - (visible, self.text, self.prompt)) - if visible: - if self.prompt: - self.prompt.Show() - if self.input: - self.input.Show() - else: - if self.prompt: - self.prompt.Hide() - if self.input: - self.input.Hide() - - -def prepare_fields(parent, fields, sizer, change_hdlr): - for row, (name, field) in enumerate(fields.items()): - initial = field.initial - # if config.has_option(parent.section, name): - # initial = config.get(parent.section, name) - - add_attributes = wx.ALIGN_CENTER_VERTICAL - width = 1 - field.prompt = wx.StaticText(parent, label=field.text, name=name) - - # Generate different control based on field type - if field.type is TYPES.string or field.type is TYPES.int: - field.input = wx.TextCtrl(parent, value=initial, name=name, - size=TEXT_BOX_SIZE) - - elif field.type is TYPES.radio: - field.input = wx.RadioBox( - parent, choices=field.choices, majorDimension=1, - style=wx.RA_SPECIFY_COLS, name=name, id=wx.ID_ANY) - - elif field.type is TYPES.choice: - field.input = wx.Choice( - parent, choices=field.choices, name=name) - if initial: - field.input.SetSelection(field.input.FindString(initial)) - elif field.type is TYPES.checkbox: - width = 2 - field.input = wx.CheckBox(parent, name=name, label=field.text, - ) # style=wx.ALIGN_RIGHT) - field.input.SetValue(initial == 'Y') - if field.prompt: - field.prompt.Hide() - field.prompt = None - - elif field.type is TYPES.help: - width = 2 - field.prompt.Wrap(TEXT_WIDTH) - field.input = None - - elif field.type is TYPES.separator: - width = 2 - field.prompt = wx.StaticLine(parent, -1) - add_attributes = wx.EXPAND | wx.ALL - field.input = None - - else: - raise NotImplementedError() - - col = 0 - if field.prompt: - sizer.Add(field.prompt, (row, col), span=(1, width), - flag=add_attributes) - col += 1 - if field.input: - field.input.Enable(field.enabled) - sizer.Add(field.input, (row, col), - flag=add_attributes) - - # Go through again and set show/hide relationships - for name, field in fields.items(): - if field.shows: - # Add display handlers - field.input.Bind(wx.EVT_CHECKBOX, change_hdlr) - # todo tsmith add other evts - - # Start by hiding target prompt/input controls - for target_name in field.shows: - target = fields[target_name] - if target.prompt: - target.prompt.Hide() - if target.input: - target.input.Hide() - - -def on_change(parent, fields, event): - obj = event.GetEventObject() - - # debug("Checked: " + str(event.Checked()) + - # ", Reverse: " + str(parent.fields[obj.GetName()].reverse) + - # ", Will show: " + str(event.Checked() is not - # parent.fields[obj.GetName()].reverse)) - - # Hide/Show the targets of the control - # Note: the "is not" implements switching the show logic around - handle_sub_show( - fields, - fields[obj.GetName()].shows, - event.Checked() is not fields[obj.GetName()].reverse) - - parent.Layout() - event.Skip() - - -def handle_sub_show(fields, targets, show): - """ Recursive function to handle showing/hiding of a list of fields - :param targets: [String] - :param show: bool - """ - - sub_handled = [] - for tgt in targets: - if tgt in sub_handled: - # Handled by newly shown control - continue - - tgt_field = fields[tgt] - # Show or hide this field as necessary - tgt_field.show(show) - - # If it shows others (checkbox) and is now shown, - # apply it's value decide on showing it's children, not the - # original show - if tgt_field.shows and show: - sub_handled.extend(tgt_field.shows) - handle_sub_show( - fields, - tgt_field.shows, - (tgt_field.get_value() is 'Y') is not fields[tgt].reverse) - - -def set_icons(parent): - # Icon setting - # todo Make higher resolution icons, verify on different linux desktops - icons = wx.IconBundle() - for sz in [16, 32, 48]: - # try: - # icon = wx.Icon(wrs_ico.windriver_favicon.getIcon(), - # width=sz, height=sz) - icon = wrs_ico.favicon.getIcon() - icons.AddIcon(icon) - # except: - # pass - parent.SetIcons(icons) - - # ico = wrs_ico.windriver_favicon.getIcon() - # self.SetIcon(ico) - - # self.tbico = wx.TaskBarIcon() - # self.tbico.SetIcon(ico, '') diff --git a/configutilities/configutilities/configutilities/common/utils.py b/configutilities/configutilities/configutilities/common/utils.py deleted file mode 100644 index 319aa53ed7..0000000000 --- a/configutilities/configutilities/configutilities/common/utils.py +++ /dev/null @@ -1,367 +0,0 @@ -""" -Copyright (c) 2015-2016 Wind River Systems, Inc. - -SPDX-License-Identifier: Apache-2.0 - -""" - -from six.moves import configparser -import re -import six -from netaddr import IPNetwork -from netaddr import IPAddress -from netaddr import AddrFormatError -from netaddr import valid_ipv4 -from netaddr import valid_ipv6 - -from configutilities.common.exceptions import ValidateFail - -EXPECTED_SERVICE_NAME_AND_TYPE = ( - {"KEYSTONE_SERVICE_NAME": "keystone", - "KEYSTONE_SERVICE_TYPE": "identity", - "SYSINV_SERVICE_NAME": "sysinv", - "SYSINV_SERVICE_TYPE": "platform", - "PATCHING_SERVICE_NAME": "patching", - "PATCHING_SERVICE_TYPE": "patching", - "NFV_SERVICE_NAME": "vim", - "NFV_SERVICE_TYPE": "nfv", - "FM_SERVICE_NAME": "fm", - "FM_SERVICE_TYPE": "faultmanagement", - "BARBICAN_SERVICE_NAME": "barbican", - "BARBICAN_SERVICE_TYPE": "key-manager", - }) - - -def is_valid_vlan(vlan): - """Determine whether vlan is valid.""" - try: - if 0 < int(vlan) < 4095: - return True - else: - return False - except (ValueError, TypeError): - return False - - -def is_mtu_valid(mtu): - """Determine whether a mtu is valid.""" - try: - if int(mtu) < 576: - return False - elif int(mtu) > 9216: - return False - else: - return True - except (ValueError, TypeError): - return False - - -def is_valid_hostname(hostname): - """Determine whether a hostname is valid as per RFC 1123.""" - - # Maximum length of 255 - if not hostname or len(hostname) > 255: - return False - # Allow a single dot on the right hand side - if hostname[-1] == ".": - hostname = hostname[:-1] - # Create a regex to ensure: - # - hostname does not begin or end with a dash - # - each segment is 1 to 63 characters long - # - valid characters are A-Z (any case) and 0-9 - valid_re = re.compile("(?!-)[A-Z\d-]{1,63}(? Validate a system configuration file\n" - "--region-config Validate a region configuration file\n" - % sys.argv[0]) - exit(1) - - -def main(): - config_file = None - system_config = False - region_config = False - - arg = 1 - while arg < len(sys.argv): - if sys.argv[arg] == "--system-config": - arg += 1 - if arg < len(sys.argv): - config_file = sys.argv[arg] - else: - print("--system-config requires the filename of the config " - "file") - exit(1) - system_config = True - elif sys.argv[arg] == "--region-config": - arg += 1 - if arg < len(sys.argv): - config_file = sys.argv[arg] - else: - print("--region-config requires the filename of the config " - "file") - exit(1) - region_config = True - elif sys.argv[arg] in ["--help", "-h", "-?"]: - show_help() - else: - print("Invalid option.") - show_help() - arg += 1 - - if [system_config, region_config].count(True) != 1: - print("Invalid combination of options selected") - show_help() - - if system_config: - config_type = DEFAULT_CONFIG - else: - config_type = REGION_CONFIG - - if not os.path.isfile(config_file): - print("Config file %s does not exist" % config_file) - exit(1) - - # Parse the system config file - print("Parsing configuration file... ", end=' ') - system_config = parse_config(config_file) - print("DONE") - - # Validate the system config file - print("Validating configuration file... ", end=' ') - try: - # we use the presence of tsconfig to determine if we are onboard or - # not since it will not be available in the offboard case - offboard = False - try: - from tsconfig.tsconfig import SW_VERSION # noqa: F401 - except ImportError: - offboard = True - validate(system_config, config_type, None, offboard) - except configparser.Error as e: - print("Error parsing configuration file %s: %s" % (config_file, e)) - except (ConfigFail, ValidateFail) as e: - print("\nValidation failed: %s" % e) - print("DONE") diff --git a/configutilities/configutilities/configutilities/configfiletool.py b/configutilities/configutilities/configutilities/configfiletool.py deleted file mode 100755 index bd85d8d7bb..0000000000 --- a/configutilities/configutilities/configutilities/configfiletool.py +++ /dev/null @@ -1,1495 +0,0 @@ -""" -Copyright (c) 2015-2017 Wind River Systems, Inc. - -SPDX-License-Identifier: Apache-2.0 - -""" - -from collections import OrderedDict -from six.moves import configparser -import wx -import wx.wizard as wiz -import wx.lib.dialogs -import wx.lib.scrolledpanel - -from configutilities.common.configobjects import REGION_CONFIG -from configutilities.common.configobjects import DEFAULT_CONFIG -from configutilities.common.exceptions import ValidateFail -from configutilities.common.guicomponents import Field -from configutilities.common.guicomponents import TYPES -from configutilities.common.guicomponents import prepare_fields -from configutilities.common.guicomponents import on_change -from configutilities.common.guicomponents import debug -from configutilities.common.guicomponents import set_icons -from configutilities.common.guicomponents import TEXT_WIDTH -from configutilities.common.guicomponents import VGAP -from configutilities.common.guicomponents import HGAP -from configutilities.common.validator import ConfigValidator -from configutilities.common.validator import TiS_VERSION - -PADDING = 5 -CONFIG_TYPE = DEFAULT_CONFIG - -# Config parser to hold current configuration -filename = None -filedir = None -config = configparser.RawConfigParser() -config.optionxform = str - - -def print_config(conf=config): - debug('======CONFIG CONTENTS======') - debug(get_config(config)) - debug('======END CONFIG======') - - -def get_config(conf=config): - result = "" - for section in conf.sections(): - result += "\n[" + section + "]" + "\n" - for option in config.options(section): - result += option + "=" + config.get(section, option) + "\n" - return result - - -def get_opt(section, option): - if config.has_section(section): - if config.has_option(section, option): - return config.get(section, option) - return None - - -class ConfigWizard(wx.wizard.Wizard): - """Titanium Cloud configuration wizard, contains pages and more specifically - ConfigPages, which have a structure for populating/processing - configuration fields (questions) - """ - def __init__(self): - wx.wizard.Wizard.__init__(self, None, -1, - "Titanium Cloud Configuration File " - "Creator v" + TiS_VERSION) - - set_icons(self) - - self.pages = [] - # Catch wizard events - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.on_page_changed) - self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.on_page_changing) - self.Bind(wiz.EVT_WIZARD_CANCEL, self.on_cancel) - self.Bind(wiz.EVT_WIZARD_FINISHED, self.on_finished) - - self.add_page(STARTPage(self)) - self.add_page(REGIONPage(self)) - self.add_page(SHAREDSERVICESPage(self)) - self.add_page(REG2SERVICESPage(self)) - self.add_page(REG2SERVICESPage2(self)) - self.add_page(SYSTEMPage(self)) - self.add_page(PXEBootPage(self)) - self.add_page(MGMTPage(self)) - self.add_page(INFRAPage(self)) - self.add_page(OAMPage(self)) - self.add_page(AUTHPage(self)) - self.add_page(ENDPage(self)) - - size = self.GetBestSize() - - # Deprecated, from before scroll panel - # for page in self.pages: - # if issubclass(type(page), ConfigPage): - # # Must create fields for the page and show them all - # # to get max possible size - # page.load() - # page.GetSizer().ShowItems(True) - # page_size = page.GetBestSize() - # if page_size.GetHeight() > size.GetHeight(): - # size.SetHeight(page_size.GetHeight()) - # if page_size.GetWidth() > size.GetWidth(): - # size.SetWidth(page_size.GetWidth()) - # page.DestroyChildren() - - size.SetWidth(560) - size.SetHeight(530) - self.SetPageSize(size) - self.GetSizer().Layout() - - def add_page(self, page): - """Add a new page""" - if self.pages: - previous_page = self.pages[-1] - page.SetPrev(previous_page) - previous_page.SetNext(page) - self.pages.append(page) - - def run(self): - """Start the wizard""" - self.RunWizard(self.pages[0]) - - def on_page_changed(self, evt): - """Executed after the page has changed.""" - page = evt.GetPage() - if evt.GetDirection(): - page.DestroyChildren() - page.load() - - def on_page_changing(self, evt): - """Executed before the page changes, can be blocked (vetoed)""" - page = evt.GetPage() - # Perform the page validation - if evt.GetDirection(): - try: - page.validate_page() - except Exception as ex: - dlg = wx.MessageDialog( # ScrolledMessageDialog( - self, - ex.message, - "Error on page") - dlg.ShowModal() - # Do not allow progress if errors were raised - evt.Veto() - # raise ex - - def on_cancel(self, evt): - """On cancel button press, not used for now""" - pass - - def on_finished(self, evt): - """On finish button press, not used for now""" - pass - - def skip_page(self, page, skip): - for p in self.pages: - if p.__class__.__name__ == page.__name__: - p.skip = skip - - -class WizardPage(wiz.PyWizardPage): - """ An extended panel obj with a few methods to keep track of its siblings. - This should be modified and added to the wizard. Season to taste.""" - def __init__(self, parent): - wx.wizard.PyWizardPage.__init__(self, parent) - self.parent = parent - self.title = "" - self.next = self.prev = None - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.SetSizer(self.sizer) - self.skip = False - - def set_title(self, title_text): - title = wx.StaticText(self, -1, title_text) - title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)) - self.sizer.AddWindow(title, 0, wx.ALIGN_LEFT | wx.ALL, PADDING) - self.add_line() - - def add_content(self, content, proportion=0): - """Add aditional widgets to the bottom of the page""" - self.sizer.Add(content, proportion, wx.EXPAND | wx.ALL, PADDING) - - def add_line(self): - self.sizer.AddWindow(wx.StaticLine(self, -1), 0, wx.EXPAND | wx.ALL, - PADDING) - - def SetNext(self, next): - """Set the next page""" - self.next = next - - def SetPrev(self, prev): - """Set the previous page""" - self.prev = prev - - def GetNext(self): - """Return the next page""" - if self.next and self.next.skip: - return self.next.GetNext() - return self.next - - def GetPrev(self): - """Return the previous page""" - if self.prev and self.prev.skip: - return self.prev.GetPrev() - return self.prev - - def load(self): - # Run every time a page is visited (from prev or next page) - pass - - def validate_page(self): - # Validate the config related to this specific page before advancing - pass - - -class ConfigPage(WizardPage): - """ A Page of the wizard with questions/answers - """ - def __init__(self, *args, **kwargs): - super(ConfigPage, self).__init__(*args, **kwargs) - # Section header to put in the INI file - self.section = "" - # Methods of the config_validator to be called for this section - self.validator_methods = [] - self.title = "" - self.help_text = "" - self.fields = OrderedDict() - - def load(self): - self.title = "" - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.SetSizer(self.sizer) - - self.section = "" - self.title = "" - self.help_text = "" - for field in self.fields.values(): - field.destroy() - self.fields = OrderedDict() - - def do_setup(self): - # Reset page, in case fields have changed - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.SetSizer(self.sizer) - - # Set up title and help text - self.set_title(self.title) - - if self.help_text: - help_text = wx.StaticText(self, -1, self.help_text) - help_text.Wrap(TEXT_WIDTH) - self.add_content(help_text) - self.add_line() - - self.spanel = wx.lib.scrolledpanel.ScrolledPanel(self, -1) - # to view spanel: , style=wx.SIMPLE_BORDER) - self.add_content(self.spanel, 3) - - # Add fields to page - # gridSizer = wx.FlexGridSizer(rows=6, cols=2, vgap=10, - # hgap=10) - self.gridSizer = wx.GridBagSizer(vgap=VGAP, hgap=HGAP) - # gridSizer.SetFlexibleDirection(wx.VERTICAL) - # gridSizer.SetFlexibleDirection(wx.BOTH) - - self.spanel.SetSizer(self.gridSizer) - self.spanel.SetupScrolling() - - # self.add_content(gridSizer) - - prepare_fields(self.spanel, self.fields, self.gridSizer, - self.on_change) - - self.Layout() - self.spanel.Layout() - - def on_change(self, event): - on_change(self, self.fields, event) - - def validate_page(self): - # Gets the config from the current page, then sends to the validator - self.get_config() - - print_config(config) - - validator = ConfigValidator(config, None, CONFIG_TYPE, True) - - mode = get_opt('SYSTEM', 'SYSTEM_MODE') - if mode: - validator.set_system_mode(mode) - - dc_role = get_opt('SYSTEM', 'DISTRIBUTED_CLOUD_ROLE') - if dc_role: - validator.set_system_dc_role(dc_role) - - for method in self.validator_methods: - getattr(validator, method)() - - def get_config(self): - # Removes possibly out-dated config section so it can be over-written - if config.has_section(self.section): - config.remove_section(self.section) - - self.add_fields() - - def add_fields(self): - # Adds the page's section to the config object if necessary - if not config.has_section(self.section): - config.add_section(self.section) - - # Add all of the non-transient fields (straight-forward mapping) - for name, field in self.fields.items(): - if not field.transient and field.get_value(): - config.set(self.section, name, field.get_value()) - - def bind_events(self): - pass - - -class STARTPage(WizardPage): - def load(self): - super(STARTPage, self).load() - - self.set_title("Start") - help_text = wx.StaticText( - self, -1, - "Welcome to the Titanium Cloud Configuration File " - "Creator.\n\n" - "This wizard will walk you through the steps of creating a " - "configuration file which can be used to automate the " - "installation of Titanium Cloud. Note this utility can only be " - "used to create configuration files compatible with version " + - TiS_VERSION + " of Titanium Cloud.\n\n" - "NOTE: Moving backwards in the wizard will result in loss of the " - "current page's configuration and will need to be reentered\n\n" - "Press next to begin.\n\n\n\n") - help_text.Wrap(TEXT_WIDTH) - self.add_content(help_text) - - # self.add_line() - - # To implement this, would need special mapping for every page... - # (from config to control) - # putting this on the long(er)-term todo list for now - # self.add_content(wx.StaticText( - # self, -1, - # 'You may optionally pre-populate this utility by reading in an ' - # 'existing Titanium Cloud configuration file')) - - # self.load_button = wx.Button(self, -1, "Load Configuration File " - # "(Optional)") - # self.Bind(wx.EVT_BUTTON, self.on_read, self.load_button) - # self.add_content(self.load_button) - - def on_read(self, event): - reader = wx.FileDialog( - self, "Open Existing Titanium Cloud Configuration File", - "", "", "INI file (*.ini)|*.ini", - wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - - if reader.ShowModal() == wx.ID_CANCEL: - return - - # Read in the config file - global filename, filedir, config - try: - config.read(reader.GetPath()) - filename = reader.GetFilename() - filedir = reader.GetDirectory() - except Exception as ex: - wx.LogError("Cannot parse configuration file, Error: %s." % ex) - config = configparser.RawConfigParser() - config.optionxform = str - return - - # todo tsmith - # Do validation of the imported file - - -class REGIONPage(ConfigPage): - def load(self): - super(REGIONPage, self).load() - - # Header in INI file - self.section = "SHARED_SERVICES" - self.validator_methods = [] - self.title = "Region Configuration" - self.help_text = ( - "Configuring this system in region mode provides the ability to " - "operate as a secondary independent region to an existing " - "Openstack cloud deployment (Certain restrictions apply, refer to " - "system documentation).\n\n" - "Keystone (and optionally Glance) " - "services can be configured as shared services, which " - "prevents them from being configured on the secondary region and " - "instead those services already configured in the primary region " - "will be accessed.") - - self.set_fields() - self.do_setup() - self.bind_events() - - # Skip region pages by default - self.skip_region(True) - - def set_fields(self): - self.fields['is_region'] = Field( - text="Configure as a secondary region", - type=TYPES.checkbox, - transient=True, - shows=["REGION_NAME", - "ADMIN_TENANT_NAME", - "ADMIN_USER_NAME", - "ADMIN_PASSWORD", - "SERVICE_TENANT_NAME", - "keystone_help", - "KEYSTONE_ADMINURL", - "sep1", - "keystone_note", - ] - ) - - self.fields['REGION_NAME'] = Field( - text="Name of the primary region", - type=TYPES.string, - initial="RegionOne" - ) - self.fields["sep1"] = Field(type=TYPES.separator) - self.fields['keystone_help'] = Field( - text="Primary Keystone Configuration\n\nThis information " - "is needed for the primary " - "region in order to validate or create the shared " - "services.", - type=TYPES.help, - ) - self.fields['SERVICE_TENANT_NAME'] = Field( - text="Name of the service tenant", - type=TYPES.string, - initial="RegionTwo_services" - ) - self.fields['ADMIN_TENANT_NAME'] = Field( - text="Name of the admin tenant", - type=TYPES.string, - initial="admin" - ) - self.fields['ADMIN_USER_NAME'] = Field( - text="Username of the keystone admin account", - type=TYPES.string, - initial="admin" - ) - self.fields['ADMIN_PASSWORD'] = Field( - text="Password of the keystone admin account", - type=TYPES.string, - initial="" - ) - self.fields['KEYSTONE_ADMINURL'] = Field( - text="Authentication URL of the keystone service", - type=TYPES.string, - initial="http://192.168.204.2:5000/v3" - ) - self.fields['keystone_note'] = Field( - text="NOTE: If 'Automatically configure shared keystone' " - "is checked in the upcoming 'Secondary Region Services' page," - " then the service tenant (above) will be created " - "if not present.", - type=TYPES.help, - ) - - def validate_page(self): - super(REGIONPage, self).validate_page() - # Do page specific validation here - if self.fields['is_region'].get_value() == 'Y' and \ - not config.has_option(self.section, "ADMIN_PASSWORD"): - raise ValidateFail("The keystone admin password is mandatory") - - def get_config(self): - super(REGIONPage, self).get_config() - - if len(config.items(self.section)) == 0: - config.remove_section(self.section) - config.remove_section("REGION_2_SERVICES") - config.remove_section("REGION2_PXEBOOT_NETWORK") - else: - # Add service name which doesn't change - config.set(self.section, "KEYSTONE_SERVICE_NAME", "keystone") - config.set(self.section, "KEYSTONE_SERVICE_TYPE", "identity") - - def bind_events(self): - self.fields['is_region'].input.Bind(wx.EVT_CHECKBOX, self.on_region) - - def on_region(self, event): - # Set the region pages to be skipped or not - self.skip_region(event.GetInt() == 0) - event.Skip() - - def skip_region(self, skip): - debug("Setting region skips to %s" % skip) - self.next.skip = skip - self.next.next.skip = skip - self.next.next.next.skip = skip - self.parent.skip_page(AUTHPage, not skip) - - # Set the config type appropriately - global CONFIG_TYPE - if skip: - CONFIG_TYPE = DEFAULT_CONFIG - else: - CONFIG_TYPE = REGION_CONFIG - - # Remove any sections that aren't handled in region-config mode - config.remove_section("PXEBOOT_NETWORK") - config.remove_section("AUTHENTICATION") - - -class SHAREDSERVICESPage(ConfigPage): - def load(self): - super(SHAREDSERVICESPage, self).load() - - self.section = "SHARED_SERVICES" - self.validator_methods = [] - self.title = "Regions - Shared Services" - self.help_text = ( - "Keystone is always configured as a shared service. " - "Glance may also optionally be configured as " - "shared services.") - - self.set_fields() - self.do_setup() - self.bind_events() - - def set_fields(self): - # GLANCE - self.fields['share_glance'] = Field( - text="Share the primary region's glance service", - type=TYPES.checkbox, - transient=True - ) - - def validate_page(self): - # do previous pages validation as well to refresh config, since they - # share a section - self.prev.validate_page() - super(SHAREDSERVICESPage, self).validate_page() - - # Do page specific validation here - - def get_config(self): - # Skip the parent get_config so the section isn't removed - # (since it's shared we want the old info) - self.add_fields() - - # Add Static service types - if self.fields['share_glance'].get_value() == 'Y': - config.set(self.section, "GLANCE_SERVICE_NAME", "glance") - config.set(self.section, "GLANCE_SERVICE_TYPE", "image") - - -class REG2SERVICESPage(ConfigPage): - - def load(self): - super(REG2SERVICESPage, self).load() - self.section = "REGION_2_SERVICES" - # Validation is only done on last of region pages - self.validator_methods = [] - self.title = "Secondary Region Services (1/2)" - self.help_text = ( - "Secondary region services are not shared with the primary " - "region, during installation they will be configured to run " - "in this region.") - - self.set_fields() - self.do_setup() - self.bind_events() - - def set_fields(self): - - self.fields['create_help'] = Field( - text="During configuration, the Primary Region's Keystone " - "can be automatically " - "provisioned to accommodate this region, including if " - "necessary the services tenant, users, services, " - "and endpoints. If this is not " - "enabled, manual configuration of the Primary Region's " - "Keystone must be done and " - "only validation will be performed during this secondary " - "region's configuration.\n\n" - "Note: passwords are optional if this option is selected.", - type=TYPES.help, - ) - self.fields['CREATE'] = Field( - text="Automatically configure shared keystone", - type=TYPES.checkbox, - initial='Y', - ) - self.fields['REGION_NAME'] = Field( - text="Name for this system's region", - type=TYPES.string, - initial="RegionTwo" - ) - self.fields['sep1'] = Field(type=TYPES.separator) - - if not config.has_option('SHARED_SERVICES', 'GLANCE_SERVICE_NAME'): - # GLANCE - self.fields['GLANCE_USER_NAME'] = Field( - text="Glance username", - type=TYPES.string, - initial="glance") - self.fields['GLANCE_PASSWORD'] = Field( - text="Glance user password", - type=TYPES.string, - initial="") - self.fields['sep2'] = Field(type=TYPES.separator) - - self.fields['NOVA_USER_NAME'] = Field( - text="Nova username", - type=TYPES.string, initial="nova") - self.fields['NOVA_PASSWORD'] = Field( - text="Nova user password", - type=TYPES.string, initial="") - - def validate_page(self): - super(REG2SERVICESPage, self).validate_page() - - if self.fields['CREATE'].get_value() == 'N': - if (('GLANCE_PASSWORD' in self.fields and - not self.fields['GLANCE_PASSWORD'].get_value()) or - not self.fields['NOVA_PASSWORD'].get_value()): - raise ValidateFail("Passwords are mandatory when automatic " - "keystone configuration is not enabled.") - - def get_config(self): - super(REG2SERVICESPage, self).get_config() - - -class REG2SERVICESPage2(ConfigPage): - - def load(self): - super(REG2SERVICESPage2, self).load() - - self.section = "REGION_2_SERVICES" - # Validation is only done on last page - self.validator_methods = ["validate_network", "validate_region"] - self.title = "Secondary Region Services (2/2)" - - self.set_fields() - self.do_setup() - self.bind_events() - - def set_fields(self): - self.fields['NEUTRON_USER_NAME'] = Field( - text="Neutron username", - type=TYPES.string, initial="neutron") - self.fields['NEUTRON_PASSWORD'] = Field( - text="Neutron user password", - type=TYPES.string, initial="") - - self.fields['SYSINV_USER_NAME'] = Field( - text="Sysinv username", - type=TYPES.string, initial="sysinv") - self.fields['SYSINV_PASSWORD'] = Field( - text="Sysinv user password", - type=TYPES.string, initial="") - - self.fields['PATCHING_USER_NAME'] = Field( - text="Patching username", - type=TYPES.string, initial="patching") - self.fields['PATCHING_PASSWORD'] = Field( - text="Patching user password", - type=TYPES.string, initial="") - - self.fields['HEAT_USER_NAME'] = Field( - text="Heat username", - type=TYPES.string, initial="heat") - self.fields['HEAT_PASSWORD'] = Field( - text="Heat user password", - type=TYPES.string, initial="") - self.fields['HEAT_ADMIN_DOMAIN'] = Field( - text="Heat admin domain", - type=TYPES.string, initial="heat") - self.fields['HEAT_ADMIN_USER_NAME'] = Field( - text="Heat admin username", - type=TYPES.string, initial="heat_stack_admin") - self.fields['HEAT_ADMIN_PASSWORD'] = Field( - text="Password of the heat admin user", - type=TYPES.string, initial="") - - self.fields['CEILOMETER_USER_NAME'] = Field( - text="Ceilometer username", - type=TYPES.string, initial="ceilometer") - self.fields['CEILOMETER_PASSWORD'] = Field( - text="Ceilometer user password", - type=TYPES.string, initial="") - - self.fields['AODH_USER_NAME'] = Field( - text="Aodh username", - type=TYPES.string, initial="aodh") - self.fields['AODH_PASSWORD'] = Field( - text="Aodh user password", - type=TYPES.string, initial="") - - self.fields['NFV_USER_NAME'] = Field( - text="NFV username", - type=TYPES.string, initial="vim") - self.fields['NFV_PASSWORD'] = Field( - text="NFV user password", - type=TYPES.string, initial="") - - self.fields['MTCE_USER_NAME'] = Field( - text="MTCE username", - type=TYPES.string, initial="mtce") - self.fields['MTCE_PASSWORD'] = Field( - text="MTCE user password", - type=TYPES.string, initial="") - - self.fields['PANKO_USER_NAME'] = Field( - text="PANKO username", - type=TYPES.string, initial="panko") - self.fields['PANKO_PASSWORD'] = Field( - text="PANKO user password", - type=TYPES.string, initial="") - - self.fields['PLACEMENT_USER_NAME'] = Field( - text="Placement username", - type=TYPES.string, initial="placement") - self.fields['PLACEMENT_PASSWORD'] = Field( - text="Placement user password", - type=TYPES.string, initial="") - - self.fields['GNOCCHI_USER_NAME'] = Field( - text="GNOCCHI username", - type=TYPES.string, initial="gnocchi") - self.fields['GNOCCHI_PASSWORD'] = Field( - text="GNOCCHI user password", - type=TYPES.string, initial="") - - self.fields['FM_USER_NAME'] = Field( - text="FM username", - type=TYPES.string, initial="fm") - self.fields['FM_PASSWORD'] = Field( - text="FM user password", - type=TYPES.string, initial="") - - self.fields['BARBICAN_USER_NAME'] = Field( - text="Barbican username", - type=TYPES.string, initial="barbican") - self.fields['BARBICAN_PASSWORD'] = Field( - text="Barbican user password", - type=TYPES.string, initial="") - - def validate_page(self): - self.prev.validate_page() - super(REG2SERVICESPage2, self).validate_page() - - def get_config(self): - # Special handling for all region sections is done here - self.add_fields() - - -class SYSTEMPage(ConfigPage): - def load(self): - super(SYSTEMPage, self).load() - - self.section = "SYSTEM" - self.validator_methods = [] - self.title = "System" - self.help_text = ( - "All-in-one System Mode Configuration\n\nAvailable options are: \n" - "duplex-direct: two node redundant configuration. Management and " - "infrastructure networks are directly connected to peer ports\n" - "duplex: two node redundant configuration\n" - "simplex: single node non-redundant configuration") - - self.system_mode = ['duplex-direct', 'duplex', 'simplex'] - - self.set_fields() - self.do_setup() - self.bind_events() - - self.skip_not_required_pages(False) - - def set_fields(self): - self.fields['use_mode'] = Field( - text="Configure as an All-in-one system", - type=TYPES.checkbox, - transient=True, - shows=["SYSTEM_MODE"] - ) - self.fields['SYSTEM_MODE'] = Field( - text="System redundant configuration", - type=TYPES.radio, - choices=self.system_mode, - ) - - def validate_page(self): - super(SYSTEMPage, self).validate_page() - - def get_config(self): - super(SYSTEMPage, self).get_config() - if len(config.items(self.section)) == 0: - config.remove_section(self.section) - else: - config.set(self.section, 'SYSTEM_TYPE', 'All-in-one') - - def bind_events(self): - self.fields['SYSTEM_MODE'].input.Bind(wx.EVT_RADIOBOX, self.on_mode) - self.fields['use_mode'].input.Bind(wx.EVT_CHECKBOX, self.on_use_mode) - - def on_mode(self, event): - # Set the pages to be skipped or not - self.skip_not_required_pages( - self.system_mode[event.GetInt()] == 'simplex') - event.Skip() - - def on_use_mode(self, event): - # Set the pages to be skipped or not - if event.GetInt() == 0: - # If set to not in use, ensure the pages are not skipped - self.skip_not_required_pages(False) - # And reset to the default selection - self.fields['SYSTEM_MODE'].set_value('duplex-direct') - event.Skip() - - def skip_not_required_pages(self, skip): - # Skip PXEBOOT, BMC and INFRA pages - self.parent.skip_page(PXEBootPage, skip) - self.parent.skip_page(INFRAPage, skip) - - # Remove the sections that are not required - config.remove_section("PXEBOOT_NETWORK") - config.remove_section("BOARD_MANAGEMENT_NETWORK") - config.remove_section("INFRA_NETWORK") - - -class PXEBootPage(ConfigPage): - - def load(self): - super(PXEBootPage, self).load() - self.section = "PXEBOOT_NETWORK" - self.validator_methods = ["validate_pxeboot"] - self.title = "PXEBoot Network" - self.help_text = ( - "The PXEBoot network is used for initial booting and installation " - "of each node. IP addresses on this network are reachable only " - "within the data center.\n\n" - "The default configuration combines the PXEBoot network and the " - "management network. If a separate PXEBoot network is used, it " - "will share the management interface, which requires the " - "management network to be placed on a VLAN.") - - self.set_fields() - self.do_setup() - self.bind_events() - - def set_fields(self): - if config.has_section("REGION_2_SERVICES"): - self.fields['mandatory'] = Field( - text="A PXEBoot network is mandatory for secondary" - " region deployments.", - type=TYPES.help - ) - self.section = "REGION2_PXEBOOT_NETWORK" - else: - self.fields['use_pxe'] = Field( - text="Configure a separate PXEBoot network", - type=TYPES.checkbox, - transient=True, - shows=["PXEBOOT_CIDR", "use_entire_subnet"] - ) - self.fields['PXEBOOT_CIDR'] = Field( - text="PXEBoot subnet", - type=TYPES.string, - initial="192.168.202.0/24" - ) - - # Start/end ranges - self.fields['use_entire_subnet'] = Field( - text="Restrict PXEBoot subnet address range", - type=TYPES.checkbox, - shows=["IP_START_ADDRESS", "IP_END_ADDRESS"], - transient=True - ) - self.fields['IP_START_ADDRESS'] = Field( - text="PXEBoot network start address", - type=TYPES.string, - initial="192.168.202.2", - ) - self.fields['IP_END_ADDRESS'] = Field( - text="PXEBoot network end address", - type=TYPES.string, - initial="192.168.202.254", - ) - - def get_config(self): - super(PXEBootPage, self).get_config() - - if len(config.items(self.section)) == 0: - config.remove_section(self.section) - if config.has_section("REGION_2_SERVICES"): - raise ValidateFail( - "Must configure a PXEBoot network when in region mode") - - def validate_page(self): - super(PXEBootPage, self).validate_page() - # Do page specific validation here - - -class MGMTPage(ConfigPage): - - def load(self): - super(MGMTPage, self).load() - - # Preserve order plus allow mapping back to raw value - if get_opt('SYSTEM', 'SYSTEM_MODE') == 'duplex-direct': - self.lag_choices = OrderedDict([ - ('802.3ad (LACP) policy', '4'), - ]) - else: - self.lag_choices = OrderedDict([ - ('Active-backup policy', '1'), - ('802.3ad (LACP) policy', '4'), - ]) - self.section = "MGMT_NETWORK" - if get_opt('SYSTEM', 'SYSTEM_MODE') != 'simplex': - self.validator_methods = ["validate_pxeboot", "validate_mgmt"] - self.help_text = ( - "The management network is used for internal communication " - "between platform components. IP addresses on this network " - "are reachable only within the data center.") - else: - self.validator_methods = ["validate_aio_simplex_mgmt"] - self.help_text = ( - "The management network is used for internal communication " - "between platform components. IP addresses on this network " - "are reachable only within the host.") - self.title = "Management Network" - - self.set_fields() - self.do_setup() - self.bind_events() - - def set_fields(self): - if get_opt('SYSTEM', 'SYSTEM_MODE') != 'simplex': - self.fields['mgmt_port1'] = Field( - text="Management interface", - type=TYPES.string, - initial="enp0s8", - transient=True - ) - self.fields['lag_help'] = Field( - text="A management bond interface provides redundant " - "connections for the management network. When selected, " - "the field above specifies the first member of the bond.", - type=TYPES.help, - ) - self.fields['LAG_INTERFACE'] = Field( - text="Use management interface link aggregation", - type=TYPES.checkbox, - shows=["LAG_MODE", "mgmt_port2"], - transient=True - ) - self.fields['LAG_MODE'] = Field( - text="Management interface bonding policy", - type=TYPES.choice, - choices=self.lag_choices.keys(), - transient=True - ) - self.fields['mgmt_port2'] = Field( - text="Second management interface member", - type=TYPES.string, - initial="", - transient=True - ) - self.fields['INTERFACE_MTU'] = Field( - text="Management interface MTU", - type=TYPES.int, - initial="1500", - transient=True - ) - if config.has_option('PXEBOOT_NETWORK', 'PXEBOOT_CIDR') or \ - config.has_option('REGION2_PXEBOOT_NETWORK', - 'PXEBOOT_CIDR'): - self.fields['vlan_help'] = Field( - text=("A management VLAN is required because a separate " - "PXEBoot network was configured on the management " - "interface."), - type=TYPES.help - ) - self.fields['VLAN'] = Field( - text="Management VLAN Identifier", - type=TYPES.int, - initial="", - ) - - self.fields['CIDR'] = Field( - text="Management subnet", - type=TYPES.string, - initial="192.168.204.0/24", - ) - - self.fields['MULTICAST_CIDR'] = Field( - text="Management multicast subnet", - type=TYPES.string, - initial='239.1.1.0/28' - ) - - # Start/end ranges - self.fields['use_entire_subnet'] = Field( - text="Restrict management subnet address range", - type=TYPES.checkbox, - shows=["IP_START_ADDRESS", "IP_END_ADDRESS"], - transient=True - ) - self.fields['IP_START_ADDRESS'] = Field( - text="Management network start address", - type=TYPES.string, - initial="192.168.204.2", - ) - self.fields['IP_END_ADDRESS'] = Field( - text="Management network end address", - type=TYPES.string, - initial="192.168.204.254", - ) - - # Dynamic addressing - self.fields['dynamic_help'] = Field( - text=( - "IP addresses can be assigned to hosts dynamically or " - "a static IP address can be specified for each host. " - "Note: This choice applies to both the management network " - "and infrastructure network."), - type=TYPES.help, - ) - self.fields['DYNAMIC_ALLOCATION'] = Field( - text="Use dynamic IP address allocation", - type=TYPES.checkbox, - initial='Y' - ) - else: - self.fields['CIDR'] = Field( - text="Management subnet", - type=TYPES.string, - initial="192.168.204.0/28", - ) - - def validate_page(self): - super(MGMTPage, self).validate_page() - # Do page specific validation here - - def get_config(self): - super(MGMTPage, self).get_config() - - if get_opt('SYSTEM', 'SYSTEM_MODE') != 'simplex': - # Add logical interface - ports = self.fields['mgmt_port1'].get_value() - if self.fields['mgmt_port2'].get_value(): - ports += "," + self.fields['mgmt_port2'].get_value() - li = create_li( - lag=self.fields['LAG_INTERFACE'].get_value(), - mode=self.lag_choices.get(self.fields['LAG_MODE'].get_value()), - mtu=self.fields['INTERFACE_MTU'].get_value(), - ports=ports - ) - config.set(self.section, 'LOGICAL_INTERFACE', li) - clean_lis() - - -class INFRAPage(ConfigPage): - def load(self): - super(INFRAPage, self).load() - - # Preserve order plus allow mapping back to raw value - self.lag_choices = OrderedDict([ - ('Active-backup policy', '1'), - ('Balanced XOR policy', '2'), - ('802.3ad (LACP) policy', '4'), - ]) - - self.section = "INFRA_NETWORK" - self.validator_methods = ["validate_storage", - "validate_pxeboot", - "validate_mgmt", - "validate_infra"] - self.title = "Infrastructure Network" - self.help_text = ( - "The infrastructure network is used for internal communication " - "between platform components to offload the management network " - "of high bandwidth services. " - "IP addresses on this network are reachable only within the data " - "center.\n\n" - "If a separate infrastructure interface is not configured the " - "management network will be used.") - - self.set_fields() - self.do_setup() - self.bind_events() - - def set_fields(self): - self.fields['use_infra'] = Field( - text="Configure an infrastructure interface", - type=TYPES.checkbox, - transient=True - ) - self.fields['infra_port1'] = Field( - text="Infrastructure interface", - type=TYPES.string, - initial="", - transient=True - ) - self.fields['lag_help'] = Field( - text="An infrastructure bond interface provides redundant " - "connections for the infrastructure network. When selected, " - "the field above specifies the first member of the bond.", - type=TYPES.help, - ) - self.fields['LAG_INTERFACE'] = Field( - text="Use infrastructure interface link aggregation", - type=TYPES.checkbox, - shows=["LAG_MODE", "infra_port2"], - transient=True - ) - self.fields['LAG_MODE'] = Field( - text="Infrastructure interface bonding policy", - type=TYPES.choice, - choices=self.lag_choices.keys(), - transient=True - ) - self.fields['infra_port2'] = Field( - text="Second infrastructure interface member", - type=TYPES.string, - initial="", - transient=True - ) - self.fields['INTERFACE_MTU'] = Field( - text="Infrastructure interface MTU", - type=TYPES.int, - initial="1500", - transient=True - ) - - # VLAN - self.fields['use_vlan'] = Field( - text="Configure an infrastructure VLAN", - type=TYPES.checkbox, - shows=["VLAN"], - transient=True - ) - self.fields['VLAN'] = Field( - text="Infrastructure VLAN Identifier", - type=TYPES.int, - initial="", - ) - - self.fields['CIDR'] = Field( - text="Infrastructure subnet", - type=TYPES.string, - initial="192.168.205.0/24", - ) - - # Start/end ranges - self.fields['use_entire_subnet'] = Field( - text="Restrict infrastructure subnet address range", - type=TYPES.checkbox, - shows=["IP_START_ADDRESS", "IP_END_ADDRESS"], - transient=True - ) - self.fields['IP_START_ADDRESS'] = Field( - text="Infrastructure network start address", - type=TYPES.string, - initial="192.168.205.2", - ) - self.fields['IP_END_ADDRESS'] = Field( - text="Infrastructure network end address", - type=TYPES.string, - initial="192.168.205.254", - ) - - # This field show/hides all other fields - self.fields['use_infra'].shows = [field for field in self.fields.keys() - if field is not 'use_infra'] - - def validate_page(self): - super(INFRAPage, self).validate_page() - - def get_config(self): - if self.fields['use_infra'].get_value() is 'N': - if config.has_section(self.section): - config.remove_section(self.section) - clean_lis() - return - - super(INFRAPage, self).get_config() - - # Add logical interface - ports = self.fields['infra_port1'].get_value() - if self.fields['infra_port2'].get_value(): - ports += "," + self.fields['infra_port2'].get_value() - li = create_li( - lag=self.fields['LAG_INTERFACE'].get_value(), - mode=self.lag_choices.get(self.fields['LAG_MODE'].get_value()), - mtu=self.fields['INTERFACE_MTU'].get_value(), - ports=ports - ) - config.set(self.section, 'LOGICAL_INTERFACE', li) - clean_lis() - - if len(config.items(self.section)) == 0: - config.remove_section(self.section) - - -class OAMPage(ConfigPage): - def load(self): - super(OAMPage, self).load() - - self.lag_choices = OrderedDict([ - ('Active-backup policy', '1'), - ('Balanced XOR policy', '2'), - ('802.3ad (LACP) policy', '4'), - ]) - - self.section = "OAM_NETWORK" - if get_opt('SYSTEM', 'SYSTEM_MODE') == 'simplex': - self.simplex = True - self.validator_methods = ["validate_aio_network"] - else: - self.simplex = False - self.validator_methods = ["validate_pxeboot", - "validate_mgmt", - "validate_infra", - "validate_oam"] - self.title = "External OAM Network" - self.help_text = ( - "The external OAM network is used for management of the " - "cloud. It also provides access to the " - "platform APIs. IP addresses on this network are reachable " - "outside the data center.") - - self.set_fields() - self.do_setup() - self.bind_events() - - def set_fields(self): - self.fields['oam_port1'] = Field( - text="External OAM interface", - type=TYPES.string, - initial="enp0s3", - transient=True - ) - self.fields['lag_help'] = Field( - text="An external OAM bond interface provides redundant " - "connections for the OAM network. When selected, the " - "field above specifies the first member of the bond.", - type=TYPES.help, - ) - self.fields['LAG_INTERFACE'] = Field( - text="External OAM interface link aggregation", - type=TYPES.checkbox, - shows=["LAG_MODE", "oam_port2"], - transient=True - ) - self.fields['LAG_MODE'] = Field( - text="OAM interface bonding policy", - type=TYPES.choice, - choices=self.lag_choices.keys(), - transient=True - ) - self.fields['oam_port2'] = Field( - text="Second External OAM interface member", - type=TYPES.string, - initial="", - transient=True - ) - self.fields['INTERFACE_MTU'] = Field( - text="External OAM interface MTU", - type=TYPES.int, - initial="1500", - transient=True - ) - - # VLAN - self.fields['use_vlan'] = Field( - text="Configure an External OAM VLAN", - type=TYPES.checkbox, - shows=["VLAN"], - transient=True - ) - self.fields['VLAN'] = Field( - text="External OAM VLAN Identifier", - type=TYPES.int, - initial="", - ) - - self.fields['CIDR'] = Field( - text="External OAM subnet", - type=TYPES.string, - initial="10.10.10.0/24", - ) - self.fields['GATEWAY'] = Field( - text="External OAM gateway address", - type=TYPES.string, - initial="10.10.10.1", - ) - if not self.simplex: - self.fields['IP_FLOATING_ADDRESS'] = Field( - text="External OAM floating address", - type=TYPES.string, - initial="10.10.10.2", - ) - self.fields['IP_UNIT_0_ADDRESS'] = Field( - text="External OAM address for first controller node", - type=TYPES.string, - initial="10.10.10.3", - ) - self.fields['IP_UNIT_1_ADDRESS'] = Field( - text="External OAM address for second controller node", - type=TYPES.string, - initial="10.10.10.4", - ) - else: - self.fields['IP_ADDRESS'] = Field( - text="External OAM address", - type=TYPES.string, - initial="10.10.10.2", - ) - - def get_config(self): - super(OAMPage, self).get_config() - - # Add logical interface - ports = self.fields['oam_port1'].get_value() - if self.fields['oam_port2'].get_value(): - ports += "," + self.fields['oam_port2'].get_value() - li = create_li( - lag=self.fields['LAG_INTERFACE'].get_value(), - mode=self.lag_choices.get(self.fields['LAG_MODE'].get_value()), - mtu=self.fields['INTERFACE_MTU'].get_value(), - ports=ports - ) - config.set(self.section, 'LOGICAL_INTERFACE', li) - clean_lis() - - def validate_page(self): - super(OAMPage, self).validate_page() - # Do page specific validation here - - -class AUTHPage(ConfigPage): - def load(self): - super(AUTHPage, self).load() - self.section = "AUTHENTICATION" - self.validator_methods = ["validate_authentication"] - self.title = "Authentication" - self.help_text = ( - "Create the admin user password.\n" - "It must have a minimum length of 7 characters, and must " - "contain at least 1 upper case, 1 lower case, 1 digit, " - "and 1 special character.\n\n" - "Note: This password will be stored as plaintext in the generated " - "INI file.") - - self.set_fields() - self.do_setup() - self.bind_events() - - def set_fields(self): - self.fields['ADMIN_PASSWORD'] = Field( - text="Password", - type=TYPES.string, - ) - - def get_config(self): - super(AUTHPage, self).get_config() - - def validate_page(self): - super(AUTHPage, self).validate_page() - # Do page specific validation here - - -class ENDPage(WizardPage): - # Final page for file saving - def load(self): - super(ENDPage, self).load() - # Must ensure fields are destroyed/don't exist before adding to - # prevent double-loading - self.sizer.Clear(True) - - self.set_title("Configuration Complete") - self.add_content( - wx.StaticText(self, -1, 'Titanium Cloud Configuration is ' - 'complete, configuration file may now be ' - 'saved.')) - - self.write_button = wx.Button(self, -1, "Save Configuration File") - self.Bind(wx.EVT_BUTTON, self.on_save, self.write_button) - self.add_content(self.write_button) - - # Add the version to the config - if not config.has_section("VERSION"): - config.add_section("VERSION") - config.set("VERSION", "RELEASE", TiS_VERSION) - - self.preview = wx.TextCtrl(self, -1, value=get_config(), - style=wx.TE_MULTILINE | wx.TE_READONLY) - self.add_content(self.preview, 3) - - def on_save(self, event): - writer = wx.FileDialog(self, - message="Save Configuration File", - defaultDir=filedir or "", - defaultFile=filename or "TiC_config.ini", - wildcard="INI file (*.ini)|*.ini", - style=wx.FD_SAVE, - ) - - if writer.ShowModal() == wx.ID_CANCEL: - return - - # Write the configuration to disk - try: - with open(writer.GetPath(), "wb") as f: - config.write(f) - except IOError: - wx.LogError("Error writing configuration file '%s'." % - writer.GetPath()) - - -# todo tsmith include a 'reformat' to shuffle numbers down? -def clean_lis(): - # Remove unreferenced Logical Interfaces in the config - referenced = [] - for sec in config.sections(): - if config.has_option(sec, 'LOGICAL_INTERFACE'): - referenced.append(config.get(sec, 'LOGICAL_INTERFACE')) - - for sec in config.sections(): - if "LOGICAL_INTERFACE_" in sec and sec not in referenced: - config.remove_section(sec) - - -def create_li(lag='N', mode=None, mtu=1500, ports=None): - # todo more graceful matching to an existing LI - for number in range(1, len(config.sections())): - if config.has_section("LOGICAL_INTERFACE_" + str(number)): - debug("Found interface " + str(number) + " with ports " + - config.get("LOGICAL_INTERFACE_" + str(number), - 'INTERFACE_PORTS') - + ". Searching for ports: " + ports) - if config.get("LOGICAL_INTERFACE_" + str(number), - 'INTERFACE_PORTS') == ports: - debug("Matched to LI: " + str(number)) - - # This logical interface already exists, - # so use that but update any values - name = "LOGICAL_INTERFACE_" + str(number) - config.set(name, 'LAG_INTERFACE', lag) - if mode: - config.set(name, 'LAG_MODE', mode) - config.set(name, 'INTERFACE_MTU', mtu) - return name - - # Get unused LI number - number = 1 - while config.has_section("LOGICAL_INTERFACE_" + str(number)): - number += 1 - - # LI doesnt exist so create it with the given values - name = "LOGICAL_INTERFACE_" + str(number) - config.add_section(name) - config.set(name, 'LAG_INTERFACE', lag) - if mode: - config.set(name, 'LAG_MODE', mode) - config.set(name, 'INTERFACE_MTU', mtu) - config.set(name, 'INTERFACE_PORTS', ports) - return name - - -def main(): - app = wx.App(0) # Start the application - - # Create wizard and add the pages to it - conf_wizard = ConfigWizard() - - # Start the wizard - conf_wizard.run() - - # Cleanup - conf_wizard.Destroy() - app.MainLoop() - - -if __name__ == '__main__': - main() diff --git a/configutilities/configutilities/configutilities/configgui.py b/configutilities/configutilities/configutilities/configgui.py deleted file mode 100755 index 9260a15ee7..0000000000 --- a/configutilities/configutilities/configutilities/configgui.py +++ /dev/null @@ -1,114 +0,0 @@ -""" -Copyright (c) 2015-2017 Wind River Systems, Inc. - -SPDX-License-Identifier: Apache-2.0 - -""" - -import wx - -from configutilities.common.guicomponents import set_icons -from configutilities.common.validator import TiS_VERSION -from configutilities import configfiletool -from configutilities import hostfiletool - -TEXT_WIDTH = 560 -BTN_SIZE = (200, -1) - - -class WelcomeScreen(wx.Frame): - def __init__(self, *args, **kwargs): - super(WelcomeScreen, self).__init__(*args, **kwargs) - page = Content(self) - - set_icons(self) - - size = page.main_sizer.Fit(self) - self.SetMinSize(size) - self.Layout() - - -class Content(wx.Panel): - def __init__(self, *args, **kwargs): - super(Content, self).__init__(*args, **kwargs) - - self.title = wx.StaticText( - self, -1, - 'Titanium Cloud Configuration Utility') - self.title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)) - - # Set up controls for the main page - self.description = wx.StaticText( - self, -1, - ' Welcome, The following tools are available for use:') - - self.config_desc = wx.StaticText( - self, -1, - "The Titanium Cloud configuration file wizard allows users to " - "create the configuration INI file which is used during the " - "installation process") - self.config_desc.Wrap(TEXT_WIDTH / 2) - self.hosts_desc = wx.StaticText( - self, -1, - "The Titanium Cloud host file tool allows users to create an XML " - "file specifying hosts to be provisioned as part of the Titanium " - "Cloud cloud deployment.") - self.hosts_desc.Wrap(TEXT_WIDTH / 2) - - self.config_wiz_btn = wx.Button( - self, -1, "Launch Config File Wizard", size=BTN_SIZE) - self.Bind(wx.EVT_BUTTON, self.launch_config_wiz, self.config_wiz_btn) - - self.host_file_tool_btn = wx.Button( - self, -1, "Launch Host File Tool", size=BTN_SIZE) - self.Bind(wx.EVT_BUTTON, self.launch_host_wiz, self.host_file_tool_btn) - - self.box1 = wx.StaticBox(self) - self.box2 = wx.StaticBox(self) - - # Do layout of controls - self.main_sizer = wx.BoxSizer(wx.VERTICAL) - self.tool1Sizer = wx.StaticBoxSizer(self.box1, wx.HORIZONTAL) - self.tool2Sizer = wx.StaticBoxSizer(self.box2, wx.HORIZONTAL) - - self.main_sizer.AddSpacer(10) - self.main_sizer.Add(self.title, flag=wx.ALIGN_CENTER) - self.main_sizer.AddSpacer(10) - self.main_sizer.Add(self.description) - self.main_sizer.AddSpacer(5) - self.main_sizer.Add(self.tool1Sizer, proportion=1, flag=wx.EXPAND) - self.main_sizer.Add(self.tool2Sizer, proportion=1, flag=wx.EXPAND) - self.main_sizer.AddSpacer(5) - - self.tool1Sizer.Add(self.config_desc, flag=wx.ALIGN_CENTER) - self.tool1Sizer.AddSpacer(10) - self.tool1Sizer.Add(self.config_wiz_btn, flag=wx.ALIGN_CENTER) - self.tool2Sizer.Add(self.hosts_desc, flag=wx.ALIGN_CENTER) - self.tool2Sizer.AddSpacer(10) - self.tool2Sizer.Add(self.host_file_tool_btn, flag=wx.ALIGN_CENTER) - - self.SetSizer(self.main_sizer) - - self.Layout() - - def launch_config_wiz(self, event): - conf_wizard = configfiletool.ConfigWizard() - conf_wizard.run() - conf_wizard.Destroy() - - def launch_host_wiz(self, event): - hostfiletool.HostGUI() - - -def main(): - app = wx.App(0) # Start the application - - gui = WelcomeScreen(None, title="Titanium Cloud Configuration Utility v" - + TiS_VERSION) - gui.Show() - app.MainLoop() - app.Destroy() - - -if __name__ == '__main__': - main() diff --git a/configutilities/configutilities/configutilities/hostfiletool.py b/configutilities/configutilities/configutilities/hostfiletool.py deleted file mode 100755 index 3f4e4356cf..0000000000 --- a/configutilities/configutilities/configutilities/hostfiletool.py +++ /dev/null @@ -1,515 +0,0 @@ -""" -Copyright (c) 2015-2017 Wind River Systems, Inc. - -SPDX-License-Identifier: Apache-2.0 - -""" - -from collections import OrderedDict -import netaddr -import xml.etree.ElementTree as ET - -import wx - -from configutilities.common import utils -from configutilities.common import exceptions -from configutilities.common.guicomponents import Field -from configutilities.common.guicomponents import TYPES -from configutilities.common.guicomponents import prepare_fields -from configutilities.common.guicomponents import on_change -from configutilities.common.guicomponents import set_icons -from configutilities.common.guicomponents import handle_sub_show -from configutilities.common.configobjects import HOST_XML_ATTRIBUTES -from configutilities.common.validator import TiS_VERSION - -PAGE_SIZE = (200, 200) -WINDOW_SIZE = (570, 700) -CB_TRUE = True -CB_FALSE = False -PADDING = 10 - -IMPORT_ID = 100 -EXPORT_ID = 101 - -INTERNAL_ID = 105 -EXTERNAL_ID = 106 - -filedir = "" -filename = "" - -# Globals -BULK_ADDING = False - - -class HostPage(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent=parent) - - self.parent = parent - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.SetSizer(self.sizer) - self.fieldgroup = [] - self.fieldgroup.append(OrderedDict()) - self.fieldgroup.append(OrderedDict()) - self.fieldgroup.append(OrderedDict()) - - self.fields_sizer1 = wx.GridBagSizer(vgap=10, hgap=10) - self.fields_sizer2 = wx.GridBagSizer(vgap=10, hgap=10) - self.fields_sizer3 = wx.GridBagSizer(vgap=10, hgap=10) - - # Basic Fields - self.fieldgroup[0]['personality'] = Field( - text="Personality", - type=TYPES.choice, - choices=['compute', 'controller', 'storage'], - initial='compute' - ) - self.fieldgroup[0]['hostname'] = Field( - text="Hostname", - type=TYPES.string, - initial=parent.get_next_hostname() - ) - self.fieldgroup[0]['mgmt_mac'] = Field( - text="Management MAC Address", - type=TYPES.string, - initial="" - ) - self.fieldgroup[0]['mgmt_ip'] = Field( - text="Management IP Address", - type=TYPES.string, - initial="" - ) - self.fieldgroup[0]['location'] = Field( - text="Location", - type=TYPES.string, - initial="" - ) - - # Board Management - self.fieldgroup[1]['uses_bm'] = Field( - text="This host uses Board Management", - type=TYPES.checkbox, - initial="", - shows=['bm_ip', 'bm_username', - 'bm_password', 'power_on'], - transient=True - ) - self.fieldgroup[1]['bm_ip'] = Field( - text="Board Management IP Address", - type=TYPES.string, - initial="" - ) - self.fieldgroup[1]['bm_username'] = Field( - text="Board Management username", - type=TYPES.string, - initial="" - ) - self.fieldgroup[1]['bm_password'] = Field( - text="Board Management password", - type=TYPES.string, - initial="" - ) - self.fieldgroup[1]['power_on'] = Field( - text="Power on host", - type=TYPES.checkbox, - initial="N", - transient=True - ) - - # Installation Parameters - self.fieldgroup[2]['boot_device'] = Field( - text="Boot Device", - type=TYPES.string, - initial="" - ) - self.fieldgroup[2]['rootfs_device'] = Field( - text="Rootfs Device", - type=TYPES.string, - initial="" - ) - self.fieldgroup[2]['install_output'] = Field( - text="Installation Output", - type=TYPES.choice, - choices=['text', 'graphical'], - initial="text" - ) - self.fieldgroup[2]['console'] = Field( - text="Console", - type=TYPES.string, - initial="" - ) - - prepare_fields(self, self.fieldgroup[0], self.fields_sizer1, - self.on_change) - prepare_fields(self, self.fieldgroup[1], self.fields_sizer2, - self.on_change) - prepare_fields(self, self.fieldgroup[2], self.fields_sizer3, - self.on_change) - - # Bind button handlers - self.Bind(wx.EVT_CHOICE, self.on_personality, - self.fieldgroup[0]['personality'].input) - - self.Bind(wx.EVT_TEXT, self.on_hostname, - self.fieldgroup[0]['hostname'].input) - - # Control Buttons - self.button_sizer = wx.BoxSizer(orient=wx.HORIZONTAL) - - self.add = wx.Button(self, -1, "Add a New Host") - self.Bind(wx.EVT_BUTTON, self.on_add, self.add) - - self.remove = wx.Button(self, -1, "Remove this Host") - self.Bind(wx.EVT_BUTTON, self.on_remove, self.remove) - - self.button_sizer.Add(self.add) - self.button_sizer.Add(self.remove) - - # Add fields and spacers - self.sizer.Add(self.fields_sizer1) - self.sizer.AddWindow(wx.StaticLine(self, -1), 0, wx.EXPAND | wx.ALL, - PADDING) - self.sizer.Add(self.fields_sizer2) - self.sizer.AddWindow(wx.StaticLine(self, -1), 0, wx.EXPAND | wx.ALL, - PADDING) - self.sizer.Add(self.fields_sizer3) - self.sizer.AddStretchSpacer() - self.sizer.AddWindow(wx.StaticLine(self, -1), 0, wx.EXPAND | wx.ALL, - PADDING) - self.sizer.Add(self.button_sizer, border=10, flag=wx.CENTER) - - def on_hostname(self, event, string=None): - """Update the List entry text to match the new hostname - """ - string = string or event.GetString() - index = self.parent.GetSelection() - self.parent.SetPageText(index, string) - self.parent.parent.Layout() - - def on_personality(self, event, string=None): - """Remove hostname field if it's a storage or controller - """ - string = string or event.GetString() - index = self.parent.GetSelection() - if string == 'compute': - self.fieldgroup[0]['hostname'].show(True) - self.parent.SetPageText(index, - self.fieldgroup[0]['hostname'].get_value()) - return - elif string == 'controller': - self.fieldgroup[0]['hostname'].show(False) - elif string == 'storage': - self.fieldgroup[0]['hostname'].show(False) - self.parent.SetPageText(index, string) - self.parent.Layout() - - def on_add(self, event): - try: - self.validate() - except Exception as ex: - wx.LogError("Error on page: " + ex.message) - return - - self.parent.new_page() - - def on_remove(self, event): - if self.parent.GetPageCount() is 1: - wx.LogError("Must leave at least one host") - return - index = self.parent.GetSelection() - self.parent.DeletePage(index) - - def to_xml(self): - """Create the XML for this host - """ - self.validate() - - attrs = "" - # Generic handling - for fgroup in self.fieldgroup: - for name, field in fgroup.items(): - if field.transient or not field.get_value(): - continue - attrs += "\t\t<" + name + ">" + \ - field.get_value() + "\n" - - # Special Fields - if self.fieldgroup[1]['power_on'].get_value() is 'Y': - attrs += "\t\t\n" - - if self.fieldgroup[1]['uses_bm'].get_value() is 'Y': - attrs += "\t\tbmc\n" - - return "\t\n" + attrs + "\t\n" - - def validate(self): - if self.fieldgroup[0]['personality'].get_value() == "compute" and not \ - utils.is_valid_hostname( - self.fieldgroup[0]['hostname'].get_value()): - raise exceptions.ValidateFail( - "Hostname %s is not valid" % - self.fieldgroup[0]['hostname'].get_value()) - - if not utils.is_valid_mac(self.fieldgroup[0]['mgmt_mac'].get_value()): - raise exceptions.ValidateFail( - "Management MAC address %s is not valid" % - self.fieldgroup[0]['mgmt_mac'].get_value()) - - ip = self.fieldgroup[0]['mgmt_ip'].get_value() - if ip: - try: - netaddr.IPAddress(ip) - except Exception: - raise exceptions.ValidateFail( - "Management IP address %s is not valid" % ip) - - if self.fieldgroup[1]['uses_bm'].get_value() == 'Y': - ip = self.fieldgroup[1]['bm_ip'].get_value() - if ip: - try: - netaddr.IPAddress(ip) - except Exception: - raise exceptions.ValidateFail( - "Board Management IP address %s is not valid" % ip) - - else: - raise exceptions.ValidateFail( - "Board Management IP is not specified. " - "External Board Management Network requires Board " - "Management IP address.") - - def on_change(self, event): - on_change(self, self.fieldgroup[1], event) - - def set_field(self, name, value): - for fgroup in self.fieldgroup: - for fname, field in fgroup.items(): - if fname == name: - field.set_value(value) - - -class HostBook(wx.Listbook): - def __init__(self, parent): - wx.Listbook.__init__(self, parent, style=wx.BK_DEFAULT) - - self.parent = parent - self.Layout() - # Add a starting host - self.new_page() - - self.Bind(wx.EVT_LISTBOOK_PAGE_CHANGED, self.on_changed) - self.Bind(wx.EVT_LISTBOOK_PAGE_CHANGING, self.on_changing) - - def on_changed(self, event): - event.Skip() - - def on_changing(self, event): - # Trigger page validation before leaving - if BULK_ADDING: - event.Skip() - return - index = self.GetSelection() - try: - if index != -1: - self.GetPage(index).validate() - except Exception as ex: - wx.LogError("Error on page: " + ex.message) - event.Veto() - return - event.Skip() - - def new_page(self, hostname=None): - new_page = HostPage(self) - self.AddPage(new_page, hostname or self.get_next_hostname()) - self.SetSelection(self.GetPageCount() - 1) - return new_page - - def get_next_hostname(self, suggest=None): - prefix = "compute-" - new_suggest = suggest or 0 - - for existing in range(self.GetPageCount()): - if prefix + str(new_suggest) in self.GetPageText(existing): - new_suggest = self.get_next_hostname(suggest=new_suggest + 1) - - if suggest: - prefix = "" - return prefix + str(new_suggest) - - def to_xml(self): - """Create the complete XML and allow user to save - """ - xml = "\n" \ - "\n" - for index in range(self.GetPageCount()): - try: - xml += self.GetPage(index).to_xml() - except Exception as ex: - wx.LogError("Error on page number %s: %s" % - (index + 1, ex.message)) - return - xml += "" - - writer = wx.FileDialog(self, - message="Save Host XML File", - defaultDir=filedir or "", - defaultFile=filename or "TiS_hosts.xml", - wildcard="XML file (*.xml)|*.xml", - style=wx.FD_SAVE, - ) - - if writer.ShowModal() == wx.ID_CANCEL: - return - - # Write the XML file to disk - try: - with open(writer.GetPath(), "wb") as f: - f.write(xml.encode('utf-8')) - except IOError: - wx.LogError("Error writing hosts xml file '%s'." % - writer.GetPath()) - - -class HostGUI(wx.Frame): - def __init__(self): - wx.Frame.__init__(self, None, wx.ID_ANY, - "Titanium Cloud Host File Creator v" + TiS_VERSION, - size=WINDOW_SIZE) - self.panel = wx.Panel(self) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.book = HostBook(self.panel) - self.sizer.Add(self.book, 1, wx.ALL | wx.EXPAND, 5) - self.panel.SetSizer(self.sizer) - set_icons(self) - - menu_bar = wx.MenuBar() - - # File - file_menu = wx.Menu() - import_item = wx.MenuItem(file_menu, IMPORT_ID, '&Import') - file_menu.AppendItem(import_item) - export_item = wx.MenuItem(file_menu, EXPORT_ID, '&Export') - file_menu.AppendItem(export_item) - menu_bar.Append(file_menu, '&File') - self.Bind(wx.EVT_MENU, self.on_import, id=IMPORT_ID) - self.Bind(wx.EVT_MENU, self.on_export, id=EXPORT_ID) - - self.SetMenuBar(menu_bar) - self.Layout() - self.SetMinSize(WINDOW_SIZE) - self.Show() - - def on_import(self, e): - global BULK_ADDING - try: - BULK_ADDING = True - msg = "" - - reader = wx.FileDialog(self, - "Import Existing Titanium Cloud Host File", - "", "", "XML file (*.xml)|*.xml", - wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - - if reader.ShowModal() == wx.ID_CANCEL: - return - - # Read in the config file - try: - with open(reader.GetPath(), 'rb') as f: - contents = f.read() - root = ET.fromstring(contents) - except Exception as ex: - wx.LogError("Cannot parse host file, Error: %s." % ex) - return - - # Check version of host file - if root.get('version', "") != TiS_VERSION: - msg += "Warning: This file was created using tools for a " \ - "different version of Titanium Cloud than this tool " \ - "was designed for (" + TiS_VERSION + ")" - - for idx, xmlhost in enumerate(root.findall('host')): - hostname = None - name_elem = xmlhost.find('hostname') - if name_elem is not None: - hostname = name_elem.text - new_host = self.book.new_page() - self.book.GetSelection() - try: - for attr in HOST_XML_ATTRIBUTES: - elem = xmlhost.find(attr) - if elem is not None and elem.text: - # Enable and display bm section if used - if attr == 'bm_type' and elem.text: - new_host.set_field("uses_bm", "Y") - handle_sub_show( - new_host.fieldgroup[1], - new_host.fieldgroup[1]['uses_bm'].shows, - True) - new_host.Layout() - - # Basic field setting - new_host.set_field(attr, elem.text) - - # Additional functionality for special fields - if attr == 'personality': - # Update hostname visibility and page title - new_host.on_personality(None, elem.text) - - # Special handling for presence of power_on element - if attr == 'power_on' and elem is not None: - new_host.set_field(attr, "Y") - - new_host.validate() - except Exception as ex: - if msg: - msg += "\n" - msg += "Warning: Added host %s has a validation error, " \ - "reason: %s" % \ - (hostname or ("with index " + str(idx)), - ex.message) - # No longer delete hosts with validation errors, - # The user can fix them up before exporting - # self.book.DeletePage(new_index) - - if msg: - wx.LogWarning(msg) - finally: - BULK_ADDING = False - self.Layout() - - def on_export(self, e): - # Do a validation of current page first - index = self.book.GetSelection() - try: - if index != -1: - self.book.GetPage(index).validate() - except Exception as ex: - wx.LogError("Error on page: " + ex.message) - return - - # Check for hostname conflicts - hostnames = [] - for existing in range(self.book.GetPageCount()): - hostname = self.book.GetPage( - existing).fieldgroup[0]['hostname'].get_value() - if hostname in hostnames: - wx.LogError("Cannot export, duplicate hostname '%s'" % - hostname) - return - # Ignore multiple None hostnames - elif hostname: - hostnames.append(hostname) - - self.book.to_xml() - - -def main(): - app = wx.App(0) # Start the application - HostGUI() - app.MainLoop() - - -if __name__ == '__main__': - main() diff --git a/configutilities/configutilities/configutilities/setup.py b/configutilities/configutilities/configutilities/setup.py deleted file mode 100755 index b946b6a7a8..0000000000 --- a/configutilities/configutilities/configutilities/setup.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Copyright (c) 2016-2017 Wind River Systems, Inc. - -SPDX-License-Identifier: Apache-2.0 - -""" - -from setuptools import setup -from setuptools import find_packages - -setup( - name='wrs-configutility', - description='Titanium Cloud Configuration Utility', - version='3.1.0', - license='Apache-2.0', - platforms=['any'], - provides=['configutilities'], - packages=find_packages(), - install_requires=['netaddr>=0.7.14', 'six'], - package_data={}, - include_package_data=False, - entry_points={ - 'gui_scripts': [ - 'config_gui = configutilities.configgui:main', - ], - 'console_scripts': [ - 'config_validator = configutilities.config_validator:main' - ], - } -) diff --git a/configutilities/configutilities/favicon.ico b/configutilities/configutilities/favicon.ico deleted file mode 100755 index 3820c51ecf..0000000000 Binary files a/configutilities/configutilities/favicon.ico and /dev/null differ diff --git a/configutilities/configutilities/pylint.rc b/configutilities/configutilities/pylint.rc deleted file mode 100755 index 5c51c4c3ba..0000000000 --- a/configutilities/configutilities/pylint.rc +++ /dev/null @@ -1,233 +0,0 @@ -[MASTER] -# Specify a configuration file. -rcfile=pylint.rc - -# Python code to execute, usually for sys.path manipulation such as pygtk.require(). -#init-hook= - -# Add files or directories to the blacklist. They should be base names, not paths. -ignore=tests - -# Pickle collected data for later comparisons. -persistent=yes - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - - -[MESSAGES CONTROL] -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time. -#enable= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). -# https://pylint.readthedocs.io/en/latest/user_guide/output.html#source-code-analysis-section -# We are disabling (C)onvention -# We are disabling (R)efactor -# The following warnings should be fixed: -# fixme (todo, xxx, fixme) -# W0102: dangerous-default-value -# W0106: expression-not-assigned -# W0107: unnecessary-pass -# W0201: attribute-defined-outside-init -# W0231: super-init-not-called -# W0235: useless-super-delegation -# W0311: bad-indentation -# W0603: global-statement -# W0611: unused-import -# W0612: unused-variable -# W0613: unused-argument -# W0622: redefined-builtin -# W0703: broad-except -# W1401: anomalous-backslash-in-string -# E0401: import-error -# E1101: no-member -disable=C, R, fixme, W0102, W0106, W0107, W0201, W0231, W0235, W0311, - W0603, W0611, W0612, W0613, W0622, W0703, W1401, E0401, E1101 - -[REPORTS] -# Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html -output-format=text - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". -files-output=no - -# Tells whether to display a full report or only the messages -reports=no - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - - -[SIMILARITIES] -# Minimum lines number of a similarity. -min-similarity-lines=4 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - - -[FORMAT] -# Maximum number of characters on a single line. -max-line-length=85 - -# Maximum number of lines in a module -max-module-lines=1000 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 tab). -indent-string=' ' - - -[TYPECHECK] -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# List of classes names for which member attributes should not be checked -# (useful for classes with attributes dynamically set). -ignored-classes=SQLObject - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E0201 when accessed. Python regular -# expressions are accepted. -generated-members=REQUEST,acl_users,aq_parent - - -[BASIC] -# List of builtins function names that should not be used, separated by a comma -bad-functions=map,filter,apply,input - -# Regular expression which should only match correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression which should only match correct module level names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression which should only match correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression which should only match correct function names -function-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct method names -method-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct instance attribute names -attr-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match correct list comprehension / -# generator expression variable names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Regular expression which should only match functions or classes name which do -# not require a docstring -no-docstring-rgx=__.*__ - - -[MISCELLANEOUS] -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -[VARIABLES] -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching the beginning of the name of dummy variables -# (i.e. not used). -dummy-variables-rgx=_|dummy - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - - -[IMPORTS] -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,string,TERMIOS,Bastion,rexec - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - - -[DESIGN] -# Maximum number of arguments for function / method -max-args=5 - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.* - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of branch for function / method body -max-branchs=12 - -# Maximum number of statements in function / method body -max-statements=50 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - - -[CLASSES] -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - - -[EXCEPTIONS] -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/configutilities/configutilities/setup.py b/configutilities/configutilities/setup.py deleted file mode 100755 index 9ac7b4cd7d..0000000000 --- a/configutilities/configutilities/setup.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Copyright (c) 2016 Wind River Systems, Inc. - -SPDX-License-Identifier: Apache-2.0 - -""" - -from setuptools import setup -from setuptools import find_packages - -setup( - name='configutilities', - description='Configuration File Validator', - version='3.1.0', - license='Apache-2.0', - platforms=['any'], - provides=['configutilities'], - packages=find_packages(), - install_requires=['netaddr>=0.7.14'], - package_data={}, - include_package_data=False, - entry_points={ - 'console_scripts': [ - 'config_validator = configutilities.config_validator:main', - ], - } -) diff --git a/configutilities/configutilities/test-requirements.txt b/configutilities/configutilities/test-requirements.txt deleted file mode 100644 index e069914668..0000000000 --- a/configutilities/configutilities/test-requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -# 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 diff --git a/configutilities/configutilities/tox.ini b/configutilities/configutilities/tox.ini deleted file mode 100644 index f9ac97717c..0000000000 --- a/configutilities/configutilities/tox.ini +++ /dev/null @@ -1,46 +0,0 @@ -# Tox (http://tox.testrun.org/) is a tool for running tests -# in multiple virtualenvs. This configuration file will run the -# test suite on all supported python versions. To use it, "pip install tox" -# and then run "tox" from this directory. - -[tox] -envlist = flake8,pylint -# Tox does not work if the path to the workdir is too long, so move it to /tmp -toxworkdir = /tmp/{env:USER}_ccutiltox -stxdir = {toxinidir}/../../.. - - -[testenv] -whitelist_externals = find -install_command = pip install --no-cache-dir {opts} {packages} - -[testenv:venv] -commands = {posargs} - -[testenv:flake8] -basepython = python2.7 -deps = -r{toxinidir}/test-requirements.txt -commands = flake8 {posargs} - -# hacking pulls in flake8 2.5.5 which does not support parsing multi-line ignore list -# H series are hacking -# H102: Apache 2.0 license header not found -# H104: File contains nothing but comments -# H306: imports not in alphabetical order -# H401: docstring should not start with a space -# H403: multi line docstrings should end on a new line -# H404: multi line docstring should start without a leading new line -# H405: multi line docstring summary not separated with an empty line -[flake8] -ignore = H102,H104,H306,H401,H403,H404,H405 -exclude = dist,build - -[testenv:pylint] -basepython = python3 -sitepackages = False - -deps = -r{toxinidir}/test-requirements.txt - -e{[tox]stxdir}/stx-update/tsconfig/tsconfig - pylint -commands = - pylint {posargs} configutilities --rcfile=./pylint.rc diff --git a/controllerconfig/centos/build_srpm.data b/controllerconfig/centos/build_srpm.data index 8a80236ea8..04bab29441 100755 --- a/controllerconfig/centos/build_srpm.data +++ b/controllerconfig/centos/build_srpm.data @@ -1,2 +1,2 @@ SRC_DIR="controllerconfig" -TIS_PATCH_VER=150 +TIS_PATCH_VER=151 diff --git a/controllerconfig/controllerconfig/controllerconfig/__init__.py b/controllerconfig/controllerconfig/controllerconfig/__init__.py index 1d58fc700e..138851db64 100644 --- a/controllerconfig/controllerconfig/controllerconfig/__init__.py +++ b/controllerconfig/controllerconfig/controllerconfig/__init__.py @@ -1,5 +1,34 @@ # -# Copyright (c) 2015 Wind River Systems, Inc. +# Copyright (c) 2015-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # + +from controllerconfig.common.validator import validate # noqa: F401 +from controllerconfig.common.configobjects import Network # noqa: F401 +from controllerconfig.common.configobjects import DEFAULT_CONFIG # noqa: F401 +from controllerconfig.common.configobjects import REGION_CONFIG # noqa: F401 +from controllerconfig.common.configobjects import DEFAULT_NAMES # noqa: F401 +from controllerconfig.common.configobjects import HP_NAMES # noqa: F401 +from controllerconfig.common.configobjects import SUBCLOUD_CONFIG # noqa: F401 +from controllerconfig.common.configobjects import MGMT_TYPE # noqa: F401 +from controllerconfig.common.configobjects import INFRA_TYPE # noqa: F401 +from controllerconfig.common.configobjects import OAM_TYPE # noqa: F401 +from controllerconfig.common.configobjects import NETWORK_PREFIX_NAMES # noqa: F401 +from controllerconfig.common.configobjects import HOST_XML_ATTRIBUTES # noqa: F401 +from controllerconfig.common.configobjects import DEFAULT_DOMAIN_NAME # noqa: F401 +from controllerconfig.common.exceptions import ConfigError # noqa: F401 +from controllerconfig.common.exceptions import ConfigFail # noqa: F401 +from controllerconfig.common.exceptions import ValidateFail # noqa: F401 +from controllerconfig.utils import is_valid_vlan # noqa: F401 +from controllerconfig.utils import is_mtu_valid # noqa: F401 +from controllerconfig.utils import validate_network_str # noqa: F401 +from controllerconfig.utils import validate_address_str # noqa: F401 +from controllerconfig.utils import validate_address # noqa: F401 +from controllerconfig.utils import is_valid_url # noqa: F401 +from controllerconfig.utils import is_valid_domain_or_ip # noqa: F401 +from controllerconfig.utils import ip_version_to_string # noqa: F401 +from controllerconfig.utils import lag_mode_to_str # noqa: F401 +from controllerconfig.utils import validate_openstack_password # noqa: F401 +from controllerconfig.utils import validate_nameserver_address_str # noqa: F401 +from controllerconfig.utils import extract_openstack_password_rules_from_file # noqa: F401 diff --git a/configutilities/configutilities/configutilities/common/configobjects.py b/controllerconfig/controllerconfig/controllerconfig/common/configobjects.py similarity index 96% rename from configutilities/configutilities/configutilities/common/configobjects.py rename to controllerconfig/controllerconfig/controllerconfig/common/configobjects.py index 003d73db2a..1866a7c996 100644 --- a/configutilities/configutilities/configutilities/common/configobjects.py +++ b/controllerconfig/controllerconfig/controllerconfig/common/configobjects.py @@ -1,17 +1,17 @@ """ -Copyright (c) 2015-2016 Wind River Systems, Inc. +Copyright (c) 2015-2019 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 """ from netaddr import IPRange -from configutilities.common.exceptions import ConfigFail -from configutilities.common.exceptions import ValidateFail -from configutilities.common.utils import is_mtu_valid -from configutilities.common.utils import is_valid_vlan -from configutilities.common.utils import validate_network_str -from configutilities.common.utils import validate_address_str +from controllerconfig.common.exceptions import ConfigFail +from controllerconfig.common.exceptions import ValidateFail +from controllerconfig.utils import is_mtu_valid +from controllerconfig.utils import is_valid_vlan +from controllerconfig.utils import validate_network_str +from controllerconfig.utils import validate_address_str DEFAULT_CONFIG = 0 REGION_CONFIG = 1 @@ -26,8 +26,6 @@ NETWORK_PREFIX_NAMES = [ ('CLM', 'BLS', 'CAN', 'CLUSTER') ] -# Additions to this list must be reflected in the hostfile -# generator tool (config->configutilities->hostfiletool.py) HOST_XML_ATTRIBUTES = ['hostname', 'personality', 'subfunctions', 'mgmt_mac', 'mgmt_ip', 'bm_ip', 'bm_type', 'bm_username', diff --git a/configutilities/configutilities/configutilities/common/crypt.py b/controllerconfig/controllerconfig/controllerconfig/common/crypt.py similarity index 92% rename from configutilities/configutilities/configutilities/common/crypt.py rename to controllerconfig/controllerconfig/controllerconfig/common/crypt.py index c90bafc946..ce53d73f80 100644 --- a/configutilities/configutilities/configutilities/common/crypt.py +++ b/controllerconfig/controllerconfig/controllerconfig/common/crypt.py @@ -12,6 +12,11 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +# +# Copyright (c) 2019 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# """ Routines for URL-safe encrypting/decrypting @@ -34,20 +39,19 @@ from six.moves import range def urlsafe_encrypt(key, plaintext, blocksize=16): - """ - Encrypts plaintext. Resulting ciphertext will contain URL-safe characters. + """Encrypts plaintext. + + Resulting ciphertext will contain URL-safe characters. If plaintext is Unicode, encode it to UTF-8 before encryption. :param key: AES secret key :param plaintext: Input text to be encrypted :param blocksize: Non-zero integer multiple of AES blocksize in bytes (16) - :returns: Resulting ciphertext """ + def pad(text): - """ - Pads text to be encrypted - """ + """Pads text to be encrypted""" pad_length = (blocksize - len(text) % blocksize) # NOTE(rosmaita): I know this looks stupid, but we can't just # use os.urandom() to get the bytes because we use char(0) as @@ -74,8 +78,8 @@ def urlsafe_encrypt(key, plaintext, blocksize=16): def urlsafe_decrypt(key, ciphertext): - """ - Decrypts URL-safe base64 encoded ciphertext. + """Decrypts URL-safe base64 encoded ciphertext. + On Python 3, the result is decoded from UTF-8. :param key: AES secret key diff --git a/controllerconfig/controllerconfig/controllerconfig/common/dcmanager.py b/controllerconfig/controllerconfig/controllerconfig/common/dcmanager.py index 02ef188742..c88c69cc1e 100755 --- a/controllerconfig/controllerconfig/controllerconfig/common/dcmanager.py +++ b/controllerconfig/controllerconfig/controllerconfig/common/dcmanager.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2017 Wind River Systems, Inc. +# Copyright (c) 2017-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -11,7 +11,7 @@ DC Manager Interactions from controllerconfig.common import log from Crypto.Hash import MD5 -from configutilities.common import crypt +from controllerconfig.common import crypt import json diff --git a/controllerconfig/controllerconfig/controllerconfig/common/exceptions.py b/controllerconfig/controllerconfig/controllerconfig/common/exceptions.py index afbcd3bb33..66a4b7e1c3 100644 --- a/controllerconfig/controllerconfig/controllerconfig/common/exceptions.py +++ b/controllerconfig/controllerconfig/controllerconfig/common/exceptions.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2014 Wind River Systems, Inc. +# Copyright (c) 2014-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -8,7 +8,26 @@ Configuration Errors """ -from configutilities import ConfigError + +class ConfigError(Exception): + """Base class for configuration exceptions.""" + + def __init__(self, message=None): + self.message = message + super(ConfigError, self).__init__(message) + + def __str__(self): + return self.message or "" + + +class ConfigFail(ConfigError): + """General configuration error.""" + pass + + +class ValidateFail(ConfigError): + """Validation of data failed.""" + pass class BackupFail(ConfigError): diff --git a/configutilities/configutilities/configutilities/common/validator.py b/controllerconfig/controllerconfig/controllerconfig/common/validator.py similarity index 97% rename from configutilities/configutilities/configutilities/common/validator.py rename to controllerconfig/controllerconfig/controllerconfig/common/validator.py index 69e1e33656..a27447263b 100644 --- a/configutilities/configutilities/configutilities/common/validator.py +++ b/controllerconfig/controllerconfig/controllerconfig/common/validator.py @@ -1,34 +1,34 @@ """ -Copyright (c) 2015-2017 Wind River Systems, Inc. +Copyright (c) 2015-2019 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 """ -from configutilities.common.configobjects import DEFAULT_NAMES -from configutilities.common.configobjects import NETWORK_PREFIX_NAMES -from configutilities.common.configobjects import OAM_TYPE -from configutilities.common.configobjects import MGMT_TYPE -from configutilities.common.configobjects import Network -from configutilities.common.configobjects import REGION_CONFIG -from configutilities.common.configobjects import INFRA_TYPE -from configutilities.common.configobjects import DEFAULT_DOMAIN_NAME -from configutilities.common.configobjects import HP_NAMES -from configutilities.common.configobjects import SUBCLOUD_CONFIG -from configutilities.common.configobjects import CLUSTER_TYPE +from controllerconfig.common.configobjects import DEFAULT_NAMES +from controllerconfig.common.configobjects import NETWORK_PREFIX_NAMES +from controllerconfig.common.configobjects import OAM_TYPE +from controllerconfig.common.configobjects import MGMT_TYPE +from controllerconfig.common.configobjects import Network +from controllerconfig.common.configobjects import REGION_CONFIG +from controllerconfig.common.configobjects import INFRA_TYPE +from controllerconfig.common.configobjects import DEFAULT_DOMAIN_NAME +from controllerconfig.common.configobjects import HP_NAMES +from controllerconfig.common.configobjects import SUBCLOUD_CONFIG +from controllerconfig.common.configobjects import CLUSTER_TYPE from netaddr import IPRange -from configutilities.common.utils import lag_mode_to_str -from configutilities.common.utils import validate_network_str -from configutilities.common.utils import check_network_overlap -from configutilities.common.utils import is_mtu_valid -from configutilities.common.utils import get_service -from configutilities.common.utils import get_optional -from configutilities.common.utils import validate_address_str -from configutilities.common.utils import validate_nameserver_address_str -from configutilities.common.utils import is_valid_url -from configutilities.common.utils import is_valid_domain_or_ip -from configutilities.common.utils import is_valid_bool_str -from configutilities.common.exceptions import ConfigFail -from configutilities.common.exceptions import ValidateFail +from controllerconfig.utils import lag_mode_to_str +from controllerconfig.utils import validate_network_str +from controllerconfig.utils import check_network_overlap +from controllerconfig.utils import is_mtu_valid +from controllerconfig.utils import get_service +from controllerconfig.utils import get_optional +from controllerconfig.utils import validate_address_str +from controllerconfig.utils import validate_nameserver_address_str +from controllerconfig.utils import is_valid_url +from controllerconfig.utils import is_valid_domain_or_ip +from controllerconfig.utils import is_valid_bool_str +from controllerconfig.common.exceptions import ConfigFail +from controllerconfig.common.exceptions import ValidateFail # Constants diff --git a/controllerconfig/controllerconfig/controllerconfig/config_management.py b/controllerconfig/controllerconfig/controllerconfig/config_management.py index db42355336..9cbd6972c1 100644 --- a/controllerconfig/controllerconfig/controllerconfig/config_management.py +++ b/controllerconfig/controllerconfig/controllerconfig/config_management.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2017 Wind River Systems, Inc. +Copyright (c) 2017-2019 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 @@ -13,8 +13,8 @@ import subprocess import sys import time -import configutilities.common.exceptions as cexeptions -import configutilities.common.utils as cutils +import controllerconfig.common.exceptions as exeptions +import controllerconfig.utils as utils from six.moves import input @@ -109,9 +109,9 @@ def configure_management(): continue break except (netaddr.AddrFormatError, ValueError): - print ("Invalid CIDR - " - "please enter a valid management IP address in " - "CIDR notation.") + print("Invalid CIDR - " + "please enter a valid management IP address in " + "CIDR notation.") while True: user_input = input("Enter management gateway IP address [" + @@ -127,18 +127,18 @@ def configure_management(): management_gateway_address = ip_input break except (netaddr.AddrFormatError, ValueError): - print ("Invalid address - " - "please enter a valid management gateway IP address") + print("Invalid address - " + "please enter a valid management gateway IP address") min_addresses = 8 while True: user_input = input("Enter System Controller subnet in " "CIDR notation: ") try: - system_controller_subnet = cutils.validate_network_str( + system_controller_subnet = utils.validate_network_str( user_input, min_addresses) break - except cexeptions.ValidateFail as e: + except exeptions.ValidateFail as e: print("{}".format(e)) print("Disabling non-management interfaces... ", end=' ') diff --git a/controllerconfig/controllerconfig/controllerconfig/configassistant.py b/controllerconfig/controllerconfig/controllerconfig/configassistant.py index 0b0a9ea918..5185abfc27 100644 --- a/controllerconfig/controllerconfig/controllerconfig/configassistant.py +++ b/controllerconfig/controllerconfig/controllerconfig/configassistant.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2014-2018 Wind River Systems, Inc. +Copyright (c) 2014-2019 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 @@ -20,19 +20,19 @@ import textwrap import time import pyudev -from configutilities import ConfigFail -from configutilities import ValidateFail -from configutilities import is_valid_vlan -from configutilities import is_mtu_valid -from configutilities import validate_network_str -from configutilities import validate_address_str -from configutilities import validate_address -from configutilities import ip_version_to_string -from configutilities import validate_nameserver_address_str -from configutilities import is_valid_url -from configutilities import is_valid_domain_or_ip -from configutilities import validate_openstack_password -from configutilities import DEFAULT_DOMAIN_NAME +from controllerconfig import ConfigFail +from controllerconfig import ValidateFail +from controllerconfig import is_valid_vlan +from controllerconfig import is_mtu_valid +from controllerconfig import validate_network_str +from controllerconfig import validate_address_str +from controllerconfig import validate_address +from controllerconfig import ip_version_to_string +from controllerconfig import validate_nameserver_address_str +from controllerconfig import is_valid_url +from controllerconfig import is_valid_domain_or_ip +from controllerconfig import validate_openstack_password +from controllerconfig import DEFAULT_DOMAIN_NAME from netaddr import IPNetwork from netaddr import IPAddress from netaddr import IPRange diff --git a/controllerconfig/controllerconfig/controllerconfig/regionconfig.py b/controllerconfig/controllerconfig/controllerconfig/regionconfig.py index a3cfa6cb20..930ee43d68 100755 --- a/controllerconfig/controllerconfig/controllerconfig/regionconfig.py +++ b/controllerconfig/controllerconfig/controllerconfig/regionconfig.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2015-2018 Wind River Systems, Inc. +Copyright (c) 2015-2019 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 @@ -19,16 +19,15 @@ from controllerconfig.common import constants from controllerconfig.common import log from controllerconfig.common import rest_api_utils as rutils from controllerconfig.common.exceptions import KeystoneFail -from configutilities.common import utils as cutils -from configutilities.common.configobjects import REGION_CONFIG -from configutilities.common.configobjects import SUBCLOUD_CONFIG -from configutilities import ConfigFail +from controllerconfig.common.configobjects import REGION_CONFIG +from controllerconfig.common.configobjects import SUBCLOUD_CONFIG +from controllerconfig import ConfigFail from controllerconfig.configassistant import ConfigAssistant from netaddr import IPAddress from controllerconfig.systemconfig import parse_system_config from controllerconfig.systemconfig import configure_management_interface from controllerconfig.systemconfig import create_cgcs_config_file -from configutilities import DEFAULT_DOMAIN_NAME +from controllerconfig import DEFAULT_DOMAIN_NAME # Temporary file for building cgcs_config TEMP_CGCS_CONFIG_FILE = "/tmp/cgcs_config" @@ -290,18 +289,18 @@ def validate_region_one_keystone_config(region_config, token, api_url, users, # Verify that region two endpoints & services match our requirements, # optionally creating missing entries - public_address = cutils.get_optional(region_config, 'CAN_NETWORK', - 'CAN_IP_START_ADDRESS') + public_address = utils.get_optional(region_config, 'CAN_NETWORK', + 'CAN_IP_START_ADDRESS') if not public_address: - public_address = cutils.get_optional(region_config, 'CAN_NETWORK', - 'CAN_IP_FLOATING_ADDRESS') + public_address = utils.get_optional(region_config, 'CAN_NETWORK', + 'CAN_IP_FLOATING_ADDRESS') if not public_address: - public_address = cutils.get_optional(region_config, 'OAM_NETWORK', - 'IP_START_ADDRESS') + public_address = utils.get_optional(region_config, 'OAM_NETWORK', + 'IP_START_ADDRESS') if not public_address: # AIO-SX configuration - public_address = cutils.get_optional(region_config, 'OAM_NETWORK', - 'IP_ADDRESS') + public_address = utils.get_optional(region_config, 'OAM_NETWORK', + 'IP_ADDRESS') if not public_address: public_address = region_config.get('OAM_NETWORK', 'IP_FLOATING_ADDRESS') @@ -313,17 +312,17 @@ def validate_region_one_keystone_config(region_config, token, api_url, users, internal_address = region_config.get('MGMT_NETWORK', 'IP_START_ADDRESS') - internal_infra_address = cutils.get_optional( + internal_infra_address = utils.get_optional( region_config, 'BLS_NETWORK', 'BLS_IP_START_ADDRESS') if not internal_infra_address: - internal_infra_address = cutils.get_optional( + internal_infra_address = utils.get_optional( region_config, 'INFRA_NETWORK', 'IP_START_ADDRESS') for endpoint in expected_region_2_endpoints: - service_name = cutils.get_service(region_config, 'REGION_2_SERVICES', - endpoint[SERVICE_NAME]) - service_type = cutils.get_service(region_config, 'REGION_2_SERVICES', - endpoint[SERVICE_TYPE]) + service_name = utils.get_service(region_config, 'REGION_2_SERVICES', + endpoint[SERVICE_NAME]) + service_type = utils.get_service(region_config, 'REGION_2_SERVICES', + endpoint[SERVICE_TYPE]) service_id = services.get_service_id(service_name, service_type) expected_public_url = endpoint[PUBLIC_URL].format(public_address) diff --git a/controllerconfig/controllerconfig/controllerconfig/systemconfig.py b/controllerconfig/controllerconfig/controllerconfig/systemconfig.py index 17905f7e78..2ca27bbc11 100644 --- a/controllerconfig/controllerconfig/controllerconfig/systemconfig.py +++ b/controllerconfig/controllerconfig/controllerconfig/systemconfig.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2015-2017 Wind River Systems, Inc. +Copyright (c) 2015-2019 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 @@ -18,16 +18,16 @@ from controllerconfig.common.exceptions import BackupFail from controllerconfig.common.exceptions import RestoreFail from controllerconfig.common.exceptions import UserQuit from controllerconfig.common.exceptions import CloneFail -from configutilities import lag_mode_to_str -from configutilities import Network -from configutilities import validate -from configutilities import ConfigFail -from configutilities import DEFAULT_CONFIG -from configutilities import REGION_CONFIG -from configutilities import SUBCLOUD_CONFIG -from configutilities import MGMT_TYPE -from configutilities import HP_NAMES -from configutilities import DEFAULT_NAMES +from controllerconfig import lag_mode_to_str +from controllerconfig import Network +from controllerconfig import validate +from controllerconfig import ConfigFail +from controllerconfig import DEFAULT_CONFIG +from controllerconfig import REGION_CONFIG +from controllerconfig import SUBCLOUD_CONFIG +from controllerconfig import MGMT_TYPE +from controllerconfig import HP_NAMES +from controllerconfig import DEFAULT_NAMES from controllerconfig.configassistant import ConfigAssistant from controllerconfig import backup_restore from controllerconfig import utils diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/test_region_config.py b/controllerconfig/controllerconfig/controllerconfig/tests/test_region_config.py index 5b263c1138..5e0531fae4 100644 --- a/controllerconfig/controllerconfig/controllerconfig/tests/test_region_config.py +++ b/controllerconfig/controllerconfig/controllerconfig/tests/test_region_config.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2014-2017 Wind River Systems, Inc. +Copyright (c) 2014-2019 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 @@ -17,9 +17,9 @@ import pytest import shutil import sys -import configutilities.common.exceptions as exceptions -from configutilities import REGION_CONFIG -from configutilities import validate +import controllerconfig.common.exceptions as exceptions +from controllerconfig import REGION_CONFIG +from controllerconfig import validate import controllerconfig.common.keystone as keystone from controllerconfig.tests import test_answerfile diff --git a/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py b/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py index 2bda2825c9..0798fcdd46 100644 --- a/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py +++ b/controllerconfig/controllerconfig/controllerconfig/tests/test_system_config.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2014, 2017 Wind River Systems, Inc. +Copyright (c) 2014-2019 Wind River Systems, Inc. SPDX-License-Identifier: Apache-2.0 @@ -11,9 +11,9 @@ import os import pytest import sys -import configutilities.common.exceptions as exceptions -from configutilities import validate -from configutilities import DEFAULT_CONFIG +import controllerconfig.common.exceptions as exceptions +from controllerconfig import validate +from controllerconfig import DEFAULT_CONFIG sys.modules['fm_core'] = mock.Mock() diff --git a/controllerconfig/controllerconfig/controllerconfig/upgrades/utils.py b/controllerconfig/controllerconfig/controllerconfig/upgrades/utils.py index bca695478d..a478a5ad47 100644 --- a/controllerconfig/controllerconfig/controllerconfig/upgrades/utils.py +++ b/controllerconfig/controllerconfig/controllerconfig/upgrades/utils.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2016 Wind River Systems, Inc. +# Copyright (c) 2016-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -21,7 +21,7 @@ import yaml from tsconfig.tsconfig import SW_VERSION from tsconfig.tsconfig import PLATFORM_PATH -from configutilities import DEFAULT_DOMAIN_NAME +from controllerconfig import DEFAULT_DOMAIN_NAME from controllerconfig import utils as cutils from controllerconfig.common import log from controllerconfig.common import constants diff --git a/controllerconfig/controllerconfig/controllerconfig/utils.py b/controllerconfig/controllerconfig/controllerconfig/utils.py index 7bfb522a99..c29437b3cb 100644 --- a/controllerconfig/controllerconfig/controllerconfig/utils.py +++ b/controllerconfig/controllerconfig/controllerconfig/utils.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2014-2018 Wind River Systems, Inc. +# Copyright (c) 2014-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -19,13 +19,17 @@ import time import sys import yaml +from six.moves import configparser +import re +import six + import netaddr from tsconfig import tsconfig -from configutilities.common.utils import is_valid_mac from sysinv.common import constants as sysinv_constants from controllerconfig.common import constants from controllerconfig.common import log +from controllerconfig.common.exceptions import ValidateFail LOOPBACK_IFNAME = 'lo' @@ -40,6 +44,21 @@ LOG = log.get_logger(__name__) DEVNULL = open(os.devnull, 'w') +EXPECTED_SERVICE_NAME_AND_TYPE = ( + {"KEYSTONE_SERVICE_NAME": "keystone", + "KEYSTONE_SERVICE_TYPE": "identity", + "SYSINV_SERVICE_NAME": "sysinv", + "SYSINV_SERVICE_TYPE": "platform", + "PATCHING_SERVICE_NAME": "patching", + "PATCHING_SERVICE_TYPE": "patching", + "NFV_SERVICE_NAME": "vim", + "NFV_SERVICE_TYPE": "nfv", + "FM_SERVICE_NAME": "fm", + "FM_SERVICE_TYPE": "faultmanagement", + "BARBICAN_SERVICE_NAME": "barbican", + "BARBICAN_SERVICE_TYPE": "key-manager", + }) + def filesystem_get_free_space(path): """ Get Free space of directory """ @@ -283,21 +302,6 @@ def validate_and_normalize_mac(address): return address.lower() -def is_valid_ipv4(address): - """Verify that address represents a valid IPv4 address.""" - try: - return netaddr.valid_ipv4(address) - except Exception: - return False - - -def is_valid_ipv6(address): - try: - return netaddr.valid_ipv6(address) - except Exception: - return False - - def is_valid_ip(address): if not is_valid_ipv4(address): return is_valid_ipv6(address) @@ -895,3 +899,318 @@ def is_ssh_parent(): return False except subprocess.CalledProcessError: return False + + +def is_valid_vlan(vlan): + """Determine whether vlan is valid.""" + try: + if 0 < int(vlan) < 4095: + return True + else: + return False + except (ValueError, TypeError): + return False + + +def is_mtu_valid(mtu): + """Determine whether a mtu is valid.""" + try: + if int(mtu) < 576: + return False + elif int(mtu) > 9216: + return False + else: + return True + except (ValueError, TypeError): + return False + + +def is_valid_hostname(hostname): + """Determine whether a hostname is valid as per RFC 1123.""" + + # Maximum length of 255 + if not hostname or len(hostname) > 255: + return False + # Allow a single dot on the right hand side + if hostname[-1] == ".": + hostname = hostname[:-1] + # Create a regex to ensure: + # - hostname does not begin or end with a dash + # - each segment is 1 to 63 characters long + # - valid characters are A-Z (any case) and 0-9 + valid_re = re.compile("(?!-)[A-Z\d-]{1,63}(?