Merge "Remove wrs-configutilities SDK Module"
This commit is contained in:
commit
a5c6b508b1
26
.zuul.yaml
26
.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
|
||||
|
@ -10,9 +10,6 @@ workerconfig
|
||||
workerconfig-standalone
|
||||
workerconfig-subfunction
|
||||
|
||||
# configutilities
|
||||
configutilities
|
||||
|
||||
# controllerconfig
|
||||
controllerconfig
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
cgts-client-wheels
|
||||
configutilities-wheels
|
||||
controllerconfig-wheels
|
||||
sysinv-wheels
|
||||
|
@ -1,7 +1,6 @@
|
||||
kubernetes/applications/stx-openstack/stx-openstack-helm
|
||||
worker-utils
|
||||
workerconfig
|
||||
configutilities
|
||||
controllerconfig
|
||||
storageconfig
|
||||
sysinv/cgts-client
|
||||
|
@ -1,4 +1,3 @@
|
||||
cgts-client-wheels
|
||||
configutilities-wheels
|
||||
controllerconfig-wheels
|
||||
sysinv-wheels
|
||||
|
6
configutilities/.gitignore
vendored
6
configutilities/.gitignore
vendored
@ -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
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
SRC_DIR="configutilities"
|
||||
COPY_LIST="$SRC_DIR/LICENSE"
|
||||
TIS_PATCH_VER=2
|
@ -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 <info@windriver.com>
|
||||
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/*
|
@ -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.
|
@ -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.
|
@ -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 <filename>
|
||||
|
||||
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.
|
||||
|
@ -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
|
@ -1,5 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2015 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
@ -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
|
@ -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, '')
|
@ -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}(?<!-)$", re.IGNORECASE)
|
||||
return all(valid_re.match(x) for x in hostname.split("."))
|
||||
|
||||
|
||||
def is_valid_mac(mac):
|
||||
"""Verify the format of a MAC addres."""
|
||||
if not mac:
|
||||
return False
|
||||
m = "[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$"
|
||||
return isinstance(mac, six.string_types) and re.match(m, mac.lower())
|
||||
|
||||
|
||||
def validate_network_str(network_str, minimum_size,
|
||||
existing_networks=None, multicast=False):
|
||||
"""Determine whether a network is valid."""
|
||||
try:
|
||||
network = IPNetwork(network_str)
|
||||
if network.ip != network.network:
|
||||
raise ValidateFail("Invalid network address")
|
||||
elif network.size < minimum_size:
|
||||
raise ValidateFail("Subnet too small - must have at least %d "
|
||||
"addresses" % minimum_size)
|
||||
elif network.version == 6 and network.prefixlen < 64:
|
||||
raise ValidateFail("IPv6 minimum prefix length is 64")
|
||||
elif existing_networks:
|
||||
if any(network.ip in subnet for subnet in existing_networks):
|
||||
raise ValidateFail("Subnet overlaps with another "
|
||||
"configured subnet")
|
||||
elif multicast and not network.is_multicast():
|
||||
raise ValidateFail("Invalid subnet - must be multicast")
|
||||
return network
|
||||
except AddrFormatError:
|
||||
raise ValidateFail(
|
||||
"Invalid subnet - not a valid IP subnet")
|
||||
|
||||
|
||||
def is_valid_filename(filename):
|
||||
return '\0' not in filename
|
||||
|
||||
|
||||
def is_valid_by_path(filename):
|
||||
return "/dev/disk/by-path" in filename and "-part" not in filename
|
||||
|
||||
|
||||
def is_valid_url(url_str):
|
||||
# Django URL validation patterns
|
||||
r = re.compile(
|
||||
r'^(?:http|ftp)s?://' # http:// or https://
|
||||
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)' # domain...
|
||||
r'+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
|
||||
r'localhost|' # localhost...
|
||||
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
|
||||
r'(?::\d+)?' # optional port
|
||||
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
||||
|
||||
url = r.match(url_str)
|
||||
if url:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def is_valid_domain(url_str):
|
||||
r = re.compile(
|
||||
r'^(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)' # domain...
|
||||
r'+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
|
||||
r'[A-Za-z0-9-_]*)' # localhost, hostname
|
||||
r'(?::\d+)?' # optional port
|
||||
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
||||
|
||||
url = r.match(url_str)
|
||||
if url:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def is_valid_ipv4(address):
|
||||
"""Verify that address represents a valid IPv4 address."""
|
||||
try:
|
||||
return valid_ipv4(address)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def is_valid_ipv6(address):
|
||||
try:
|
||||
return valid_ipv6(address)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def is_valid_domain_or_ip(url_str):
|
||||
if url_str:
|
||||
if is_valid_domain(url_str):
|
||||
return True
|
||||
ip_with_port = url_str.split(':')
|
||||
if len(ip_with_port) <= 2:
|
||||
# check ipv4 or ipv4 with port
|
||||
return is_valid_ipv4(ip_with_port[0])
|
||||
else:
|
||||
# check ipv6 with port
|
||||
if '[' in url_str:
|
||||
try:
|
||||
bkt_idx = url_str.index(']')
|
||||
if bkt_idx + 1 == len(url_str):
|
||||
# brackets without port
|
||||
return False
|
||||
else:
|
||||
return is_valid_ipv6(url_str[1:bkt_idx])
|
||||
except Exception:
|
||||
return False
|
||||
else:
|
||||
# check ipv6 without port
|
||||
return is_valid_ipv6(url_str)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def is_valid_bool_str(val):
|
||||
"""Check if the provided string is a valid bool string or not."""
|
||||
boolstrs = ('true', 'false')
|
||||
return str(val).lower() in boolstrs
|
||||
|
||||
|
||||
def validate_address_str(ip_address_str, network):
|
||||
"""Determine whether an address is valid."""
|
||||
try:
|
||||
ip_address = IPAddress(ip_address_str)
|
||||
if ip_address.version != network.version:
|
||||
msg = ("Invalid IP version - must match network version " +
|
||||
ip_version_to_string(network.version))
|
||||
raise ValidateFail(msg)
|
||||
elif ip_address == network:
|
||||
raise ValidateFail("Cannot use network address")
|
||||
elif ip_address == network.broadcast:
|
||||
raise ValidateFail("Cannot use broadcast address")
|
||||
elif ip_address not in network:
|
||||
raise ValidateFail(
|
||||
"Address must be in subnet %s" % str(network))
|
||||
return ip_address
|
||||
except AddrFormatError:
|
||||
raise ValidateFail(
|
||||
"Invalid address - not a valid IP address")
|
||||
|
||||
|
||||
def ip_version_to_string(ip_version):
|
||||
"""Determine whether a nameserver address is valid."""
|
||||
if ip_version == 4:
|
||||
return "IPv4"
|
||||
elif ip_version == 6:
|
||||
return "IPv6"
|
||||
else:
|
||||
return "IP"
|
||||
|
||||
|
||||
def validate_nameserver_address_str(ip_address_str, subnet_version=None):
|
||||
"""Determine whether a nameserver address is valid."""
|
||||
try:
|
||||
ip_address = IPAddress(ip_address_str)
|
||||
if subnet_version is not None and ip_address.version != subnet_version:
|
||||
msg = ("Invalid IP version - must match OAM subnet version " +
|
||||
ip_version_to_string(subnet_version))
|
||||
raise ValidateFail(msg)
|
||||
return ip_address
|
||||
except AddrFormatError:
|
||||
msg = "Invalid address - "
|
||||
"not a valid %s address" % ip_version_to_string(subnet_version)
|
||||
raise ValidateFail(msg)
|
||||
|
||||
|
||||
def validate_address(ip_address, network):
|
||||
"""Determine whether an address is valid."""
|
||||
if ip_address.version != network.version:
|
||||
msg = ("Invalid IP version - must match network version " +
|
||||
ip_version_to_string(network.version))
|
||||
raise ValidateFail(msg)
|
||||
elif ip_address == network:
|
||||
raise ValidateFail("Cannot use network address")
|
||||
elif ip_address == network.broadcast:
|
||||
raise ValidateFail("Cannot use broadcast address")
|
||||
elif ip_address not in network:
|
||||
raise ValidateFail("Address must be in subnet %s" % str(network))
|
||||
|
||||
|
||||
def check_network_overlap(new_network, configured_networks):
|
||||
""" Validate that new_network does not overlap any configured_networks.
|
||||
"""
|
||||
if any(new_network.ip in subnet for subnet in
|
||||
configured_networks):
|
||||
raise ValidateFail(
|
||||
"Subnet %s overlaps with another configured subnet" % new_network)
|
||||
|
||||
|
||||
def lag_mode_to_str(lag_mode):
|
||||
if lag_mode == 0:
|
||||
return "balance-rr"
|
||||
if lag_mode == 1:
|
||||
return "active-backup"
|
||||
elif lag_mode == 2:
|
||||
return "balance-xor"
|
||||
elif lag_mode == 3:
|
||||
return "broadcast"
|
||||
elif lag_mode == 4:
|
||||
return "802.3ad"
|
||||
elif lag_mode == 5:
|
||||
return "balance-tlb"
|
||||
elif lag_mode == 6:
|
||||
return "balance-alb"
|
||||
else:
|
||||
raise Exception(
|
||||
"Invalid LAG_MODE value of %d. Valid values: 0-6" % lag_mode)
|
||||
|
||||
|
||||
def validate_openstack_password(password, rules_file,
|
||||
section="security_compliance"):
|
||||
try:
|
||||
config = configparser.RawConfigParser()
|
||||
parsed_config = config.read(rules_file)
|
||||
if not parsed_config:
|
||||
msg = ("Cannot parse rules file: %s" % rules_file)
|
||||
raise Exception(msg)
|
||||
if not config.has_section(section):
|
||||
msg = ("Required section '%s' not found in rules file" % section)
|
||||
raise Exception(msg)
|
||||
|
||||
password_regex = get_optional(config, section, 'password_regex')
|
||||
password_regex_description = get_optional(config, section,
|
||||
'password_regex_description')
|
||||
|
||||
if not password_regex:
|
||||
msg = ("Required option 'password_regex' not found in "
|
||||
"rule file: %s" % rules_file)
|
||||
raise Exception(msg)
|
||||
# Even if regex_description is not found, we will proceed
|
||||
# and give a generic failure warning instead
|
||||
if not password_regex_description:
|
||||
password_regex_description = ("Password does not meet "
|
||||
"complexity criteria")
|
||||
|
||||
if not isinstance(password, six.string_types):
|
||||
msg = ("Password must be a string type")
|
||||
raise Exception(msg)
|
||||
try:
|
||||
# config parser would read in the string as a literal
|
||||
# representation which would fail regex matching
|
||||
password_regex = password_regex.strip('"')
|
||||
if not re.match(password_regex, password):
|
||||
return False, password_regex_description
|
||||
except re.error:
|
||||
msg = ("Unable to validate password due to invalid "
|
||||
"complexity criteria ('password_regex')")
|
||||
raise Exception(msg)
|
||||
except Exception:
|
||||
raise Exception("Password validation failed")
|
||||
return True, ""
|
||||
|
||||
|
||||
def extract_openstack_password_rules_from_file(
|
||||
rules_file, section="security_compliance"):
|
||||
try:
|
||||
config = configparser.RawConfigParser()
|
||||
parsed_config = config.read(rules_file)
|
||||
if not parsed_config:
|
||||
msg = ("Cannot parse rules file: %s" % rules_file)
|
||||
raise Exception(msg)
|
||||
if not config.has_section(section):
|
||||
msg = ("Required section '%s' not found in rules file" % section)
|
||||
raise Exception(msg)
|
||||
|
||||
rules = config.items(section)
|
||||
if not rules:
|
||||
msg = ("section '%s' contains no configuration options" % section)
|
||||
raise Exception(msg)
|
||||
return dict(rules)
|
||||
except Exception:
|
||||
raise Exception("Failed to extract password rules from file")
|
||||
|
||||
|
||||
def get_optional(conf, section, key):
|
||||
if conf.has_option(section, key):
|
||||
return conf.get(section, key)
|
||||
return None
|
||||
|
||||
|
||||
def get_service(conf, section, key):
|
||||
if key in EXPECTED_SERVICE_NAME_AND_TYPE:
|
||||
if conf.has_option(section, key):
|
||||
value = conf.get(section, key)
|
||||
if value != EXPECTED_SERVICE_NAME_AND_TYPE[key]:
|
||||
raise ValidateFail("Unsupported %s: %s " % (key, value))
|
||||
else:
|
||||
value = EXPECTED_SERVICE_NAME_AND_TYPE[key]
|
||||
return value
|
||||
else:
|
||||
return conf.get(section, key)
|
@ -1,37 +0,0 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# This file was generated by img2py.py
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2015-2016 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
#
|
||||
# Stylized red Wind River 'W' icon
|
||||
#
|
||||
|
||||
from wx.lib.embeddedimage import PyEmbeddedImage
|
||||
|
||||
favicon = PyEmbeddedImage(
|
||||
"iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAA99J"
|
||||
"REFUWIXtls1PE2sUxn/z0Q7U0g/AXmNAUBGNxsSYGnWjQQ0YNAISY1y4kLh16T/g1qV/gwtJ"
|
||||
"JFFATbBCmuBXrhiMitGk0hpBJaQtM4Vpp+3cxXAHSltub1zggpPM4p155pznfd5zznuEv8Fk"
|
||||
"A03cyOCbBDYJ/BEE5EpqUPiP72YFmHI42bV/f0ng6uDG3BzZubmSTuW6OhzbtmEaBuloFDOd"
|
||||
"Lo3buhVHIGDhpqcxMxnLfzoaXYlnmiAICJKEoCjWWpKI37tH7MYNyOUKvQoCDbdvU3ftGnlN"
|
||||
"Y7qvj4VQqGiXgizTeOcOtVeukHr1isjly+QSCYvYdF9fEVvR5aLu6lX8ly4B4OnoQGlqIh2J"
|
||||
"FOCcTU34urqQa2uhthZ/by/qs2cW8VWmtLTgPXcOyetlcWLCDg4gL4RCJSXLfPtGzcmTyIEA"
|
||||
"SnMz7hMn0CMRe3cm4GlvR9m1y/7H096Os7mZzNevK6ICnrNncTY2kksmSQ4PF+SCKCwv1j76"
|
||||
"p0+kXr9eRol4z59HdDptx5LLhf/iRRBXCknZuRPPmTMFOSR7PPi6ugBYfPuWpcnJgiMqW4Z5"
|
||||
"XScxOGjL6T5+HGXPHszlXbkOH2bL0aOQz2PMzlo4UcTX04Pkctm7dx05wpZgEIDko0dkVbUg"
|
||||
"TlkCAqCOjpKJxQBwbN+O59Qp+5uvuxvJ5yMTizF765Z9ru5jx6g+dMiSWRDwdXcjut1kf/1i"
|
||||
"YWSkKM66jSgTiaCGw/ba29mJWFWFo6EBb2cnAOrYGPN376K9eAGA5Pfbkjt37MDb0QGA9vIl"
|
||||
"+tRUUYWsSyCfy5EcHMQ0DABcwSBV+/ZR09aG0tpKXteJDwyQVVXi/f2Y2axN1BEIUHP6NMru"
|
||||
"3WCaJIeGyJfoEesSEABtfBz982cA5Pp6/D09+Ht7ESSJpclJUs+fIwALIyPoU1MAVO3di+/C"
|
||||
"BUsJUSQTi6GOjZXslvJ6BACMmRnUp0+pPnAAgPrr1xHdbgASDx9izM9b3XJmhsSDB1QfPIjg"
|
||||
"cPDXzZs4AgEA1HCYzJoeUpECYGVyYmiIfCoFWMkoeTwYP36QHB4uxA0MYPz8aanQ2ork82Ea"
|
||||
"hiX/2i5aKQEBWHzzhqV37wrea+Ew+sePtqwCsPT+vdUJV1n6yxe08fGyl1VF13E2Hif5+LG9"
|
||||
"Ng2D+P375JeT81/LGwbx/n7yum6/WwiFML5/L+u74nkg+eSJfSMuffiAFg4XXzpY5704MWER"
|
||||
"0jS79ZYzodKxXFAUatrakP1+MtGoVfdm6V9dwSBVLS3kUinU0VHymvb7BKB4TvhdHFRQhqut"
|
||||
"kqnn/+DgD5gJNwlsEthwAv8AApOBr7T8BuQAAAAASUVORK5CYII=")
|
@ -1,103 +0,0 @@
|
||||
"""
|
||||
Copyright (c) 2015-2016 Wind River Systems, Inc.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import os
|
||||
from six.moves import configparser
|
||||
from configutilities.common.validator import validate
|
||||
from configutilities.common.configobjects import DEFAULT_CONFIG
|
||||
from configutilities.common.configobjects import REGION_CONFIG
|
||||
from configutilities.common.exceptions import ConfigFail
|
||||
from configutilities.common.exceptions import ValidateFail
|
||||
|
||||
|
||||
def parse_config(config_file):
|
||||
"""Parse system config file"""
|
||||
config = configparser.RawConfigParser()
|
||||
try:
|
||||
config.read(config_file)
|
||||
except Exception as e:
|
||||
raise ConfigFail("Error parsing system config file: %s" % e.message)
|
||||
return config
|
||||
|
||||
|
||||
def show_help():
|
||||
print("Usage: %s\n"
|
||||
"Perform validation of a given configuration file\n\n"
|
||||
"--system-config <name> Validate a system configuration file\n"
|
||||
"--region-config <name> 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")
|
File diff suppressed because it is too large
Load Diff
@ -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()
|
@ -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() + "</" + name + ">\n"
|
||||
|
||||
# Special Fields
|
||||
if self.fieldgroup[1]['power_on'].get_value() is 'Y':
|
||||
attrs += "\t\t<power_on/>\n"
|
||||
|
||||
if self.fieldgroup[1]['uses_bm'].get_value() is 'Y':
|
||||
attrs += "\t\t<bm_type>bmc</bm_type>\n"
|
||||
|
||||
return "\t<host>\n" + attrs + "\t</host>\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 = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" \
|
||||
"<hosts version=\"" + TiS_VERSION + "\">\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 += "</hosts>"
|
||||
|
||||
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()
|
@ -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'
|
||||
],
|
||||
}
|
||||
)
|
Binary file not shown.
Before Width: | Height: | Size: 32 KiB |
@ -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
|
@ -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',
|
||||
],
|
||||
}
|
||||
)
|
@ -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
|
@ -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
|
@ -1,2 +1,2 @@
|
||||
SRC_DIR="controllerconfig"
|
||||
TIS_PATCH_VER=150
|
||||
TIS_PATCH_VER=151
|
||||
|
@ -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
|
||||
|
@ -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',
|
@ -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
|
@ -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
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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
|
@ -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=' ')
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
@ -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}(?<!-)$", re.IGNORECASE) # noqa pylint: disable=anomalous-backslash-in-string
|
||||
return all(valid_re.match(x) for x in hostname.split("."))
|
||||
|
||||
|
||||
def is_valid_mac(mac):
|
||||
"""Verify the format of a MAC addres."""
|
||||
if not mac:
|
||||
return False
|
||||
m = "[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$"
|
||||
return isinstance(mac, six.string_types) and re.match(m, mac.lower())
|
||||
|
||||
|
||||
def validate_network_str(network_str, minimum_size,
|
||||
existing_networks=None, multicast=False):
|
||||
"""Determine whether a network is valid."""
|
||||
try:
|
||||
network = netaddr.IPNetwork(network_str)
|
||||
if network.ip != network.network:
|
||||
raise ValidateFail("Invalid network address")
|
||||
elif network.size < minimum_size:
|
||||
raise ValidateFail("Subnet too small - must have at least %d "
|
||||
"addresses" % minimum_size)
|
||||
elif network.version == 6 and network.prefixlen < 64:
|
||||
raise ValidateFail("IPv6 minimum prefix length is 64")
|
||||
elif existing_networks:
|
||||
if any(network.ip in subnet for subnet in existing_networks):
|
||||
raise ValidateFail("Subnet overlaps with another "
|
||||
"configured subnet")
|
||||
elif multicast and not network.is_multicast():
|
||||
raise ValidateFail("Invalid subnet - must be multicast")
|
||||
return network
|
||||
except netaddr.AddrFormatError:
|
||||
raise ValidateFail(
|
||||
"Invalid subnet - not a valid IP subnet")
|
||||
|
||||
|
||||
def is_valid_filename(filename):
|
||||
return '\0' not in filename
|
||||
|
||||
|
||||
def is_valid_by_path(filename):
|
||||
return "/dev/disk/by-path" in filename and "-part" not in filename
|
||||
|
||||
|
||||
def is_valid_url(url_str):
|
||||
# Django URL validation patterns
|
||||
r = re.compile(
|
||||
r'^(?:http|ftp)s?://' # http:// or https://
|
||||
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)' # domain...
|
||||
r'+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
|
||||
r'localhost|' # localhost...
|
||||
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
|
||||
r'(?::\d+)?' # optional port
|
||||
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
||||
|
||||
url = r.match(url_str)
|
||||
if url:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def is_valid_domain(url_str):
|
||||
r = re.compile(
|
||||
r'^(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)' # domain...
|
||||
r'+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
|
||||
r'[A-Za-z0-9-_]*)' # localhost, hostname
|
||||
r'(?::\d+)?' # optional port
|
||||
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
||||
|
||||
url = r.match(url_str)
|
||||
if url:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
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_domain_or_ip(url_str):
|
||||
if url_str:
|
||||
if is_valid_domain(url_str):
|
||||
return True
|
||||
ip_with_port = url_str.split(':')
|
||||
if len(ip_with_port) <= 2:
|
||||
# check ipv4 or ipv4 with port
|
||||
return is_valid_ipv4(ip_with_port[0])
|
||||
else:
|
||||
# check ipv6 with port
|
||||
if '[' in url_str:
|
||||
try:
|
||||
bkt_idx = url_str.index(']')
|
||||
if bkt_idx + 1 == len(url_str):
|
||||
# brackets without port
|
||||
return False
|
||||
else:
|
||||
return is_valid_ipv6(url_str[1:bkt_idx])
|
||||
except Exception:
|
||||
return False
|
||||
else:
|
||||
# check ipv6 without port
|
||||
return is_valid_ipv6(url_str)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def is_valid_bool_str(val):
|
||||
"""Check if the provided string is a valid bool string or not."""
|
||||
boolstrs = ('true', 'false')
|
||||
return str(val).lower() in boolstrs
|
||||
|
||||
|
||||
def validate_address_str(ip_address_str, network):
|
||||
"""Determine whether an address is valid."""
|
||||
try:
|
||||
ip_address = netaddr.IPAddress(ip_address_str)
|
||||
if ip_address.version != network.version:
|
||||
msg = ("Invalid IP version - must match network version " +
|
||||
ip_version_to_string(network.version))
|
||||
raise ValidateFail(msg)
|
||||
elif ip_address == network:
|
||||
raise ValidateFail("Cannot use network address")
|
||||
elif ip_address == network.broadcast:
|
||||
raise ValidateFail("Cannot use broadcast address")
|
||||
elif ip_address not in network:
|
||||
raise ValidateFail(
|
||||
"Address must be in subnet %s" % str(network))
|
||||
return ip_address
|
||||
except netaddr.AddrFormatError:
|
||||
raise ValidateFail(
|
||||
"Invalid address - not a valid IP address")
|
||||
|
||||
|
||||
def ip_version_to_string(ip_version):
|
||||
"""Determine whether a nameserver address is valid."""
|
||||
if ip_version == 4:
|
||||
return "IPv4"
|
||||
elif ip_version == 6:
|
||||
return "IPv6"
|
||||
else:
|
||||
return "IP"
|
||||
|
||||
|
||||
def validate_nameserver_address_str(ip_address_str, subnet_version=None):
|
||||
"""Determine whether a nameserver address is valid."""
|
||||
try:
|
||||
ip_address = netaddr.IPAddress(ip_address_str)
|
||||
if subnet_version is not None and ip_address.version != subnet_version:
|
||||
msg = ("Invalid IP version - must match OAM subnet version " +
|
||||
ip_version_to_string(subnet_version))
|
||||
raise ValidateFail(msg)
|
||||
return ip_address
|
||||
except netaddr.AddrFormatError:
|
||||
msg = "Invalid address - not a valid %s address" % \
|
||||
ip_version_to_string(subnet_version)
|
||||
raise ValidateFail(msg)
|
||||
|
||||
|
||||
def validate_address(ip_address, network):
|
||||
"""Determine whether an address is valid."""
|
||||
if ip_address.version != network.version:
|
||||
msg = ("Invalid IP version - must match network version " +
|
||||
ip_version_to_string(network.version))
|
||||
raise ValidateFail(msg)
|
||||
elif ip_address == network:
|
||||
raise ValidateFail("Cannot use network address")
|
||||
elif ip_address == network.broadcast:
|
||||
raise ValidateFail("Cannot use broadcast address")
|
||||
elif ip_address not in network:
|
||||
raise ValidateFail("Address must be in subnet %s" % str(network))
|
||||
|
||||
|
||||
def check_network_overlap(new_network, configured_networks):
|
||||
""" Validate that new_network does not overlap any configured_networks.
|
||||
"""
|
||||
if any(new_network.ip in subnet for subnet in
|
||||
configured_networks):
|
||||
raise ValidateFail(
|
||||
"Subnet %s overlaps with another configured subnet" % new_network)
|
||||
|
||||
|
||||
def validate_openstack_password(password, rules_file,
|
||||
section="security_compliance"):
|
||||
try:
|
||||
config = configparser.RawConfigParser()
|
||||
parsed_config = config.read(rules_file)
|
||||
if not parsed_config:
|
||||
msg = ("Cannot parse rules file: %s" % rules_file)
|
||||
raise Exception(msg)
|
||||
if not config.has_section(section):
|
||||
msg = ("Required section '%s' not found in rules file" % section)
|
||||
raise Exception(msg)
|
||||
|
||||
password_regex = get_optional(config, section, 'password_regex')
|
||||
password_regex_description = get_optional(config, section,
|
||||
'password_regex_description')
|
||||
|
||||
if not password_regex:
|
||||
msg = ("Required option 'password_regex' not found in "
|
||||
"rule file: %s" % rules_file)
|
||||
raise Exception(msg)
|
||||
# Even if regex_description is not found, we will proceed
|
||||
# and give a generic failure warning instead
|
||||
if not password_regex_description:
|
||||
password_regex_description = ("Password does not meet "
|
||||
"complexity criteria")
|
||||
|
||||
if not isinstance(password, six.string_types):
|
||||
msg = "Password must be a string type"
|
||||
raise Exception(msg)
|
||||
try:
|
||||
# config parser would read in the string as a literal
|
||||
# representation which would fail regex matching
|
||||
password_regex = password_regex.strip('"')
|
||||
if not re.match(password_regex, password):
|
||||
return False, password_regex_description
|
||||
except re.error:
|
||||
msg = ("Unable to validate password due to invalid "
|
||||
"complexity criteria ('password_regex')")
|
||||
raise Exception(msg)
|
||||
except Exception:
|
||||
raise Exception("Password validation failed")
|
||||
return True, ""
|
||||
|
||||
|
||||
def extract_openstack_password_rules_from_file(
|
||||
rules_file, section="security_compliance"):
|
||||
try:
|
||||
config = configparser.RawConfigParser()
|
||||
parsed_config = config.read(rules_file)
|
||||
if not parsed_config:
|
||||
msg = ("Cannot parse rules file: %s" % rules_file)
|
||||
raise Exception(msg)
|
||||
if not config.has_section(section):
|
||||
msg = ("Required section '%s' not found in rules file" % section)
|
||||
raise Exception(msg)
|
||||
|
||||
rules = config.items(section)
|
||||
if not rules:
|
||||
msg = ("section '%s' contains no configuration options" % section)
|
||||
raise Exception(msg)
|
||||
return dict(rules)
|
||||
except Exception:
|
||||
raise Exception("Failed to extract password rules from file")
|
||||
|
||||
|
||||
def get_optional(conf, section, key):
|
||||
if conf.has_option(section, key):
|
||||
return conf.get(section, key)
|
||||
return None
|
||||
|
||||
|
||||
def get_service(conf, section, key):
|
||||
if key in EXPECTED_SERVICE_NAME_AND_TYPE:
|
||||
if conf.has_option(section, key):
|
||||
value = conf.get(section, key)
|
||||
if value != EXPECTED_SERVICE_NAME_AND_TYPE[key]:
|
||||
raise ValidateFail("Unsupported %s: %s " % (key, value))
|
||||
else:
|
||||
value = EXPECTED_SERVICE_NAME_AND_TYPE[key]
|
||||
return value
|
||||
else:
|
||||
return conf.get(section, key)
|
||||
|
@ -14,7 +14,6 @@ whitelist_externals = find
|
||||
install_command = pip install --no-cache-dir -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/pike} {opts} {packages}
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
-e{[tox]stxdir}/stx-config/configutilities/configutilities
|
||||
-e{[tox]stxdir}/stx-fault/fm-api
|
||||
-e{[tox]stxdir}/stx-update/tsconfig/tsconfig
|
||||
-e{[tox]stxdir}/stx-config/sysinv/sysinv/sysinv
|
||||
|
@ -4,6 +4,8 @@
|
||||
#
|
||||
# Copyright (C) 2019 Intel Corporation
|
||||
#
|
||||
# Copyright (c) 2019 Wind River Systems, Inc.
|
||||
#
|
||||
# lib/stx-config
|
||||
# Functions to control the configuration and operation of stx-config
|
||||
|
||||
@ -36,7 +38,6 @@ STX_SYSCONFDIR=${STX_SYSCONFDIR:-/etc}
|
||||
# Set up GITDIR so setup_lib and setup_dev_lib work properly
|
||||
GITDIR["cgts-client"]=$STX_CONFIG_DIR/sysinv/cgts-client/cgts-client
|
||||
|
||||
STX_CONF_UTILS_DIR=$STX_CONFIG_DIR/configutilities/configutilities
|
||||
STX_CTRL_CONF_DIR=$STX_CONFIG_DIR/controllerconfig/controllerconfig
|
||||
|
||||
SYSINV_DIR=$STX_CONFIG_DIR/sysinv/sysinv/sysinv
|
||||
@ -88,7 +89,6 @@ function cleanup_cgtsclient {
|
||||
function cleanup_config {
|
||||
if is_service_enabled sysinv; then
|
||||
cleanup_sysinv
|
||||
cleanup_configutilities
|
||||
cleanup_controllerconfig
|
||||
fi
|
||||
|
||||
@ -97,10 +97,6 @@ function cleanup_config {
|
||||
fi
|
||||
}
|
||||
|
||||
function cleanup_configutilities {
|
||||
pip_uninstall configutilities
|
||||
}
|
||||
|
||||
function cleanup_controllerconfig {
|
||||
pip_uninstall controllerconfig
|
||||
|
||||
@ -230,7 +226,6 @@ function install_config {
|
||||
install_cgtsclient
|
||||
fi
|
||||
if is_service_enabled sysinv; then
|
||||
install_configutilities
|
||||
install_controllerconfig
|
||||
install_sysinv
|
||||
fi
|
||||
@ -239,11 +234,6 @@ function install_config {
|
||||
fi
|
||||
}
|
||||
|
||||
function install_configutilities {
|
||||
# We can't use setup_develop as there is no setup.cfg file present for configutilities
|
||||
setup_package $STX_CONF_UTILS_DIR -e
|
||||
}
|
||||
|
||||
function install_controllerconfig {
|
||||
# This is a hack to work around the lack of proper global-requirements
|
||||
# setup in these packages
|
||||
|
@ -1,2 +1,2 @@
|
||||
SRC_DIR="sysinv"
|
||||
TIS_PATCH_VER=309
|
||||
TIS_PATCH_VER=310
|
||||
|
@ -16,8 +16,9 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# Copyright (c) 2013-2018 Wind River Systems, Inc.
|
||||
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import ast
|
||||
import cgi
|
||||
@ -42,7 +43,7 @@ import wsme
|
||||
import wsmeext.pecan as wsme_pecan
|
||||
|
||||
from wsme import types as wtypes
|
||||
from configutilities import HOST_XML_ATTRIBUTES
|
||||
from controllerconfig import HOST_XML_ATTRIBUTES
|
||||
from fm_api import constants as fm_constants
|
||||
from fm_api import fm_api
|
||||
from pecan import expose
|
||||
|
@ -38,7 +38,6 @@ setenv = VIRTUAL_ENV={envdir}
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
-e{[tox]stxdir}/stx-update/tsconfig/tsconfig
|
||||
-e{[tox]stxdir}/stx-config/configutilities/configutilities
|
||||
-e{[tox]stxdir}/stx-fault/fm-api
|
||||
-e{[tox]stxdir}/stx-fault/python-fmclient/fmclient
|
||||
-e{[tox]stxdir}/stx-config/controllerconfig/controllerconfig
|
||||
|
Loading…
Reference in New Issue
Block a user