StarlingX open source release updates
Signed-off-by: Dean Troyer <dtroyer@gmail.com>
This commit is contained in:
parent
9e5dab7ca9
commit
527e098821
|
@ -0,0 +1,7 @@
|
||||||
|
The following contributors from Wind River have developed the seed code in this
|
||||||
|
repository. We look forward to community collaboration and contributions for
|
||||||
|
additional features, enhancements and refactoring.
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
=============
|
||||||
|
Don Penney <Don.Penney@windriver.com>
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,5 @@
|
||||||
|
==========
|
||||||
|
stx-update
|
||||||
|
==========
|
||||||
|
|
||||||
|
StarlingX Software Management
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,13 @@
|
||||||
|
Metadata-Version: 1.1
|
||||||
|
Name: cgcs-patch
|
||||||
|
Version: 1.0
|
||||||
|
Summary: TIS Platform Patching
|
||||||
|
Home-page:
|
||||||
|
Author: Windriver
|
||||||
|
Author-email: info@windriver.com
|
||||||
|
License: Apache-2.0
|
||||||
|
|
||||||
|
Description: TIS Platform Patching
|
||||||
|
|
||||||
|
|
||||||
|
Platform: UNKNOWN
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-2014 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cgcs_make_patch.make_patch_functions import make_patch
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(make_patch())
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-2014 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cgcs_make_patch.make_patch_functions import modify_patch
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(modify_patch())
|
|
@ -0,0 +1,52 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# This bash source file provides variables and functions that
|
||||||
|
# may be used by in-service patching scripts.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Source platform.conf, for nodetype and subfunctions
|
||||||
|
. /etc/platform/platform.conf
|
||||||
|
|
||||||
|
declare PATCH_SCRIPTDIR=/run/patching/patch-scripts
|
||||||
|
declare PATCH_FLAGDIR=/run/patching/patch-flags
|
||||||
|
declare -i PATCH_STATUS_OK=0
|
||||||
|
declare -i PATCH_STATUS_FAILED=1
|
||||||
|
|
||||||
|
declare logfile=/var/log/patching.log
|
||||||
|
declare NAME=$(basename $0)
|
||||||
|
|
||||||
|
function loginfo()
|
||||||
|
{
|
||||||
|
echo "`date "+%FT%T.%3N"`: $NAME: $*" >> $logfile
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_controller()
|
||||||
|
{
|
||||||
|
[[ $nodetype == "controller" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_compute()
|
||||||
|
{
|
||||||
|
[[ $nodetype == "compute" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_storage()
|
||||||
|
{
|
||||||
|
[[ $nodetype == "storage" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_cpe()
|
||||||
|
{
|
||||||
|
[[ $nodetype == "controller" && $subfunction =~ compute ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_locked()
|
||||||
|
{
|
||||||
|
test -f /var/run/.node_locked
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
d /run/patching 0700 root root -
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cgcs_patch.patch_functions import patch_build
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(patch_build())
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
# Patching "goenabled" check.
|
||||||
|
# If a patch has been applied on this node, it is now out-of-date and should be rebooted.
|
||||||
|
|
||||||
|
NAME=$(basename $0)
|
||||||
|
SYSTEM_CHANGED_FLAG=/var/run/node_is_patched
|
||||||
|
|
||||||
|
logfile=/var/log/patching.log
|
||||||
|
|
||||||
|
function LOG()
|
||||||
|
{
|
||||||
|
logger "$NAME: $*"
|
||||||
|
echo "`date "+%FT%T.%3N"`: $NAME: $*" >> $logfile
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -f $SYSTEM_CHANGED_FLAG ]
|
||||||
|
then
|
||||||
|
LOG "Node has been patched. Failing goenabled check."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
[runtime]
|
||||||
|
controller_multicast = 239.1.1.3
|
||||||
|
agent_multicast = 239.1.1.4
|
||||||
|
api_port = 5487
|
||||||
|
controller_port = 5488
|
||||||
|
agent_port = 5489
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
/var/log/patching.log
|
||||||
|
/var/log/patching-api.log
|
||||||
|
/var/log/patching-insvc.log
|
||||||
|
{
|
||||||
|
nodateext
|
||||||
|
size 10M
|
||||||
|
start 1
|
||||||
|
rotate 10
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
compress
|
||||||
|
delaycompress
|
||||||
|
copytruncate
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
[process]
|
||||||
|
process = sw-patch-agent
|
||||||
|
pidfile = /var/run/sw-patch-agent.pid
|
||||||
|
script = /etc/init.d/sw-patch-agent
|
||||||
|
style = lsb ; ocf or lsb
|
||||||
|
severity = major ; Process failure severity
|
||||||
|
; critical : host is failed
|
||||||
|
; major : host is degraded
|
||||||
|
; minor : log is generated
|
||||||
|
restarts = 3 ; Number of back to back unsuccessful restarts before severity assertion
|
||||||
|
interval = 5 ; Number of seconds to wait between back-to-back unsuccessful restarts
|
||||||
|
debounce = 20 ; Number of seconds the process needs to run before declaring
|
||||||
|
; it as running O.K. after a restart.
|
||||||
|
; Time after which back-to-back restart count is cleared.
|
||||||
|
startuptime = 10 ; Seconds to wait after process start before starting the debounce monitor
|
||||||
|
mode = passive ; Monitoring mode: passive (default) or active
|
||||||
|
; passive: process death monitoring (default: always)
|
||||||
|
; active: heartbeat monitoring, i.e. request / response messaging
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
[process]
|
||||||
|
process = sw-patch-controller-daemon
|
||||||
|
pidfile = /var/run/sw-patch-controller-daemon.pid
|
||||||
|
script = /etc/init.d/sw-patch-controller-daemon
|
||||||
|
style = lsb ; ocf or lsb
|
||||||
|
severity = major ; Process failure severity
|
||||||
|
; critical : host is failed
|
||||||
|
; major : host is degraded
|
||||||
|
; minor : log is generated
|
||||||
|
restarts = 3 ; Number of back to back unsuccessful restarts before severity assertion
|
||||||
|
interval = 5 ; Number of seconds to wait between back-to-back unsuccessful restarts
|
||||||
|
debounce = 20 ; Number of seconds the process needs to run before declaring
|
||||||
|
; it as running O.K. after a restart.
|
||||||
|
; Time after which back-to-back restart count is cleared.
|
||||||
|
startuptime = 10 ; Seconds to wait after process start before starting the debounce monitor
|
||||||
|
mode = passive ; Monitoring mode: passive (default) or active
|
||||||
|
; passive: process death monitoring (default: always)
|
||||||
|
; active: heartbeat monitoring, i.e. request / response messaging
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"admin": "role:admin or role:administrator",
|
||||||
|
"admin_api": "is_admin:True",
|
||||||
|
"default": "rule:admin_api"
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-2014 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cgcs_make_patch.make_patch_functions import query_patch
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(query_patch())
|
|
@ -0,0 +1,175 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
echo "This utility must be run as root." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
function show_usage()
|
||||||
|
{
|
||||||
|
cat <<EOF
|
||||||
|
Usage: [ --include-pyc ] [ --include-cfg ] --skip-multi [ pkg ... ]
|
||||||
|
|
||||||
|
This utility scans the installed RPMs to compare checksums of files.
|
||||||
|
By default, files flagged as config are skipped, as are python pyc files.
|
||||||
|
|
||||||
|
Optional arguments:
|
||||||
|
--include-pyc : Include pyc files in check
|
||||||
|
--include-cfg : Include config files in check
|
||||||
|
--skip-links : Skip symlink check
|
||||||
|
--skip-multi : Skip the search for files with multiple owners
|
||||||
|
pkg : Specify one or more packages to limit the scan
|
||||||
|
(implies --skip-multi)
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
declare INCLUDE_PYTHON_FILES="no"
|
||||||
|
declare INCLUDE_CFG_FILES="no"
|
||||||
|
declare CHECK_FOR_MULTI="yes"
|
||||||
|
declare CHECK_LINKS="yes"
|
||||||
|
declare TIS_ONLY="yes"
|
||||||
|
|
||||||
|
declare CHECK_RPM=
|
||||||
|
|
||||||
|
for arg in "$@"
|
||||||
|
do
|
||||||
|
case $arg in
|
||||||
|
-h|--help)
|
||||||
|
show_usage
|
||||||
|
;;
|
||||||
|
--include-pyc)
|
||||||
|
INCLUDE_PYTHON_FILES="yes"
|
||||||
|
;;
|
||||||
|
--include-cfg)
|
||||||
|
INCLUDE_CFG_FILES="yes"
|
||||||
|
;;
|
||||||
|
--skip-links)
|
||||||
|
CHECK_LINKS="no"
|
||||||
|
;;
|
||||||
|
--skip-multi)
|
||||||
|
CHECK_FOR_MULTI="no"
|
||||||
|
;;
|
||||||
|
--all-rpms)
|
||||||
|
TIS_ONLY="no"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
CHECK_RPM="$CHECK_RPM $arg"
|
||||||
|
CHECK_FOR_MULTI="no"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
function rpm_list()
|
||||||
|
{
|
||||||
|
if [ -n "$CHECK_RPM" ]
|
||||||
|
then
|
||||||
|
for pkg in $CHECK_RPM
|
||||||
|
do
|
||||||
|
echo $pkg
|
||||||
|
done
|
||||||
|
elif [ "$TIS_ONLY" = "yes" ]
|
||||||
|
then
|
||||||
|
rpm -qa | grep '\.tis\.' | sort
|
||||||
|
else
|
||||||
|
rpm -qa | sort
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
rpm_list | while read pkg
|
||||||
|
do
|
||||||
|
# Get the --dump from the pkg
|
||||||
|
rpm -q --queryformat "[%{FILENAMES}|%{FILEMD5S}|%{FILEFLAGS:fflags}|%{FILELINKTOS}\n]" $pkg | \
|
||||||
|
while IFS='|' read pname psum pflags plinkto
|
||||||
|
do
|
||||||
|
if [[ $pname == "(contains" ]]
|
||||||
|
then
|
||||||
|
# (contains no files)
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $INCLUDE_CFG_FILES == "no" && $pflags =~ c ]]
|
||||||
|
then
|
||||||
|
# Skip file already flagged as config
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $INCLUDE_PYTHON_FILES == "no" && $pname =~ \.py[co]?$ ]]
|
||||||
|
then
|
||||||
|
# Skip python .py or .pyc file
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Directories and symlinks will have no checksum
|
||||||
|
if [[ -z $psum ]]
|
||||||
|
then
|
||||||
|
if [[ -n $plinkto && $CHECK_LINKS == "yes" ]]
|
||||||
|
then
|
||||||
|
# Check the symlink pointer
|
||||||
|
flinkto=$(readlink $pname)
|
||||||
|
if [[ "$flinkto" != "$plinkto" ]]
|
||||||
|
then
|
||||||
|
echo "Link Mismatch: $pname ($pkg)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Does the file exist?
|
||||||
|
if [ ! -e "$pname" ]
|
||||||
|
then
|
||||||
|
echo "Missing: $pname ($pkg)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Has the file been replaced by a symlink? ie. update-alternatives
|
||||||
|
if [ -L "$pname" ]
|
||||||
|
then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $psum $pname | sha256sum --check --status
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
echo "Mismatch: $pname ($pkg)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
function check_for_multi_master()
|
||||||
|
{
|
||||||
|
# Search for files owned by multiple packages
|
||||||
|
prev=
|
||||||
|
rpm_list | xargs rpm -q --queryformat "[%{FILENAMES}|%{=NAME}\n]" | sort | while IFS='|' read f p
|
||||||
|
do
|
||||||
|
if [ "$f" = "$prev" ]
|
||||||
|
then
|
||||||
|
echo $f
|
||||||
|
fi
|
||||||
|
prev=$f
|
||||||
|
done | sort -u | while read f
|
||||||
|
do
|
||||||
|
if [ ! -d "$f" ]
|
||||||
|
then
|
||||||
|
echo $f
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $CHECK_FOR_MULTI = "yes" ]
|
||||||
|
then
|
||||||
|
echo
|
||||||
|
echo
|
||||||
|
echo "The following files belong to multiple packages:"
|
||||||
|
echo
|
||||||
|
check_for_multi_master
|
||||||
|
fi
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
. /etc/patching/patch-functions
|
||||||
|
|
||||||
|
declare SCRIPTS=$(find $PATCH_SCRIPTDIR -type f -executable | sort)
|
||||||
|
declare -i NUM_SCRIPTS=$(echo "$SCRIPTS" | wc -l)
|
||||||
|
|
||||||
|
if [ $NUM_SCRIPTS -eq 0 ]
|
||||||
|
then
|
||||||
|
loginfo "No in-service patch scripts found."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
loginfo "Running $NUM_SCRIPTS in-service patch scripts"
|
||||||
|
|
||||||
|
declare SCRIPTLOG=/var/log/patching-insvc.log
|
||||||
|
cat <<EOF >>$SCRIPTLOG
|
||||||
|
############################################################
|
||||||
|
`date "+%FT%T.%3N"`: Running $NUM_SCRIPTS in-service patch scripts:
|
||||||
|
|
||||||
|
$SCRIPTS
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
EOF
|
||||||
|
|
||||||
|
declare -i FAILURES=0
|
||||||
|
for cmd in $SCRIPTS
|
||||||
|
do
|
||||||
|
cat <<EOF >>$SCRIPTLOG
|
||||||
|
############################################################
|
||||||
|
`date "+%FT%T.%3N"`: Running $cmd
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
bash -x $cmd >>$SCRIPTLOG 2>&1
|
||||||
|
rc=$?
|
||||||
|
if [ $rc -ne $PATCH_STATUS_OK ]
|
||||||
|
then
|
||||||
|
let -i FAILURES++
|
||||||
|
fi
|
||||||
|
cat <<EOF >>$SCRIPTLOG
|
||||||
|
`date "+%FT%T.%3N"`: Completed running $cmd (rc=$rc)
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
EOF
|
||||||
|
done
|
||||||
|
|
||||||
|
cat <<EOF >>$SCRIPTLOG
|
||||||
|
|
||||||
|
`date "+%FT%T.%3N"`: Completed running scripts with $FAILURES failures
|
||||||
|
############################################################
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit $FAILURES
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2018 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import getopt
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import rpm
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import cgcs_patch.patch_functions as pf
|
||||||
|
import cgcs_patch.patch_verify as pv
|
||||||
|
import cgcs_patch.constants as constants
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logging.getLogger('main_logger')
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
# Override the pv.dev_certificate_marker so we can verify signatures off-box
|
||||||
|
cgcs_patch_bindir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||||
|
dev_cert_path = os.path.abspath(os.path.join(cgcs_patch_bindir, '../../enable-dev-patch/enable-dev-patch/dev_certificate_enable.bin'))
|
||||||
|
|
||||||
|
pv.dev_certificate_marker = dev_cert_path
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print "Usage: %s -o <repodir> <patch> ..." \
|
||||||
|
% os.path.basename(sys.argv[0])
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
opts, remainder = getopt.getopt(sys.argv[1:],
|
||||||
|
'o:',
|
||||||
|
['output='])
|
||||||
|
except getopt.GetoptError:
|
||||||
|
usage()
|
||||||
|
|
||||||
|
output = None
|
||||||
|
|
||||||
|
for opt, arg in opts:
|
||||||
|
if opt == "--output" or opt == '-o':
|
||||||
|
output = arg
|
||||||
|
|
||||||
|
if output is None:
|
||||||
|
usage()
|
||||||
|
|
||||||
|
sw_version = os.environ['PLATFORM_RELEASE']
|
||||||
|
|
||||||
|
allpatches = pf.PatchData()
|
||||||
|
|
||||||
|
output = os.path.abspath(output)
|
||||||
|
|
||||||
|
pkgdir = os.path.join(output, 'Packages')
|
||||||
|
datadir = os.path.join(output, 'metadata')
|
||||||
|
committed_dir = os.path.join(datadir, 'committed')
|
||||||
|
|
||||||
|
if os.path.exists(output):
|
||||||
|
# Check to see if the expected structure already exists,
|
||||||
|
# maybe we're appending a patch.
|
||||||
|
if not os.path.exists(committed_dir) or not os.path.exists(pkgdir):
|
||||||
|
print "Packages or metadata dir missing from existing %s. Aborting..." % output
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# Load the existing metadata
|
||||||
|
allpatches.load_all_metadata(committed_dir, constants.COMMITTED)
|
||||||
|
else:
|
||||||
|
os.mkdir(output, 0755)
|
||||||
|
os.mkdir(datadir, 0755)
|
||||||
|
os.mkdir(committed_dir, 0755)
|
||||||
|
os.mkdir(pkgdir, 0755)
|
||||||
|
|
||||||
|
# Save the current directory, so we can chdir back after
|
||||||
|
orig_wd = os.getcwd()
|
||||||
|
|
||||||
|
tmpdir = None
|
||||||
|
try:
|
||||||
|
for p in remainder:
|
||||||
|
fpath = os.path.abspath(p)
|
||||||
|
|
||||||
|
# Create a temporary working directory
|
||||||
|
tmpdir = tempfile.mkdtemp(prefix="patchrepo_")
|
||||||
|
|
||||||
|
# Change to the tmpdir
|
||||||
|
os.chdir(tmpdir)
|
||||||
|
|
||||||
|
print "Parsing %s" % fpath
|
||||||
|
pf.PatchFile.read_patch(fpath)
|
||||||
|
|
||||||
|
thispatch = pf.PatchData()
|
||||||
|
patch_id = thispatch.parse_metadata("metadata.xml", constants.COMMITTED)
|
||||||
|
|
||||||
|
if patch_id in allpatches.metadata:
|
||||||
|
print "Skipping %s as it's already in the repo" % patch_id
|
||||||
|
# Change back to original working dir
|
||||||
|
os.chdir(orig_wd)
|
||||||
|
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
tmpdir = None
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
patch_sw_version = thispatch.query_line(patch_id, 'sw_version')
|
||||||
|
if patch_sw_version != sw_version:
|
||||||
|
print "%s is for release %s, not %s" % (patch_sw_version, sw_version)
|
||||||
|
|
||||||
|
# Move the metadata to the "committed" dir, and the rpms to the Packages dir
|
||||||
|
shutil.move('metadata.xml', os.path.join(committed_dir, "%s-metadata.xml" % patch_id))
|
||||||
|
for f in thispatch.query_line(patch_id, 'contents'):
|
||||||
|
shutil.move(f, pkgdir)
|
||||||
|
|
||||||
|
allpatches.add_patch(patch_id, thispatch)
|
||||||
|
|
||||||
|
# Change back to original working dir
|
||||||
|
os.chdir(orig_wd)
|
||||||
|
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
tmpdir = None
|
||||||
|
except:
|
||||||
|
if tmpdir is not None:
|
||||||
|
# Change back to original working dir
|
||||||
|
os.chdir(orig_wd)
|
||||||
|
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
tmpdir = None
|
||||||
|
raise
|
||||||
|
|
||||||
|
allpatches.gen_release_groups_xml(sw_version, output)
|
||||||
|
|
||||||
|
# Purge unneeded RPMs
|
||||||
|
keep = {}
|
||||||
|
for patch_id in allpatches.metadata.keys():
|
||||||
|
for rpmname in allpatches.contents[patch_id]:
|
||||||
|
try:
|
||||||
|
pkgname, arch, pkgver = pf.parse_rpm_filename(rpmname)
|
||||||
|
except ValueError as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
if pkgname not in keep:
|
||||||
|
keep[pkgname] = { arch: pkgver }
|
||||||
|
continue
|
||||||
|
elif arch not in keep[pkgname]:
|
||||||
|
keep[pkgname][arch] = pkgver
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Compare versions
|
||||||
|
keep_pkgver = keep[pkgname][arch]
|
||||||
|
if pkgver > keep_pkgver:
|
||||||
|
# Find the rpmname
|
||||||
|
keep_rpmname = keep_pkgver.generate_rpm_filename(pkgname, arch)
|
||||||
|
|
||||||
|
filename = os.path.join(pkgdir, keep_rpmname)
|
||||||
|
if os.path.exists(filename):
|
||||||
|
os.remove(filename)
|
||||||
|
|
||||||
|
# Keep the new pkgver
|
||||||
|
keep[pkgname][arch] = pkgver
|
||||||
|
else:
|
||||||
|
filename = os.path.join(pkgdir, rpmname)
|
||||||
|
if os.path.exists(filename):
|
||||||
|
os.remove(filename)
|
||||||
|
|
||||||
|
# Create the repo metadata
|
||||||
|
if os.path.exists('/usr/bin/createrepo_c'):
|
||||||
|
createrepo = '/usr/bin/createrepo_c'
|
||||||
|
else:
|
||||||
|
createrepo = 'createrepo'
|
||||||
|
|
||||||
|
os.chdir(output)
|
||||||
|
subprocess.check_call([createrepo, '-g', 'comps.xml', '.'])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cgcs_patch.patch_client import main
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cgcs_patch.patch_agent import main
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014-2015 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
# chkconfig: 345 26 30
|
||||||
|
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: sw-patch-agent
|
||||||
|
# Required-Start: $syslog
|
||||||
|
# Required-Stop: $syslog
|
||||||
|
# Default-Start: 2 3 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: sw-patch-agent
|
||||||
|
# Description: Provides the CGCS Patch Agent Daemon
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
DESC="sw-patch-agent"
|
||||||
|
DAEMON="/usr/sbin/sw-patch-agent"
|
||||||
|
PIDFILE="/var/run/sw-patch-agent.pid"
|
||||||
|
PATCH_INSTALLING_FILE="/var/run/patch_installing"
|
||||||
|
|
||||||
|
start()
|
||||||
|
{
|
||||||
|
if [ -e $PIDFILE ]; then
|
||||||
|
PIDDIR=/proc/$(cat $PIDFILE)
|
||||||
|
if [ -d ${PIDDIR} ]; then
|
||||||
|
echo "$DESC already running."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Removing stale PID file $PIDFILE"
|
||||||
|
rm -f $PIDFILE
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Starting $DESC..."
|
||||||
|
|
||||||
|
start-stop-daemon --start --quiet --background \
|
||||||
|
--pidfile ${PIDFILE} --make-pidfile --exec ${DAEMON}
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "done."
|
||||||
|
else
|
||||||
|
echo "failed."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
stop()
|
||||||
|
{
|
||||||
|
if [ -f $PATCH_INSTALLING_FILE ]
|
||||||
|
then
|
||||||
|
echo "Patches are installing. Waiting for install to complete."
|
||||||
|
while [ -f $PATCH_INSTALLING_FILE ]
|
||||||
|
do
|
||||||
|
# Verify the agent is still running
|
||||||
|
pid=$(cat $PATCH_INSTALLING_FILE)
|
||||||
|
cat /proc/$pid/cmdline 2>/dev/null | grep -q $DAEMON
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
echo "Patch agent not running."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "Continuing with shutdown."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Stopping $DESC..."
|
||||||
|
start-stop-daemon --stop --quiet --pidfile $PIDFILE
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "done."
|
||||||
|
else
|
||||||
|
echo "failed."
|
||||||
|
fi
|
||||||
|
rm -f $PIDFILE
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
start
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop
|
||||||
|
;;
|
||||||
|
restart|force-reload)
|
||||||
|
stop
|
||||||
|
start
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {start|stop|force-reload|restart}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
. /etc/patching/patch-functions
|
||||||
|
|
||||||
|
#
|
||||||
|
# Triggering a restart of the patching daemons is done by
|
||||||
|
# creating a flag file and letting the daemon handle the restart.
|
||||||
|
#
|
||||||
|
loginfo "Requesting restart of patch-agent"
|
||||||
|
|
||||||
|
restart_patch_agent_flag="/run/patching/.restart.patch-agent"
|
||||||
|
touch $restart_patch_agent_flag
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
[Unit]
|
||||||
|
Description=TIS Patching Agent
|
||||||
|
After=syslog.target network.target sw-patch.service
|
||||||
|
Before=pmon.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=forking
|
||||||
|
User=root
|
||||||
|
ExecStart=/etc/init.d/sw-patch-agent start
|
||||||
|
ExecStop=/etc/init.d/sw-patch-agent stop
|
||||||
|
ExecReload=/etc/init.d/sw-patch-agent restart
|
||||||
|
PIDFile=/var/run/sw-patch-agent.pid
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cgcs_patch.patch_controller import main
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014-2015 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
# chkconfig: 345 25 30
|
||||||
|
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: sw-patch-controller-daemon
|
||||||
|
# Required-Start: $syslog
|
||||||
|
# Required-Stop: $syslog
|
||||||
|
# Default-Start: 2 3 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: sw-patch-controller-daemon
|
||||||
|
# Description: Provides the CGCS Patch Controller Daemon
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
DESC="sw-patch-controller-daemon"
|
||||||
|
DAEMON="/usr/sbin/sw-patch-controller-daemon"
|
||||||
|
PIDFILE="/var/run/sw-patch-controller-daemon.pid"
|
||||||
|
|
||||||
|
start()
|
||||||
|
{
|
||||||
|
if [ -e $PIDFILE ]; then
|
||||||
|
PIDDIR=/proc/$(cat $PIDFILE)
|
||||||
|
if [ -d ${PIDDIR} ]; then
|
||||||
|
echo "$DESC already running."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Removing stale PID file $PIDFILE"
|
||||||
|
rm -f $PIDFILE
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Starting $DESC..."
|
||||||
|
|
||||||
|
start-stop-daemon --start --quiet --background \
|
||||||
|
--pidfile ${PIDFILE} --make-pidfile --exec ${DAEMON}
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "done."
|
||||||
|
else
|
||||||
|
echo "failed."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
stop()
|
||||||
|
{
|
||||||
|
echo -n "Stopping $DESC..."
|
||||||
|
start-stop-daemon --stop --quiet --pidfile $PIDFILE
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "done."
|
||||||
|
else
|
||||||
|
echo "failed."
|
||||||
|
fi
|
||||||
|
rm -f $PIDFILE
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
start
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop
|
||||||
|
;;
|
||||||
|
restart|force-reload)
|
||||||
|
stop
|
||||||
|
start
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {start|stop|force-reload|restart}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
. /etc/patching/patch-functions
|
||||||
|
|
||||||
|
#
|
||||||
|
# Triggering a restart of the patching daemons is done by
|
||||||
|
# creating a flag file and letting the daemon handle the restart.
|
||||||
|
#
|
||||||
|
loginfo "Requesting restart of patch-controller"
|
||||||
|
|
||||||
|
restart_patch_controller_flag="/run/patching/.restart.patch-controller"
|
||||||
|
touch $restart_patch_controller_flag
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
[Unit]
|
||||||
|
Description=TIS Patching Controller Daemon
|
||||||
|
After=syslog.target network.target sw-patch.service sw-patch-controller.service
|
||||||
|
Before=pmon.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=forking
|
||||||
|
User=root
|
||||||
|
ExecStart=/etc/init.d/sw-patch-controller-daemon start
|
||||||
|
ExecStop=/etc/init.d/sw-patch-controller-daemon stop
|
||||||
|
ExecReload=/etc/init.d/sw-patch-controller-daemon restart
|
||||||
|
PIDFile=/var/run/sw-patch-controller-daemon.pid
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
# CGCS Patching Controller setup
|
||||||
|
# chkconfig: 345 20 24
|
||||||
|
# description: CGCS Patching Controller init script
|
||||||
|
|
||||||
|
. /usr/bin/tsconfig
|
||||||
|
|
||||||
|
NAME=$(basename $0)
|
||||||
|
|
||||||
|
REPO_ID=updates
|
||||||
|
REPO_ROOT=/www/pages/${REPO_ID}
|
||||||
|
REPO_DIR=${REPO_ROOT}/rel-${SW_VERSION}
|
||||||
|
GROUPS_FILE=$REPO_DIR/comps.xml
|
||||||
|
PATCHING_DIR=/opt/patching
|
||||||
|
|
||||||
|
logfile=/var/log/patching.log
|
||||||
|
|
||||||
|
function LOG()
|
||||||
|
{
|
||||||
|
logger "$NAME: $*"
|
||||||
|
echo "`date "+%FT%T.%3N"`: $NAME: $*" >> $logfile
|
||||||
|
}
|
||||||
|
|
||||||
|
function LOG_TO_FILE()
|
||||||
|
{
|
||||||
|
echo "`date "+%FT%T.%3N"`: $NAME: $*" >> $logfile
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_groups()
|
||||||
|
{
|
||||||
|
if [ -f $GROUPS_FILE ]
|
||||||
|
then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat >$GROUPS_FILE <<EOF
|
||||||
|
<comps>
|
||||||
|
</comps>
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_setup()
|
||||||
|
{
|
||||||
|
# Does the repo exist?
|
||||||
|
if [ ! -d $REPO_DIR ]
|
||||||
|
then
|
||||||
|
LOG "Creating repo"
|
||||||
|
mkdir -p $REPO_DIR
|
||||||
|
|
||||||
|
# Setup the groups file
|
||||||
|
create_groups
|
||||||
|
|
||||||
|
createrepo -g $GROUPS_FILE $REPO_DIR >> $logfile 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d $PATCHING_DIR ]
|
||||||
|
then
|
||||||
|
LOG "Creating $PATCHING_DIR"
|
||||||
|
mkdir -p $PATCHING_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If we can ping the active controller, sync the repos
|
||||||
|
LOG_TO_FILE "ping -c 1 -w 1 controller"
|
||||||
|
ping -c 1 -w 1 controller >> $logfile 2>&1 || ping6 -c 1 -w 1 controller >> $logfile 2>&1
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
LOG "Cannot ping controller. Nothing to do"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Sync the patching dir
|
||||||
|
LOG_TO_FILE "rsync -acv --delete rsync://controller/patching/ ${PATCHING_DIR}/"
|
||||||
|
rsync -acv --delete rsync://controller/patching/ ${PATCHING_DIR}/ >> $logfile 2>&1
|
||||||
|
|
||||||
|
# Sync the patching dir
|
||||||
|
LOG_TO_FILE "rsync -acv --delete rsync://controller/repo/ ${REPO_ROOT}/"
|
||||||
|
rsync -acv --delete rsync://controller/repo/ ${REPO_ROOT}/ >> $logfile 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
do_setup
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
# Nothing to do here
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
do_setup
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {status|start|stop|restart}"
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
[Unit]
|
||||||
|
Description=TIS Patching Controller
|
||||||
|
After=syslog.service network.target sw-patch.service
|
||||||
|
Before=sw-patch-agent.service sw-patch-controller-daemon.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
User=root
|
||||||
|
ExecStart=/etc/init.d/sw-patch-controller start
|
||||||
|
RemainAfterExit=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014-2015 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
# CGCS Patching
|
||||||
|
# chkconfig: 345 20 23
|
||||||
|
# description: CGCS Patching init script
|
||||||
|
|
||||||
|
NAME=$(basename $0)
|
||||||
|
|
||||||
|
. /usr/bin/tsconfig
|
||||||
|
. /etc/platform/platform.conf
|
||||||
|
|
||||||
|
logfile=/var/log/patching.log
|
||||||
|
|
||||||
|
function LOG_TO_FILE()
|
||||||
|
{
|
||||||
|
echo "`date "+%FT%T.%3N"`: $NAME: $*" >> $logfile
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_for_rr_patch()
|
||||||
|
{
|
||||||
|
if [ -f /var/run/node_is_patched_rr ]
|
||||||
|
then
|
||||||
|
echo
|
||||||
|
echo "Node has been patched and requires an immediate reboot."
|
||||||
|
echo
|
||||||
|
LOG_TO_FILE "Node has been patched, with reboot-required flag set. Rebooting"
|
||||||
|
/sbin/reboot
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_install_uuid()
|
||||||
|
{
|
||||||
|
# Check whether our installed load matches the active controller
|
||||||
|
CONTROLLER_UUID=`curl -sf http://controller/feed/rel-${SW_VERSION}/install_uuid`
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
if [ "$HOSTNAME" = "controller-1" ]
|
||||||
|
then
|
||||||
|
# If we're on controller-1, controller-0 may not have the install_uuid
|
||||||
|
# matching this release, if we're in an upgrade. If the file doesn't exist,
|
||||||
|
# bypass this check
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
LOG_TO_FILE "Unable to retrieve installation uuid from active controller"
|
||||||
|
echo "Unable to retrieve installation uuid from active controller"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$INSTALL_UUID" != "$CONTROLLER_UUID" ]
|
||||||
|
then
|
||||||
|
LOG_TO_FILE "This node is running a different load than the active controller and must be reinstalled"
|
||||||
|
echo "This node is running a different load than the active controller and must be reinstalled"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for installation failure
|
||||||
|
if [ -f /etc/platform/installation_failed ] ; then
|
||||||
|
LOG_TO_FILE "/etc/platform/installation_failed flag is set. Aborting."
|
||||||
|
echo "$(basename $0): Detected installation failure. Aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up the RPM DB
|
||||||
|
if [ ! -f /var/run/.rpmdb_cleaned ]
|
||||||
|
then
|
||||||
|
LOG_TO_FILE "Cleaning RPM DB"
|
||||||
|
rm -f /var/lib/rpm/__db*
|
||||||
|
touch /var/run/.rpmdb_cleaned
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If the management interface is bonded, it may take some time
|
||||||
|
# before communications can be properly setup.
|
||||||
|
# Allow up to $DELAY_SEC seconds to reach controller.
|
||||||
|
DELAY_SEC=120
|
||||||
|
START=`date +%s`
|
||||||
|
FOUND=0
|
||||||
|
while [ $(date +%s) -lt $(( ${START} + ${DELAY_SEC} )) ]
|
||||||
|
do
|
||||||
|
ping -c 1 controller > /dev/null 2>&1 || ping6 -c 1 controller > /dev/null 2>&1
|
||||||
|
if [ $? -eq 0 ]
|
||||||
|
then
|
||||||
|
FOUND=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${FOUND} -eq 0 ]
|
||||||
|
then
|
||||||
|
# 'controller' is not available, just exit
|
||||||
|
LOG_TO_FILE "Unable to contact active controller (controller). Boot will continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
if [ "${system_mode}" = "simplex" ]
|
||||||
|
then
|
||||||
|
# On a simplex CPE, we need to launch the http server first,
|
||||||
|
# before we can do the patch installation
|
||||||
|
LOG_TO_FILE "***** Launching lighttpd *****"
|
||||||
|
/etc/init.d/lighttpd start
|
||||||
|
|
||||||
|
LOG_TO_FILE "***** Starting patch operation *****"
|
||||||
|
/usr/sbin/sw-patch-agent --install 2>>$logfile
|
||||||
|
LOG_TO_FILE "***** Finished patch operation *****"
|
||||||
|
|
||||||
|
LOG_TO_FILE "***** Shutting down lighttpd *****"
|
||||||
|
/etc/init.d/lighttpd stop
|
||||||
|
else
|
||||||
|
check_install_uuid
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
# The INSTALL_UUID doesn't match the active controller, so exit
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
LOG_TO_FILE "***** Starting patch operation *****"
|
||||||
|
/usr/sbin/sw-patch-agent --install 2>>$logfile
|
||||||
|
LOG_TO_FILE "***** Finished patch operation *****"
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_for_rr_patch
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
# Nothing to do here
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
LOG_TO_FILE "***** Starting patch operation *****"
|
||||||
|
/usr/sbin/sw-patch-agent --install 2>>$logfile
|
||||||
|
LOG_TO_FILE "***** Finished patch operation *****"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {start|stop|restart}"
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file provides bash-completion functionality for the sw-patch CLI
|
||||||
|
#
|
||||||
|
|
||||||
|
function _swpatch()
|
||||||
|
{
|
||||||
|
COMPREPLY=()
|
||||||
|
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
local prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
|
local subcommand=${COMP_WORDS[1]}
|
||||||
|
|
||||||
|
#
|
||||||
|
# The available sw-patch subcommands
|
||||||
|
#
|
||||||
|
local subcommands="
|
||||||
|
apply
|
||||||
|
commit
|
||||||
|
delete
|
||||||
|
query
|
||||||
|
query-dependencies
|
||||||
|
query-hosts
|
||||||
|
remove
|
||||||
|
show
|
||||||
|
upload
|
||||||
|
upload-dir
|
||||||
|
what-requires
|
||||||
|
drop-host
|
||||||
|
"
|
||||||
|
if [ -f /etc/platform/.initial_config_complete ]; then
|
||||||
|
# Post-config, so the host-install commands are accessible
|
||||||
|
subcommands="${subcommands} host-install host-install-async"
|
||||||
|
else
|
||||||
|
# Pre-config, so the install-local command is accessible
|
||||||
|
subcommands="${subcommands} install-local"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Appends the '/' when completing dir names
|
||||||
|
set mark-directories on
|
||||||
|
|
||||||
|
if [ $COMP_CWORD -gt 1 ]; then
|
||||||
|
#
|
||||||
|
# Complete the arguments to the subcommands.
|
||||||
|
#
|
||||||
|
case "$subcommand" in
|
||||||
|
apply|remove|delete|show|what-requires)
|
||||||
|
# Query the list of known patches
|
||||||
|
local patches=$(sw-patch completion patches 2>/dev/null)
|
||||||
|
COMPREPLY=( $(compgen -W "${patches}" -- ${cur}) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
host-install|host-install-async|drop-host)
|
||||||
|
if [ "${prev}" = "${subcommand}" -o "${prev}" = "--force" ]; then
|
||||||
|
# Query the list of known hosts
|
||||||
|
local names=$(sw-patch completion hosts 2>/dev/null)
|
||||||
|
COMPREPLY=( $(compgen -W "${names}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
# Only one host can be specified, so no more completion
|
||||||
|
COMPREPLY=( $(compgen -- ${cur}) )
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
upload)
|
||||||
|
# Allow dirs and files with .patch extension for completion
|
||||||
|
COMPREPLY=( $(compgen -f -o plusdirs -X '!*.patch' -- ${cur}) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
upload-dir)
|
||||||
|
# Allow dirs only for completion
|
||||||
|
COMPREPLY=( $(compgen -d -- ${cur}) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
query)
|
||||||
|
if [ "${prev}" = "--release" ]; then
|
||||||
|
# If --release has been specified, provide installed releases for completion
|
||||||
|
local releases=$(/bin/ls -d /www/pages/feed/rel-* 2>/dev/null | sed 's#/www/pages/feed/rel-##')
|
||||||
|
COMPREPLY=( $(compgen -W "${releases}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
# --release is only completion option for query
|
||||||
|
COMPREPLY=( $(compgen -W "--release" -- ${cur}) )
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
query-hosts|install-local)
|
||||||
|
# These subcommands have no options/arguments
|
||||||
|
COMPREPLY=( $(compgen -- ${cur}) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
query-dependencies)
|
||||||
|
# Query the list of known patches
|
||||||
|
local patches=$(sw-patch completion patches 2>/dev/null)
|
||||||
|
COMPREPLY=( $(compgen -W "--recursive ${patches}" -- ${cur}) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
commit)
|
||||||
|
if [ "${prev}" = "--release" ]; then
|
||||||
|
# If --release has been specified, provide installed releases for completion
|
||||||
|
local releases=$(/bin/ls -d /www/pages/feed/rel-* 2>/dev/null | sed 's#/www/pages/feed/rel-##')
|
||||||
|
COMPREPLY=( $(compgen -W "${releases}" -- ${cur}) )
|
||||||
|
else
|
||||||
|
# Query the list of known patches
|
||||||
|
local patches=$(sw-patch completion patches 2>/dev/null)
|
||||||
|
COMPREPLY=( $(compgen -W "--all --dry-run --release ${patches}" -- ${cur}) )
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Provide subcommands for completion
|
||||||
|
COMPREPLY=($(compgen -W "${subcommands}" -- ${cur}))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Bind the above function to the sw-patch CLI
|
||||||
|
complete -F _swpatch -o filenames sw-patch
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
[Unit]
|
||||||
|
Description=TIS Patching
|
||||||
|
After=syslog.target network.target
|
||||||
|
Before=sw-patch-agent.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
User=root
|
||||||
|
ExecStart=/etc/init.d/sw-patch start
|
||||||
|
RemainAfterExit=yes
|
||||||
|
StandardOutput=syslog+console
|
||||||
|
StandardError=syslog+console
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
function show_usage()
|
||||||
|
{
|
||||||
|
cat >&2 <<EOF
|
||||||
|
$(basename $0): -r <release>
|
||||||
|
|
||||||
|
This tool will extract required packages to support upgrade-start
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-r <release> : Release ID for target release.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
. /etc/build.info
|
||||||
|
if [ -z "${SW_VERSION}" ]; then
|
||||||
|
logger -t $0 "Unable to identify running release ID"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare TGT_RELEASE=
|
||||||
|
|
||||||
|
while getopts "r:h" opt; do
|
||||||
|
case $opt in
|
||||||
|
r)
|
||||||
|
TGT_RELEASE=$OPTARG
|
||||||
|
;;
|
||||||
|
h)
|
||||||
|
show_usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
logger -t $0 "Unsupported option"
|
||||||
|
show_usage
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "${TGT_RELEASE}" ]; then
|
||||||
|
logger -t $0 "You must specify the target release."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${TGT_RELEASE}" = "${SW_VERSION}" ]; then
|
||||||
|
logger -t $0 "Target release cannot be running release."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare TGT_BASE_REPO=/www/pages/feed/rel-${TGT_RELEASE}
|
||||||
|
declare TGT_PATCHES_REPO=/www/pages/updates/rel-${TGT_RELEASE}
|
||||||
|
|
||||||
|
if [ ! -d ${TGT_BASE_REPO} ]; then
|
||||||
|
logger -t $0 "Target release ${TGT_RELEASE} is not installed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare TGT_PATCHES_REPO_OPT=""
|
||||||
|
if [ -d ${TGT_PATCHES_REPO} ]; then
|
||||||
|
TGT_PATCHES_REPO_OPT="--repofrompath updates,${TGT_PATCHES_REPO}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare WORKDIR=
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
if [ -n "${WORKDIR}" -a -d "${WORKDIR}" ]; then
|
||||||
|
rm -rf ${WORKDIR}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
function extract_pkg() {
|
||||||
|
local pkgname=$1
|
||||||
|
|
||||||
|
ORIG_PWD=$PWD
|
||||||
|
cd $WORKDIR
|
||||||
|
|
||||||
|
# Find the RPM
|
||||||
|
local pkgfile=$(repoquery --repofrompath base,${TGT_BASE_REPO} ${TGT_PATCHES_REPO_OPT} --location -q ${pkgname})
|
||||||
|
if [ -z "${pkgfile}" ]; then
|
||||||
|
logger -t $0 "Could not find ${pkgname}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Chop off the file: from the start of the file location
|
||||||
|
local rpmfile=${pkgfile/file://}
|
||||||
|
|
||||||
|
rpm2cpio ${rpmfile} | cpio -idm
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
logger -t $0 "Failed to extract $pkgname files from ${pkgfile/file://}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd ${ORIG_PWD}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract files from pxe-network-installer
|
||||||
|
WORKDIR=$(mktemp -d --tmpdir=/scratch pkgextract_XXXX)
|
||||||
|
if [ -z "${WORKDIR}" -o ! -d "${WORKDIR}" ]; then
|
||||||
|
logger -t $0 "Failed to create workdir"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
extract_pkg pxe-network-installer
|
||||||
|
rsync -ac ${WORKDIR}/usr/ /usr/ &&
|
||||||
|
rsync -ac ${WORKDIR}/pxeboot/rel-${TGT_RELEASE}/ /pxeboot/rel-${TGT_RELEASE}/ &&
|
||||||
|
rsync -c ${WORKDIR}/pxeboot/pxelinux.cfg.files/*-${TGT_RELEASE} /pxeboot/pxelinux.cfg.files/ &&
|
||||||
|
rsync -ac ${WORKDIR}/www/pages/feed/rel-${TGT_RELEASE}/ /www/pages/feed/rel-${TGT_RELEASE}/
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
logger -t $0 "rsync command failed, extracting pxe-network-installer"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
rm -rf ${WORKDIR}
|
||||||
|
|
||||||
|
# Extract files from platform-kickstarts
|
||||||
|
WORKDIR=$(mktemp -d --tmpdir=/scratch pkgextract_XXXX)
|
||||||
|
if [ -z "${WORKDIR}" -o ! -d "${WORKDIR}" ]; then
|
||||||
|
logger -t $0 "Failed to create workdir"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
extract_pkg platform-kickstarts
|
||||||
|
rsync -ac ${WORKDIR}/www/pages/feed/rel-${TGT_RELEASE}/ /www/pages/feed/rel-${TGT_RELEASE}/
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
logger -t $0 "rsync command failed, extracting platform-kickstarts"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
rm -rf ${WORKDIR}
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
source "$SRC_BASE/build-tools/spec-utils"
|
||||||
|
|
||||||
|
if [ "x$DATA" == "x" ]; then
|
||||||
|
echo "ERROR: Environment variable 'DATA' not defined."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$DATA" ]; then
|
||||||
|
echo "ERROR: Couldn't find '$PWD/$DATA'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset TIS_PATCH_VER # Ensure there's nothing in the env already
|
||||||
|
|
||||||
|
source $DATA
|
||||||
|
|
||||||
|
if [ -z "$TIS_PATCH_VER" ]; then
|
||||||
|
echo "ERROR: TIS_PATCH_VER must be defined"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SRC_DIR="cgcs-patch"
|
||||||
|
EXTRA_DIR="bin"
|
||||||
|
|
||||||
|
VERSION=$(grep '^Version:' PKG-INFO | awk -F ': ' '{print $2}' | sed -e 's/^[[:space:]]*//')
|
||||||
|
TAR_NAME=$(grep '^Name:' PKG-INFO | awk -F ': ' '{print $2}' | sed -e 's/^[[:space:]]*//')
|
||||||
|
CUR_DIR=`pwd`
|
||||||
|
BUILD_DIR="$RPMBUILD_BASE"
|
||||||
|
|
||||||
|
mkdir -p $BUILD_DIR/SRPMS
|
||||||
|
|
||||||
|
TAR="$TAR_NAME-$VERSION.tar.gz"
|
||||||
|
TAR_PATH="$BUILD_DIR/SOURCES/$TAR"
|
||||||
|
|
||||||
|
# copy the LICENSE for rpm spec %license directive
|
||||||
|
cp $SRC_DIR/LICENSE $BUILD_DIR/SOURCES/
|
||||||
|
|
||||||
|
TAR_NEEDED=0
|
||||||
|
if [ -f $TAR_PATH ]; then
|
||||||
|
n=`find . -cnewer $TAR_PATH -and ! -path './.git*' \
|
||||||
|
-and ! -path './build/*' \
|
||||||
|
-and ! -path './.pc/*' \
|
||||||
|
-and ! -path './patches/*' \
|
||||||
|
-and ! -path "./$DISTRO/*" \
|
||||||
|
-and ! -path './pbr-*.egg/*' \
|
||||||
|
| wc -l`
|
||||||
|
if [ $n -gt 0 ]; then
|
||||||
|
TAR_NEEDED=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
TAR_NEEDED=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $TAR_NEEDED -gt 0 ]; then
|
||||||
|
tar czvf $TAR_PATH $SRC_DIR $EXTRA_DIR \
|
||||||
|
--exclude='cgcs-patch/cgcs_patch_id' \
|
||||||
|
--exclude='cgcs-patch/cgcs_make_patch' \
|
||||||
|
--exclude='.git*' \
|
||||||
|
--exclude='build' \
|
||||||
|
--exclude='.pc' \
|
||||||
|
--exclude='patches' \
|
||||||
|
--exclude="$DISTRO" \
|
||||||
|
--exclude='pbr-*.egg' \
|
||||||
|
--transform "s,^$SRC_DIR/LICENSE,LICENSE," \
|
||||||
|
--transform "s,^$SRC_DIR,$TAR_NAME-$VERSION,"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
for SPEC in `ls $BUILD_DIR/SPECS`; do
|
||||||
|
SPEC_PATH="$BUILD_DIR/SPECS/$SPEC"
|
||||||
|
RELEASE=`spec_find_tag Release "$SPEC_PATH" 2>> /dev/null`
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "ERROR: 'Release' not found in '$SPEC_PATH'"
|
||||||
|
fi
|
||||||
|
NAME=`spec_find_tag Name "$SPEC_PATH" 2>> /dev/null`
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "ERROR: 'Name' not found in '$SPEC_PATH'"
|
||||||
|
fi
|
||||||
|
SRPM="$NAME-$VERSION-$RELEASE.src.rpm"
|
||||||
|
SRPM_PATH="$BUILD_DIR/SRPMS/$SRPM"
|
||||||
|
|
||||||
|
BUILD_NEEDED=0
|
||||||
|
if [ -f $SRPM_PATH ]; then
|
||||||
|
n=`find . -cnewer $SRPM_PATH | wc -l`
|
||||||
|
if [ $n -gt 0 ]; then
|
||||||
|
BUILD_NEEDED=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
BUILD_NEEDED=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $BUILD_NEEDED -gt 0 ]; then
|
||||||
|
echo "SPEC file: $SPEC_PATH"
|
||||||
|
echo "SRPM build directory: $BUILD_DIR"
|
||||||
|
echo "TIS_PATCH_VER: $TIS_PATCH_VER"
|
||||||
|
|
||||||
|
sed -i -e "1 i%define tis_patch_ver $TIS_PATCH_VER" $SPEC_PATH
|
||||||
|
rpmbuild -bs $SPEC_PATH --define="%_topdir $BUILD_DIR" --define="_tis_dist .tis"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
TIS_PATCH_VER=25
|
|
@ -0,0 +1,180 @@
|
||||||
|
Summary: TIS Platform Patching
|
||||||
|
Name: cgcs-patch
|
||||||
|
Version: 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
|
||||||
|
|
||||||
|
BuildRequires: python-setuptools
|
||||||
|
BuildRequires: systemd-units
|
||||||
|
BuildRequires: systemd-devel
|
||||||
|
Requires: python-devel
|
||||||
|
Requires: /bin/bash
|
||||||
|
|
||||||
|
%description
|
||||||
|
TIS Platform Patching
|
||||||
|
|
||||||
|
%define pythonroot /usr/lib64/python2.7/site-packages
|
||||||
|
|
||||||
|
%define debug_package %{nil}
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup
|
||||||
|
|
||||||
|
%build
|
||||||
|
%{__python} setup.py build
|
||||||
|
|
||||||
|
%install
|
||||||
|
%{__python} setup.py install --root=$RPM_BUILD_ROOT \
|
||||||
|
--install-lib=%{pythonroot} \
|
||||||
|
--prefix=/usr \
|
||||||
|
--install-data=/usr/share \
|
||||||
|
--single-version-externally-managed
|
||||||
|
|
||||||
|
install -m 755 -d %{buildroot}%{_sbindir}
|
||||||
|
install -m 755 -d %{buildroot}%{_sysconfdir}/bash_completion.d
|
||||||
|
install -m 755 -d %{buildroot}%{_sysconfdir}/goenabled.d
|
||||||
|
install -m 755 -d %{buildroot}%{_sysconfdir}/init.d
|
||||||
|
install -m 755 -d %{buildroot}%{_sysconfdir}/logrotate.d
|
||||||
|
install -m 755 -d %{buildroot}%{_sysconfdir}/patching
|
||||||
|
install -m 700 -d %{buildroot}%{_sysconfdir}/patching/patch-scripts
|
||||||
|
install -m 755 -d %{buildroot}%{_sysconfdir}/pmon.d
|
||||||
|
install -m 755 -d %{buildroot}%{_unitdir}
|
||||||
|
|
||||||
|
|
||||||
|
install -m 500 ${RPM_BUILD_DIR}/bin/sw-patch-agent \
|
||||||
|
%{buildroot}%{_sbindir}/sw-patch-agent
|
||||||
|
install -m 500 ${RPM_BUILD_DIR}/bin/sw-patch-controller-daemon \
|
||||||
|
%{buildroot}%{_sbindir}/sw-patch-controller-daemon
|
||||||
|
install -m 555 ${RPM_BUILD_DIR}/bin/sw-patch \
|
||||||
|
%{buildroot}%{_sbindir}/sw-patch
|
||||||
|
|
||||||
|
install -m 555 ${RPM_BUILD_DIR}/bin/rpm-audit \
|
||||||
|
%{buildroot}%{_sbindir}/rpm-audit
|
||||||
|
|
||||||
|
install -m 500 ${RPM_BUILD_DIR}/bin/sw-patch-controller-daemon-init.sh \
|
||||||
|
%{buildroot}%{_sysconfdir}/init.d/sw-patch-controller-daemon
|
||||||
|
install -m 500 ${RPM_BUILD_DIR}/bin/sw-patch-agent-init.sh \
|
||||||
|
%{buildroot}%{_sysconfdir}/init.d/sw-patch-agent
|
||||||
|
|
||||||
|
install -m 600 ${RPM_BUILD_DIR}/bin/patching.conf \
|
||||||
|
%{buildroot}%{_sysconfdir}/patching/patching.conf
|
||||||
|
install -m 644 ${RPM_BUILD_DIR}/bin/policy.json \
|
||||||
|
%{buildroot}%{_sysconfdir}/patching/policy.json
|
||||||
|
|
||||||
|
install -m 444 ${RPM_BUILD_DIR}/bin/pmon-sw-patch-controller-daemon.conf \
|
||||||
|
%{buildroot}%{_sysconfdir}/pmon.d/sw-patch-controller-daemon.conf
|
||||||
|
install -m 444 ${RPM_BUILD_DIR}/bin/pmon-sw-patch-agent.conf \
|
||||||
|
%{buildroot}%{_sysconfdir}/pmon.d/sw-patch-agent.conf
|
||||||
|
|
||||||
|
install -m 444 ${RPM_BUILD_DIR}/bin/*.service %{buildroot}%{_unitdir}
|
||||||
|
|
||||||
|
install -m 444 ${RPM_BUILD_DIR}/bin/sw-patch.completion %{buildroot}%{_sysconfdir}/bash_completion.d/sw-patch
|
||||||
|
|
||||||
|
install -m 400 ${RPM_BUILD_DIR}/bin/patch-functions \
|
||||||
|
%{buildroot}%{_sysconfdir}/patching/patch-functions
|
||||||
|
|
||||||
|
install -D -m 444 ${RPM_BUILD_DIR}/bin/patch-tmpdirs.conf \
|
||||||
|
%{buildroot}%{_tmpfilesdir}/patch-tmpdirs.conf
|
||||||
|
install -m 500 ${RPM_BUILD_DIR}/bin/run-patch-scripts \
|
||||||
|
%{buildroot}%{_sbindir}/run-patch-scripts
|
||||||
|
|
||||||
|
install -m 500 ${RPM_BUILD_DIR}/bin/sw-patch-controller-daemon-restart \
|
||||||
|
%{buildroot}%{_sbindir}/sw-patch-controller-daemon-restart
|
||||||
|
install -m 500 ${RPM_BUILD_DIR}/bin/sw-patch-agent-restart \
|
||||||
|
%{buildroot}%{_sbindir}/sw-patch-agent-restart
|
||||||
|
|
||||||
|
install -m 500 ${RPM_BUILD_DIR}/bin/sw-patch-init.sh \
|
||||||
|
%{buildroot}%{_sysconfdir}/init.d/sw-patch
|
||||||
|
install -m 500 ${RPM_BUILD_DIR}/bin/sw-patch-controller-init.sh \
|
||||||
|
%{buildroot}%{_sysconfdir}/init.d/sw-patch-controller
|
||||||
|
|
||||||
|
install -m 555 ${RPM_BUILD_DIR}/bin/patch_check_goenabled.sh \
|
||||||
|
%{buildroot}%{_sysconfdir}/goenabled.d/patch_check_goenabled.sh
|
||||||
|
|
||||||
|
install -m 444 ${RPM_BUILD_DIR}/bin/patching.logrotate \
|
||||||
|
%{buildroot}%{_sysconfdir}/logrotate.d/patching
|
||||||
|
|
||||||
|
install -m 500 ${RPM_BUILD_DIR}/bin/upgrade-start-pkg-extract \
|
||||||
|
%{buildroot}%{_sbindir}/upgrade-start-pkg-extract
|
||||||
|
|
||||||
|
%clean
|
||||||
|
rm -rf $RPM_BUILD_ROOT
|
||||||
|
|
||||||
|
%package -n cgcs-patch-controller
|
||||||
|
Summary: TIS Platform Patching
|
||||||
|
Group: base
|
||||||
|
Requires: /usr/bin/env
|
||||||
|
Requires: /bin/sh
|
||||||
|
Requires: requests-toolbelt
|
||||||
|
Requires: createrepo
|
||||||
|
Requires(post): /usr/bin/env
|
||||||
|
Requires(post): /bin/sh
|
||||||
|
|
||||||
|
%description -n cgcs-patch-controller
|
||||||
|
TIS Platform Patching
|
||||||
|
|
||||||
|
%post -n cgcs-patch-controller
|
||||||
|
/usr/bin/systemctl enable sw-patch-controller.service
|
||||||
|
/usr/bin/systemctl enable sw-patch-controller-daemon.service
|
||||||
|
|
||||||
|
|
||||||
|
%package -n cgcs-patch-agent
|
||||||
|
Summary: TIS Platform Patching
|
||||||
|
Group: base
|
||||||
|
Requires: /usr/bin/env
|
||||||
|
Requires: /bin/sh
|
||||||
|
Requires(post): /usr/bin/env
|
||||||
|
Requires(post): /bin/sh
|
||||||
|
|
||||||
|
%description -n cgcs-patch-agent
|
||||||
|
TIS Platform Patching
|
||||||
|
|
||||||
|
%post -n cgcs-patch-agent
|
||||||
|
/usr/bin/systemctl enable sw-patch-agent.service
|
||||||
|
|
||||||
|
%post
|
||||||
|
/usr/bin/systemctl enable sw-patch.service
|
||||||
|
|
||||||
|
%files
|
||||||
|
%license ../LICENSE
|
||||||
|
%defattr(-,root,root,-)
|
||||||
|
%{pythonroot}/cgcs_patch
|
||||||
|
%{pythonroot}/cgcs_patch-*.egg-info
|
||||||
|
%{_sbindir}/rpm-audit
|
||||||
|
%config(noreplace) %{_sysconfdir}/patching/policy.json
|
||||||
|
%config(noreplace) %{_sysconfdir}/patching/patching.conf
|
||||||
|
%dir %{_sysconfdir}/patching/patch-scripts
|
||||||
|
%{_sysconfdir}/patching/patch-functions
|
||||||
|
%{_tmpfilesdir}/patch-tmpdirs.conf
|
||||||
|
%{_sbindir}/run-patch-scripts
|
||||||
|
%{_sysconfdir}/init.d/sw-patch
|
||||||
|
%{_unitdir}/sw-patch.service
|
||||||
|
%{_sysconfdir}/goenabled.d/patch_check_goenabled.sh
|
||||||
|
%{_sysconfdir}/logrotate.d/patching
|
||||||
|
|
||||||
|
%files -n cgcs-patch-controller
|
||||||
|
%defattr(-,root,root,-)
|
||||||
|
%{_sbindir}/sw-patch
|
||||||
|
%{_sbindir}/sw-patch-controller-daemon
|
||||||
|
%{_sbindir}/sw-patch-controller-daemon-restart
|
||||||
|
%{_sbindir}/upgrade-start-pkg-extract
|
||||||
|
%{_sysconfdir}/pmon.d/sw-patch-controller-daemon.conf
|
||||||
|
%{_sysconfdir}/init.d/sw-patch-controller-daemon
|
||||||
|
%{_unitdir}/sw-patch-controller-daemon.service
|
||||||
|
%{_sysconfdir}/bash_completion.d/sw-patch
|
||||||
|
%{_sysconfdir}/init.d/sw-patch-controller
|
||||||
|
%{_unitdir}/sw-patch-controller.service
|
||||||
|
|
||||||
|
%files -n cgcs-patch-agent
|
||||||
|
%defattr(-,root,root,-)
|
||||||
|
%{_sbindir}/sw-patch-agent
|
||||||
|
%{_sbindir}/sw-patch-agent-restart
|
||||||
|
%{_sysconfdir}/pmon.d/sw-patch-agent.conf
|
||||||
|
%{_sysconfdir}/init.d/sw-patch-agent
|
||||||
|
%{_unitdir}/sw-patch-agent.service
|
||||||
|
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
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.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,226 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# repos
|
||||||
|
UPSTREAM_CLONE="git://vxgit.wrs.com/git"
|
||||||
|
# UPSTREAM_PUSH="ssh://vxgit.wrs.com/git"
|
||||||
|
ROOT_REPO=cgcs-root
|
||||||
|
|
||||||
|
JENKINS_HOST=yow-cgts3-lx.wrs.com
|
||||||
|
|
||||||
|
# SOURCE_CONTEXT=TC_17.06
|
||||||
|
# SOURCE_JENKINS_BUILD=TC_17.06_Pull
|
||||||
|
# PREFIX=TC
|
||||||
|
# SW_VERSION=18.03
|
||||||
|
# JOB=patching
|
||||||
|
USAGE=0
|
||||||
|
|
||||||
|
if [ x"$1" = x ] ; then
|
||||||
|
echo "ERROR: You must specify a source context"
|
||||||
|
USAGE=1
|
||||||
|
fi
|
||||||
|
SOURCE_CONTEXT=$1
|
||||||
|
|
||||||
|
if [ x"$2" = x ] ; then
|
||||||
|
echo "ERROR: You must specify a source context"
|
||||||
|
USAGE=1
|
||||||
|
fi
|
||||||
|
SOURCE_JENKINS_BUILD=$2
|
||||||
|
|
||||||
|
if [ x"$3" = x ] ; then
|
||||||
|
echo "ERROR: You must specify a prefix for patch and patch branch names"
|
||||||
|
USAGE=1
|
||||||
|
fi
|
||||||
|
PREFIX=$3
|
||||||
|
|
||||||
|
if [ x"$4" = x ] ; then
|
||||||
|
echo "ERROR: You must specify a sw_version"
|
||||||
|
USAGE=1
|
||||||
|
fi
|
||||||
|
SW_VERSION=$4
|
||||||
|
|
||||||
|
if [ x"$5" = x ] ; then
|
||||||
|
echo "ERROR: You must specify a job directory"
|
||||||
|
USAGE=1
|
||||||
|
fi
|
||||||
|
JOB=$5
|
||||||
|
|
||||||
|
if [ $USAGE -ne 0 ] ; then
|
||||||
|
echo "USAGE: make_patching_branch <source_context> <jenkins_src_job> <prefix> <sw_version> <repo_dir>"
|
||||||
|
echo " e.g. make_patching_branch CGCS_DEV_0007 Secure_Src_Pull_CGCS_DEV_0007 CGCS 14.10 testpatch"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PATCH_BRANCH=$PREFIX"_"$SW_VERSION"_PATCHING"
|
||||||
|
PATCH_TAG0=v$PREFIX"_"$SW_VERSION"_PATCH_0000"
|
||||||
|
MY_LOCAL_DISK=/localdisk/designer/$USER/$JOB
|
||||||
|
MY_REPO=$MY_LOCAL_DISK
|
||||||
|
|
||||||
|
if [[ "$JOB" = /* ]]
|
||||||
|
then
|
||||||
|
MY_LOCAL_DISK=$JOB
|
||||||
|
MY_REPO=$JOB
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo "PREFIX=$PREFIX"
|
||||||
|
echo "SW_VERSION=$SW_VERSION"
|
||||||
|
echo "JOB=$JOB"
|
||||||
|
echo "SOURCE_CONTEXT=$SOURCE_CONTEXT"
|
||||||
|
echo "MY_LOCAL_DISK=$MY_LOCAL_DISK"
|
||||||
|
echo "MY_REPO=$MY_REPO"
|
||||||
|
echo "SOURCE_JENKINS_BUILD=$SOURCE_JENKINS_BUILD"
|
||||||
|
echo "PATCH_BRANCH=$PATCH_BRANCH"
|
||||||
|
echo "UPSTREAM_CLONE=$UPSTREAM_CLONE"
|
||||||
|
|
||||||
|
mkdir -p $MY_LOCAL_DISK
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to create directory '$MY_LOCAL_DISK'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd $MY_LOCAL_DISK
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to change to directory '$MY_LOCAL_DISK'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get latest tools
|
||||||
|
if [ ! -d bin ] ; then
|
||||||
|
echo "clone bin"
|
||||||
|
git clone git://git.wrs.com/git/bin
|
||||||
|
else
|
||||||
|
echo "pull bin"
|
||||||
|
cd bin
|
||||||
|
git pull
|
||||||
|
cd $MY_LOCAL_DISK
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
export PATH=$MY_REPO/build-tools/branching:$PATH
|
||||||
|
|
||||||
|
|
||||||
|
# Create repo
|
||||||
|
mkdir -p $MY_REPO
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to create directory '$MY_REPO'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chgrp cgts $MY_REPO
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed chgrp '$MY_REPO'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod 750 $MY_REPO
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to chmod '$MY_REPO'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd $MY_REPO
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to change to directory '$MY_LOCAL_DISK'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d $ROOT_REPO ] ; then
|
||||||
|
WRGIT_ALL_ADDONS=1 wrgit clone $UPSTREAM_CLONE/$ROOT_REPO $ROOT_REPO $SOURCE_CONTEXT
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to clone from repo '$UPSTREAM_CLONE' with context '$SOURCE_CONTEXT'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
MY_REPO=$MY_REPO/$ROOT_REPO
|
||||||
|
else
|
||||||
|
MY_REPO=$MY_REPO/$ROOT_REPO
|
||||||
|
cd $MY_REPO
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to change to directory '$MY_REPO'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
wrgit checkout $SOURCE_CONTEXT
|
||||||
|
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: wrgit checkout '$SOURCE_CONTEXT' failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
wrgit pull
|
||||||
|
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: wrgit pull failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd $MY_REPO
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to change to directory '$MY_REPO'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
git branch | grep $PATCH_BRANCH
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
# Set context
|
||||||
|
CONTEXT_PATH="/localdisk/designer/jenkins/$SOURCE_JENKINS_BUILD/$ROOT_REPO/CONTEXT"
|
||||||
|
if [ -f $CONTEXT_PATH ]; then
|
||||||
|
cp $CONTEXT_PATH ../
|
||||||
|
else
|
||||||
|
CONTEXT_PROVIDER=$JENKINS_HOST:$CONTEXT_PATH
|
||||||
|
scp $CONTEXT_PROVIDER ../
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to obtain context from '$CONTEXT_PROVIDER'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
source ../CONTEXT
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to set context"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git branch | grep $PATCH_BRANCH
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
# create patching branch and tag
|
||||||
|
create_branches_and_tags.sh $PATCH_BRANCH .
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to create branch '$PATCH_BRANCH'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
push_branches_tags.sh $PATCH_BRANCH
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to push branch '$PATCH_BRANCH' to '$UPSTREAM_PUSH'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
wrgit checkout $PATCH_BRANCH
|
||||||
|
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: wrgit checkout '$PATCH_BRANCH' failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
git tag | grep $PATCH_TAG0
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
create_tags.sh $PATCH_TAG0
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to create tag '$PATCH_TAG0'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
push_tags.sh $PATCH_TAG0
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to push branch '$PATCH_BRANCH' to '$UPSTREAM_PUSH'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Real upstream repo
|
||||||
|
# UPSTREAM="git://vxgit.wrs.com/git/cgcs-root"
|
||||||
|
# Testing upstream repo
|
||||||
|
UPSTREAM="git://vxgit.wrs.com/git/users/cgcs/cgcs-root"
|
||||||
|
|
||||||
|
JENKINS_HOST=yow-cgts4-lx.wrs.com
|
||||||
|
|
||||||
|
# TAG=GCGS_14.10_PATCH_0001
|
||||||
|
# JOB=playground
|
||||||
|
USAGE=0
|
||||||
|
|
||||||
|
|
||||||
|
if [ x"$1" = x ] ; then
|
||||||
|
echo "ERROR: You must specify a PATCH_ID"
|
||||||
|
USAGE=1
|
||||||
|
fi
|
||||||
|
PATCH_ID=$1
|
||||||
|
|
||||||
|
if [ x"$2" = x ] ; then
|
||||||
|
echo "ERROR: You must specify a job directory"
|
||||||
|
USAGE=1
|
||||||
|
fi
|
||||||
|
JOB=$2
|
||||||
|
|
||||||
|
if [ $USAGE -ne 0 ] ; then
|
||||||
|
echo "USAGE: make_patching_tag <patch_id> <repo_dir>"
|
||||||
|
echo "USAGE: make_patching_tag CGCS_14.10_PATCH_0001 testpatch"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TAG="v$PATCH_ID"
|
||||||
|
MY_LOCAL_DISK=/localdisk/designer/$USER/$JOB
|
||||||
|
MY_REPO=$MY_LOCAL_DISK
|
||||||
|
|
||||||
|
if [[ "$JOB" = /* ]]
|
||||||
|
then
|
||||||
|
MY_LOCAL_DISK=$JOB
|
||||||
|
MY_REPO=$JOB
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo "TAG=$TAG"
|
||||||
|
echo "JOB=$JOB"
|
||||||
|
echo "MY_LOCAL_DISK=$MY_LOCAL_DISK"
|
||||||
|
echo "MY_REPO=$MY_REPO"
|
||||||
|
|
||||||
|
# Get latest tools
|
||||||
|
if [ ! -d bin ] ; then
|
||||||
|
echo "clone bin"
|
||||||
|
git clone git://git.wrs.com/git/bin
|
||||||
|
else
|
||||||
|
echo "pull bin"
|
||||||
|
cd bin
|
||||||
|
git pull
|
||||||
|
cd $MY_LOCAL_DISK
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
export PATH=$MY_REPO/build-tools/branching:$PATH
|
||||||
|
|
||||||
|
|
||||||
|
MY_REPO=$MY_REPO/cgcs-root
|
||||||
|
cd $MY_REPO
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to change to directory '$MY_REPO'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
### wrgit pull
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: wrgit pull failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create patching tag
|
||||||
|
create_tags.sh $TAG .
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to create tag '$TAG'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$USER" = "jenkins" ] ; then
|
||||||
|
sh /localdisk/designer/slittle1/proxy/push_tags.sh $TAG
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to push branch '$TAG' to '$UPSTREAM'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
push_tags.sh $TAG
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to push branch '$TAG' to '$UPSTREAM'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
USAGE=0
|
||||||
|
|
||||||
|
if [ x"$1" = x ] ; then
|
||||||
|
echo "ERROR: You must specify a prefix for patch and patch branch names"
|
||||||
|
USAGE=1
|
||||||
|
fi
|
||||||
|
PREFIX=$1
|
||||||
|
|
||||||
|
if [ x"$2" = x ] ; then
|
||||||
|
echo "ERROR: You must specify a sw_version"
|
||||||
|
USAGE=1
|
||||||
|
fi
|
||||||
|
SW_VERSION=$2
|
||||||
|
|
||||||
|
if [ x"$3" = x ] ; then
|
||||||
|
echo "ERROR: You must specify a job directory"
|
||||||
|
USAGE=1
|
||||||
|
fi
|
||||||
|
JOB=$3
|
||||||
|
|
||||||
|
PATCH_BRANCH=$PREFIX"_"$SW_VERSION"_PATCHING"
|
||||||
|
PATCH_ID0=$PREFIX"_"$SW_VERSION"_PATCH_0000"
|
||||||
|
PATCH_TAG0=v$PATCH_ID0
|
||||||
|
MY_LOCAL_DISK=/localdisk/designer/$USER/$JOB
|
||||||
|
MY_REPO=$MY_LOCAL_DISK/cgcs-root
|
||||||
|
MY_WORKSPACE=/localdisk/loadbuild/$USER/$JOB
|
||||||
|
|
||||||
|
if [[ "$JOB" = /* ]]
|
||||||
|
then
|
||||||
|
MY_LOCAL_DISK=$JOB
|
||||||
|
MY_REPO=$JOB/cgcs-root
|
||||||
|
MY_WORKSPACE=$JOB
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x"$4" != x ] ; then
|
||||||
|
MY_WORKSPACE=$4
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x"$5" != x ] ; then
|
||||||
|
MY_LOCAL_DISK=$(realpath $5/..)
|
||||||
|
fi
|
||||||
|
MY_REPO=$MY_LOCAL_DISK/cgcs-root
|
||||||
|
|
||||||
|
if [ $USAGE -ne 0 ] ; then
|
||||||
|
echo "USAGE: make_patching_workspace <prefix> <sw_version> <repo_dir> [<workspace> [<sscache> [<repo>]]]"
|
||||||
|
echo " e.g. make_patching_workspace TC 18.03 testpatch"
|
||||||
|
echo " e.g. make_patching_workspace TC 18.03 mypatch $MY_WORKSPACE $MY_REPO"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RPM_DB_DIR=$MY_WORKSPACE/export/patch_data
|
||||||
|
RPM_DB=$RPM_DB_DIR/$PATCH_ID0.rpm_db
|
||||||
|
|
||||||
|
echo "PREFIX=$PREFIX"
|
||||||
|
echo "SW_VERSION=$SW_VERSION"
|
||||||
|
echo "JOB=$JOB"
|
||||||
|
echo "MY_LOCAL_DISK=$MY_LOCAL_DISK"
|
||||||
|
echo "MY_REPO=$MY_REPO"
|
||||||
|
echo "MY_WORKSPACE=$MY_WORKSPACE"
|
||||||
|
echo "PATCH_BRANCH=$PATCH_BRANCH"
|
||||||
|
echo "PATCH_TAG0=$PATCH_TAG0"
|
||||||
|
echo "RPM_DB_DIR=$RPM_DB_DIR"
|
||||||
|
echo "RPM_DB=$RPM_DB"
|
||||||
|
|
||||||
|
|
||||||
|
cd $MY_LOCAL_DISK/bin
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to change to directory '$MY_LOCAL_DISK/bin'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export PATH=`pwd`:$PATH
|
||||||
|
|
||||||
|
cd $MY_REPO
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to change to directory '$MY_REPO'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure gits are free of changes that would prevent checkout or pull
|
||||||
|
for d in $(find . -type d -name .git | xargs --max-args=1 dirname)
|
||||||
|
do
|
||||||
|
(cd $d
|
||||||
|
echo $d
|
||||||
|
git clean -df
|
||||||
|
git reset --hard
|
||||||
|
git ls-files --others --exclude-standard | xargs --no-run-if-empty rm
|
||||||
|
if [ ! -f .subgits ]; then
|
||||||
|
if [ -f .gitignore ]; then
|
||||||
|
git ls-files --others --ignored --exclude-from=.gitignore | xargs --no-run-if-empty rm
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
done
|
||||||
|
|
||||||
|
wrgit checkout $PATCH_TAG0
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: wrgit checkout '$PATCH_TAG0' failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create workspace
|
||||||
|
echo "01: mkdir $MY_WORKSPACE"
|
||||||
|
if [ ! -d $MY_WORKSPACE ] ; then
|
||||||
|
mkdir -p $MY_WORKSPACE
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to create directory '$MY_WORKSPACE'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "02: cd $MY_WORKSPACE"
|
||||||
|
cd $MY_WORKSPACE
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to change to directory '$MY_WORKSPACE'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "03: build"
|
||||||
|
if [ ! -f export/bootimage.iso ] ; then
|
||||||
|
echo "04: build pkgs"
|
||||||
|
nice -n 20 ionice -c Idle build-pkgs
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: build-pkgs failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "05: build iso"
|
||||||
|
nice -n 20 ionice -c Idle build-iso
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: build-iso failed "
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "06: rpm db"
|
||||||
|
mkdir -p $RPM_DB_DIR
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to make directory '$RPM_DB_DIR'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" > $RPM_DB
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to write file '$RPM_DB'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for build_type in std rt; do
|
||||||
|
RPM_ROOT_DIR=$MY_WORKSPACE/$build_type/rpmbuild/RPMS
|
||||||
|
echo "RPM_ROOT_DIR=$RPM_ROOT_DIR"
|
||||||
|
cd $RPM_ROOT_DIR
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to change to directory '$RPM_ROOT_DIR'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for d in `find * -type d`; do
|
||||||
|
pushd $d > /dev/null
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: failed to change to directory '$d'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rpm -qp --queryformat "$d %{NAME} %{RELEASE}\n" *rpm >> $RPM_DB 2> /dev/null
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "ERROR: rpm query failed in directory '$d'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
popd > /dev/null
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
echo 'Build is complete'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
|
||||||
|
API_SERVICE_OPTS = [
|
||||||
|
cfg.StrOpt('api_bind_ip',
|
||||||
|
default='127.0.0.1',
|
||||||
|
help='IP for the Patching controller API server to bind to',
|
||||||
|
),
|
||||||
|
cfg.IntOpt('api_port',
|
||||||
|
default=5487,
|
||||||
|
help='The port for the Patching controller API server',
|
||||||
|
),
|
||||||
|
cfg.IntOpt('api_limit_max',
|
||||||
|
default=1000,
|
||||||
|
help='the maximum number of items returned in a single '
|
||||||
|
'response from a collection resource'),
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
opt_group = cfg.OptGroup(name='api',
|
||||||
|
title='Options for the Patching controller api service')
|
||||||
|
CONF.register_group(opt_group)
|
||||||
|
CONF.register_opts(API_SERVICE_OPTS)
|
|
@ -0,0 +1,45 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
#from oslo.config import cfg
|
||||||
|
import pecan
|
||||||
|
|
||||||
|
from cgcs_patch.api import config
|
||||||
|
|
||||||
|
#CONF = cfg.CONF
|
||||||
|
|
||||||
|
def get_pecan_config():
|
||||||
|
# Set up the pecan configuration
|
||||||
|
filename = config.__file__.replace('.pyc', '.py')
|
||||||
|
return pecan.configuration.conf_from_file(filename)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_app(pecan_config=None):
|
||||||
|
if not pecan_config:
|
||||||
|
pecan_config = get_pecan_config()
|
||||||
|
|
||||||
|
pecan.configuration.set_config(dict(pecan_config), overwrite=True)
|
||||||
|
|
||||||
|
app = pecan.make_app(
|
||||||
|
pecan_config.app.root,
|
||||||
|
static_root=pecan_config.app.static_root,
|
||||||
|
template_path=pecan_config.app.template_path,
|
||||||
|
debug=False,
|
||||||
|
force_canonical=getattr(pecan_config.app, 'force_canonical', True),
|
||||||
|
guess_content_type_from_ext=False, # Avoid mime-type lookup
|
||||||
|
)
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
class VersionSelectorApplication(object):
|
||||||
|
def __init__(self):
|
||||||
|
pc = get_pecan_config()
|
||||||
|
self.v1 = setup_app(pecan_config=pc)
|
||||||
|
|
||||||
|
def __call__(self, environ, start_response):
|
||||||
|
return self.v1(environ, start_response)
|
|
@ -0,0 +1,23 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Server Specific Configurations
|
||||||
|
server = {
|
||||||
|
'port': '5487',
|
||||||
|
'host': '127.0.0.1'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pecan Application Configurations
|
||||||
|
app = {
|
||||||
|
'root': 'cgcs_patch.api.controllers.root.RootController',
|
||||||
|
'modules': ['cgcs_patch.authapi'],
|
||||||
|
'static_root': '%(confdir)s/public',
|
||||||
|
'template_path': '%(confdir)s/../templates',
|
||||||
|
'debug': False,
|
||||||
|
'enable_acl': True,
|
||||||
|
'acl_public_routes': [],
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
|
@ -0,0 +1,266 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from pecan import expose, request
|
||||||
|
import cgi
|
||||||
|
import glob
|
||||||
|
|
||||||
|
from cgcs_patch.exceptions import PatchError
|
||||||
|
from cgcs_patch.patch_controller import pc
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from cgcs_patch.patch_functions import LOG
|
||||||
|
|
||||||
|
class PatchAPIController(object):
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query.xml', content_type='application/xml')
|
||||||
|
def index(self):
|
||||||
|
return self.query()
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query.xml', content_type='application/xml')
|
||||||
|
def query(self, **kwargs):
|
||||||
|
try:
|
||||||
|
pd = pc.patch_query_cached(**kwargs)
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error="Error: %s" % e.message)
|
||||||
|
|
||||||
|
return dict(pd=pd)
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('show.xml', content_type='application/xml')
|
||||||
|
def show(self, *args):
|
||||||
|
try:
|
||||||
|
result = pc.patch_query_specific_cached(list(args))
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error="Error: %s" % e.message)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query.xml', content_type='application/xml')
|
||||||
|
def apply(self, *args):
|
||||||
|
if pc.any_patch_host_installing():
|
||||||
|
return dict(error="Rejected: One or more nodes are installing patches.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = pc.patch_apply_api(list(args))
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error="Error: %s" % e.message)
|
||||||
|
|
||||||
|
pc.patch_sync()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query.xml', content_type='application/xml')
|
||||||
|
def remove(self, *args, **kwargs):
|
||||||
|
if pc.any_patch_host_installing():
|
||||||
|
return dict(error="Rejected: One or more nodes are installing patches.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = pc.patch_remove_api(list(args), **kwargs)
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error="Error: %s" % e.message)
|
||||||
|
|
||||||
|
pc.patch_sync()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query.xml', content_type='application/xml')
|
||||||
|
def delete(self, *args):
|
||||||
|
try:
|
||||||
|
result = pc.patch_delete_api(list(args))
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error="Error: %s" % e.message)
|
||||||
|
|
||||||
|
pc.patch_sync()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query.xml', content_type='application/xml')
|
||||||
|
def upload(self):
|
||||||
|
assert isinstance(request.POST['file'], cgi.FieldStorage)
|
||||||
|
fileitem = request.POST['file']
|
||||||
|
|
||||||
|
if not fileitem.filename:
|
||||||
|
return dict(error="Error: No file uploaded")
|
||||||
|
|
||||||
|
fn = '/scratch/' + os.path.basename(fileitem.filename)
|
||||||
|
# This technique cannot copy a very large file. It
|
||||||
|
# requires a lot of memory as all data from the
|
||||||
|
# source file is read into memory then written to
|
||||||
|
# the destination file one chunk
|
||||||
|
# open(fn, 'wb').write(fileitem.file.read())
|
||||||
|
|
||||||
|
# Copying file by chunks using OS system calls
|
||||||
|
# requires much less memory. A larger chunk
|
||||||
|
# size can be used to improve the copy speed;
|
||||||
|
# currently 64K chunk size is selected
|
||||||
|
dst = os.open(fn, os.O_WRONLY | os.O_CREAT)
|
||||||
|
src = fileitem.file.fileno()
|
||||||
|
size = 64*1024
|
||||||
|
n = size
|
||||||
|
while n >= size:
|
||||||
|
s = os.read(src, size)
|
||||||
|
n = os.write(dst, s)
|
||||||
|
os.close(dst)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = pc.patch_import_api([fn])
|
||||||
|
except PatchError as e:
|
||||||
|
os.remove(fn)
|
||||||
|
return dict(error=e.message)
|
||||||
|
|
||||||
|
os.remove(fn)
|
||||||
|
|
||||||
|
pc.patch_sync()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def upload_dir(self, **kwargs):
|
||||||
|
files = []
|
||||||
|
for key, path in kwargs.iteritems():
|
||||||
|
LOG.info("upload-dir: Retrieving patches from %s" % path)
|
||||||
|
for f in glob.glob(path + '/*.patch'):
|
||||||
|
if os.path.isfile(f):
|
||||||
|
files.append(f)
|
||||||
|
|
||||||
|
if len(files) == 0:
|
||||||
|
return dict(error="No patches found")
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = pc.patch_import_api(sorted(files))
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error=e.message)
|
||||||
|
|
||||||
|
pc.patch_sync()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def init_release(self, *args):
|
||||||
|
if len(list(args)) == 0:
|
||||||
|
return dict(error="Release must be specified")
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = pc.patch_init_release_api(list(args)[0])
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error=e.message)
|
||||||
|
|
||||||
|
pc.patch_sync()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def del_release(self, *args):
|
||||||
|
if len(list(args)) == 0:
|
||||||
|
return dict(error="Release must be specified")
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = pc.patch_del_release_api(list(args)[0])
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error=e.message)
|
||||||
|
|
||||||
|
pc.patch_sync()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query_hosts.xml', content_type='application/xml')
|
||||||
|
def query_hosts(self, *args):
|
||||||
|
return dict(data=pc.query_host_cache())
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query.xml', content_type='application/xml')
|
||||||
|
def what_requires(self, *args):
|
||||||
|
try:
|
||||||
|
result = pc.patch_query_what_requires(list(args))
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error="Error: %s" % e.message)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query.xml', content_type='application/xml')
|
||||||
|
def host_install(self, *args):
|
||||||
|
return dict(error="Deprecated: Use host_install_async")
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query.xml', content_type='application/xml')
|
||||||
|
def host_install_async(self, *args):
|
||||||
|
if len(list(args)) == 0:
|
||||||
|
return dict(error="Host must be specified for install")
|
||||||
|
force = False
|
||||||
|
if len(list(args)) > 1 and 'force' in list(args)[1:]:
|
||||||
|
force = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = pc.patch_host_install(list(args)[0], force, async=True)
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error="Error: %s" % e.message)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
@expose('query.xml', content_type='application/xml')
|
||||||
|
def drop_host(self, *args):
|
||||||
|
if len(list(args)) == 0:
|
||||||
|
return dict(error="Host must be specified")
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = pc.drop_host(list(args)[0])
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error="Error: %s" % e.message)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def query_dependencies(self, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
result = pc.patch_query_dependencies(list(args), **kwargs)
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error=e.message)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def commit(self, *args):
|
||||||
|
try:
|
||||||
|
result = pc.patch_commit(list(args))
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error=e.message)
|
||||||
|
|
||||||
|
pc.patch_sync()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def commit_dry_run(self, *args):
|
||||||
|
try:
|
||||||
|
result = pc.patch_commit(list(args), dry_run=True)
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(error=e.message)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class RootController(object):
|
||||||
|
|
||||||
|
@expose()
|
||||||
|
@expose('json')
|
||||||
|
def index(self):
|
||||||
|
return "Titanium Cloud Patching API, Available versions: /v1"
|
||||||
|
|
||||||
|
patch = PatchAPIController()
|
||||||
|
v1 = PatchAPIController()
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pecan import make_app
|
||||||
|
from cgcs_patch import model
|
||||||
|
|
||||||
|
|
||||||
|
def setup_app(config):
|
||||||
|
|
||||||
|
model.init_model()
|
||||||
|
|
||||||
|
return make_app(
|
||||||
|
config.app.root,
|
||||||
|
static_root=config.app.static_root,
|
||||||
|
template_path=config.app.template_path,
|
||||||
|
logging=getattr(config, 'logging', {}),
|
||||||
|
debug=getattr(config.app, 'debug', False),
|
||||||
|
force_canonical=getattr(config.app, 'force_canonical', True),
|
||||||
|
guess_content_type_from_ext=getattr(
|
||||||
|
config.app,
|
||||||
|
'guess_content_type_from_ext',
|
||||||
|
True),
|
||||||
|
)
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Copyright (c) 2013-2017 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
API_SERVICE_OPTS = [
|
||||||
|
cfg.StrOpt('auth_api_bind_ip',
|
||||||
|
default=None,
|
||||||
|
help='IP for the authenticated Patching API server to bind to'),
|
||||||
|
cfg.IntOpt('auth_api_port',
|
||||||
|
default=5491,
|
||||||
|
help='The port for the authenticated Patching API server'),
|
||||||
|
cfg.IntOpt('api_limit_max',
|
||||||
|
default=1000,
|
||||||
|
help='the maximum number of items returned in a single '
|
||||||
|
'response from a collection resource')
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
opt_group = cfg.OptGroup(name='api',
|
||||||
|
title='Options for the patch-api service')
|
||||||
|
CONF.register_group(opt_group)
|
||||||
|
CONF.register_opts(API_SERVICE_OPTS)
|
|
@ -0,0 +1,28 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
"""Access Control Lists (ACL's) control access the API server."""
|
||||||
|
|
||||||
|
from cgcs_patch.authapi import auth_token
|
||||||
|
|
||||||
|
OPT_GROUP_NAME = 'keystone_authtoken'
|
||||||
|
|
||||||
|
|
||||||
|
def install(app, conf, public_routes):
|
||||||
|
"""Install ACL check on application.
|
||||||
|
|
||||||
|
:param app: A WSGI application.
|
||||||
|
:param conf: Settings. Must include OPT_GROUP_NAME section.
|
||||||
|
:param public_routes: The list of the routes which will be allowed
|
||||||
|
access without authentication.
|
||||||
|
:return: The same WSGI application with ACL installed.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
keystone_config = dict(conf.items(OPT_GROUP_NAME))
|
||||||
|
return auth_token.AuthTokenMiddleware(app,
|
||||||
|
conf=keystone_config,
|
||||||
|
public_api_routes=public_routes)
|
|
@ -0,0 +1,77 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
import pecan
|
||||||
|
|
||||||
|
from cgcs_patch.authapi import acl
|
||||||
|
from cgcs_patch.authapi import config
|
||||||
|
from cgcs_patch.authapi import hooks
|
||||||
|
from cgcs_patch.authapi import policy
|
||||||
|
|
||||||
|
import ConfigParser
|
||||||
|
|
||||||
|
auth_opts = [
|
||||||
|
cfg.StrOpt('auth_strategy',
|
||||||
|
default='keystone',
|
||||||
|
help='Method to use for auth: noauth or keystone.'),
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
CONF.register_opts(auth_opts)
|
||||||
|
|
||||||
|
|
||||||
|
def get_pecan_config():
|
||||||
|
# Set up the pecan configuration
|
||||||
|
filename = config.__file__.replace('.pyc', '.py')
|
||||||
|
return pecan.configuration.conf_from_file(filename)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_app(pecan_config=None, extra_hooks=None):
|
||||||
|
config = ConfigParser.RawConfigParser()
|
||||||
|
config.read('/etc/patching/patching.conf')
|
||||||
|
|
||||||
|
policy.init()
|
||||||
|
|
||||||
|
app_hooks = [hooks.ConfigHook(),
|
||||||
|
hooks.ContextHook(pecan_config.app.acl_public_routes),
|
||||||
|
]
|
||||||
|
if extra_hooks:
|
||||||
|
app_hooks.extend(extra_hooks)
|
||||||
|
|
||||||
|
if not pecan_config:
|
||||||
|
pecan_config = get_pecan_config()
|
||||||
|
|
||||||
|
if pecan_config.app.enable_acl:
|
||||||
|
app_hooks.append(hooks.AdminAuthHook())
|
||||||
|
|
||||||
|
pecan.configuration.set_config(dict(pecan_config), overwrite=True)
|
||||||
|
|
||||||
|
app = pecan.make_app(
|
||||||
|
pecan_config.app.root,
|
||||||
|
static_root=pecan_config.app.static_root,
|
||||||
|
template_path=pecan_config.app.template_path,
|
||||||
|
debug=False,
|
||||||
|
force_canonical=getattr(pecan_config.app, 'force_canonical', True),
|
||||||
|
hooks=app_hooks,
|
||||||
|
guess_content_type_from_ext=False, # Avoid mime-type lookup
|
||||||
|
)
|
||||||
|
|
||||||
|
if pecan_config.app.enable_acl:
|
||||||
|
return acl.install(app, config, pecan_config.app.acl_public_routes)
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
class VersionSelectorApplication(object):
|
||||||
|
def __init__(self):
|
||||||
|
pc = get_pecan_config()
|
||||||
|
pc.app.enable_acl = (CONF.auth_strategy == 'keystone')
|
||||||
|
self.v1 = setup_app(pecan_config=pc)
|
||||||
|
|
||||||
|
def __call__(self, environ, start_response):
|
||||||
|
return self.v1(environ, start_response)
|
|
@ -0,0 +1,38 @@
|
||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from keystonemiddleware import auth_token
|
||||||
|
from sysinv.common import utils
|
||||||
|
|
||||||
|
|
||||||
|
class AuthTokenMiddleware(auth_token.AuthProtocol):
|
||||||
|
"""A wrapper on Keystone auth_token middleware.
|
||||||
|
|
||||||
|
Does not perform verification of authentication tokens
|
||||||
|
for public routes in the API.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, app, conf, public_api_routes=[]):
|
||||||
|
self.public_api_routes = set(public_api_routes)
|
||||||
|
|
||||||
|
super(AuthTokenMiddleware, self).__init__(app, conf)
|
||||||
|
|
||||||
|
def __call__(self, env, start_response):
|
||||||
|
path = utils.safe_rstrip(env.get('PATH_INFO'), '/')
|
||||||
|
|
||||||
|
if path in self.public_api_routes:
|
||||||
|
return self.app(env, start_response)
|
||||||
|
|
||||||
|
return super(AuthTokenMiddleware, self).__call__(env, start_response)
|
|
@ -0,0 +1,23 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Server Specific Configurations
|
||||||
|
server = {
|
||||||
|
'port': '5491',
|
||||||
|
'host': '0.0.0.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pecan Application Configurations
|
||||||
|
app = {
|
||||||
|
'root': 'cgcs_patch.api.controllers.root.RootController',
|
||||||
|
'modules': ['cgcs_patch.api'],
|
||||||
|
'static_root': '%(confdir)s/public',
|
||||||
|
'template_path': '%(confdir)s/../templates',
|
||||||
|
'debug': False,
|
||||||
|
'enable_acl': True,
|
||||||
|
'acl_public_routes': [],
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright © 2012 New Dream Network, LLC (DreamHost)
|
||||||
|
#
|
||||||
|
# Author: Doug Hellmann <doug.hellmann@dreamhost.com>
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-2017 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
from pecan import hooks
|
||||||
|
|
||||||
|
from sysinv.common import context
|
||||||
|
from sysinv.common import utils
|
||||||
|
from sysinv.openstack.common import policy
|
||||||
|
from webob import exc
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigHook(hooks.PecanHook):
|
||||||
|
"""Attach the config object to the request so controllers can get to it."""
|
||||||
|
|
||||||
|
def before(self, state):
|
||||||
|
state.request.cfg = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class ContextHook(hooks.PecanHook):
|
||||||
|
"""Configures a request context and attaches it to the request.
|
||||||
|
|
||||||
|
The following HTTP request headers are used:
|
||||||
|
|
||||||
|
X-User-Id or X-User:
|
||||||
|
Used for context.user_id.
|
||||||
|
|
||||||
|
X-Tenant-Id or X-Tenant:
|
||||||
|
Used for context.tenant.
|
||||||
|
|
||||||
|
X-Auth-Token:
|
||||||
|
Used for context.auth_token.
|
||||||
|
|
||||||
|
X-Roles:
|
||||||
|
Used for setting context.is_admin flag to either True or False.
|
||||||
|
The flag is set to True, if X-Roles contains either an administrator
|
||||||
|
or admin substring. Otherwise it is set to False.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, public_api_routes):
|
||||||
|
self.public_api_routes = public_api_routes
|
||||||
|
super(ContextHook, self).__init__()
|
||||||
|
|
||||||
|
def before(self, state):
|
||||||
|
user_id = state.request.headers.get('X-User-Id')
|
||||||
|
user_id = state.request.headers.get('X-User', user_id)
|
||||||
|
tenant = state.request.headers.get('X-Tenant-Id')
|
||||||
|
tenant = state.request.headers.get('X-Tenant', tenant)
|
||||||
|
domain_id = state.request.headers.get('X-User-Domain-Id')
|
||||||
|
domain_name = state.request.headers.get('X-User-Domain-Name')
|
||||||
|
auth_token = state.request.headers.get('X-Auth-Token', None)
|
||||||
|
creds = {'roles': state.request.headers.get('X-Roles', '').split(',')}
|
||||||
|
|
||||||
|
is_admin = policy.check('admin', state.request.headers, creds)
|
||||||
|
|
||||||
|
path = utils.safe_rstrip(state.request.path, '/')
|
||||||
|
is_public_api = path in self.public_api_routes
|
||||||
|
|
||||||
|
state.request.context = context.RequestContext(
|
||||||
|
auth_token=auth_token,
|
||||||
|
user=user_id,
|
||||||
|
tenant=tenant,
|
||||||
|
domain_id=domain_id,
|
||||||
|
domain_name=domain_name,
|
||||||
|
is_admin=is_admin,
|
||||||
|
is_public_api=is_public_api)
|
||||||
|
|
||||||
|
|
||||||
|
class AdminAuthHook(hooks.PecanHook):
|
||||||
|
"""Verify that the user has admin rights.
|
||||||
|
|
||||||
|
Checks whether the request context is an admin context and
|
||||||
|
rejects the request otherwise.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def before(self, state):
|
||||||
|
ctx = state.request.context
|
||||||
|
is_admin_api = policy.check('admin_api', {}, ctx.to_dict())
|
||||||
|
|
||||||
|
if not is_admin_api and not ctx.is_public_api:
|
||||||
|
raise exc.HTTPForbidden()
|
|
@ -0,0 +1,117 @@
|
||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright (c) 2011 OpenStack Foundation
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""Policy Engine For Patching."""
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
from sysinv.common import exception
|
||||||
|
from sysinv.common import utils
|
||||||
|
from sysinv.openstack.common import policy
|
||||||
|
|
||||||
|
|
||||||
|
_POLICY_PATH = None
|
||||||
|
_POLICY_CACHE = {}
|
||||||
|
|
||||||
|
def reset():
|
||||||
|
global _POLICY_PATH
|
||||||
|
global _POLICY_CACHE
|
||||||
|
_POLICY_PATH = None
|
||||||
|
_POLICY_CACHE = {}
|
||||||
|
policy.reset()
|
||||||
|
|
||||||
|
|
||||||
|
def init():
|
||||||
|
global _POLICY_PATH
|
||||||
|
global _POLICY_CACHE
|
||||||
|
if not _POLICY_PATH:
|
||||||
|
_POLICY_PATH = '/etc/patching/policy.json'
|
||||||
|
if not os.path.exists(_POLICY_PATH):
|
||||||
|
raise exception.ConfigNotFound(message='/etc/patching/policy.json')
|
||||||
|
utils.read_cached_file(_POLICY_PATH, _POLICY_CACHE,
|
||||||
|
reload_func=_set_rules)
|
||||||
|
|
||||||
|
|
||||||
|
def _set_rules(data):
|
||||||
|
default_rule = "rule:admin_api"
|
||||||
|
policy.set_rules(policy.Rules.load_json(data, default_rule))
|
||||||
|
|
||||||
|
|
||||||
|
def enforce(context, action, target, do_raise=True):
|
||||||
|
"""Verifies that the action is valid on the target in this context.
|
||||||
|
|
||||||
|
:param context: sysinv context
|
||||||
|
:param action: string representing the action to be checked
|
||||||
|
this should be colon separated for clarity.
|
||||||
|
i.e. ``compute:create_instance``,
|
||||||
|
``compute:attach_volume``,
|
||||||
|
``volume:attach_volume``
|
||||||
|
:param target: dictionary representing the object of the action
|
||||||
|
for object creation this should be a dictionary representing the
|
||||||
|
location of the object e.g. ``{'project_id': context.project_id}``
|
||||||
|
:param do_raise: if True (the default), raises PolicyNotAuthorized;
|
||||||
|
if False, returns False
|
||||||
|
|
||||||
|
:raises sysinv.exception.PolicyNotAuthorized: if verification fails
|
||||||
|
and do_raise is True.
|
||||||
|
|
||||||
|
:return: returns a non-False value (not necessarily "True") if
|
||||||
|
authorized, and the exact value False if not authorized and
|
||||||
|
do_raise is False.
|
||||||
|
"""
|
||||||
|
init()
|
||||||
|
|
||||||
|
credentials = context.to_dict()
|
||||||
|
|
||||||
|
# Add the exception arguments if asked to do a raise
|
||||||
|
extra = {}
|
||||||
|
if do_raise:
|
||||||
|
extra.update(exc=exception.PolicyNotAuthorized, action=action)
|
||||||
|
|
||||||
|
return policy.check(action, target, credentials, **extra)
|
||||||
|
|
||||||
|
|
||||||
|
def check_is_admin(context):
|
||||||
|
"""Whether or not role contains 'admin' role according to policy setting.
|
||||||
|
|
||||||
|
"""
|
||||||
|
init()
|
||||||
|
|
||||||
|
credentials = context.to_dict()
|
||||||
|
target = credentials
|
||||||
|
|
||||||
|
return policy.check('context_is_admin', target, credentials)
|
||||||
|
|
||||||
|
|
||||||
|
@policy.register('context_is_admin')
|
||||||
|
class IsAdminCheck(policy.Check):
|
||||||
|
"""An explicit check for is_admin."""
|
||||||
|
|
||||||
|
def __init__(self, kind, match):
|
||||||
|
"""Initialize the check."""
|
||||||
|
|
||||||
|
self.expected = (match.lower() == 'true')
|
||||||
|
|
||||||
|
super(IsAdminCheck, self).__init__(kind, str(self.expected))
|
||||||
|
|
||||||
|
def __call__(self, target, creds):
|
||||||
|
"""Determine whether is_admin matches the requested value."""
|
||||||
|
|
||||||
|
return creds['is_admin'] == self.expected
|
|
@ -0,0 +1,166 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2017-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
|
||||||
|
import cgcs_patch.utils as utils
|
||||||
|
import cgcs_patch.config as cfg
|
||||||
|
import cgcs_patch.constants as constants
|
||||||
|
from cgcs_patch.patch_functions import LOG
|
||||||
|
|
||||||
|
|
||||||
|
class PatchService:
|
||||||
|
def __init__(self):
|
||||||
|
self.sock_out = None
|
||||||
|
self.sock_in = None
|
||||||
|
self.service_type = None
|
||||||
|
self.port = None
|
||||||
|
self.mcast_addr = None
|
||||||
|
self.socket_lock = None
|
||||||
|
|
||||||
|
def update_config(self):
|
||||||
|
# Implemented in subclass
|
||||||
|
pass
|
||||||
|
|
||||||
|
def socket_lock_acquire(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def socket_lock_release(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def setup_socket_ipv4(self):
|
||||||
|
mgmt_ip = cfg.get_mgmt_ip()
|
||||||
|
if mgmt_ip is None:
|
||||||
|
# Don't setup socket unless we have a mgmt ip
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.update_config()
|
||||||
|
|
||||||
|
interface_addr = socket.inet_pton(socket.AF_INET, mgmt_ip)
|
||||||
|
|
||||||
|
# Close sockets, if necessary
|
||||||
|
for s in [self.sock_out, self.sock_in]:
|
||||||
|
if s is not None:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
self.sock_out = socket.socket(socket.AF_INET,
|
||||||
|
socket.SOCK_DGRAM)
|
||||||
|
self.sock_in = socket.socket(socket.AF_INET,
|
||||||
|
socket.SOCK_DGRAM)
|
||||||
|
|
||||||
|
self.sock_out.setblocking(0)
|
||||||
|
self.sock_in.setblocking(0)
|
||||||
|
|
||||||
|
self.sock_out.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
self.sock_in.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
|
||||||
|
self.sock_out.bind((mgmt_ip, 0))
|
||||||
|
self.sock_in.bind(('', self.port))
|
||||||
|
|
||||||
|
# These options are for outgoing multicast messages
|
||||||
|
self.sock_out.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, interface_addr)
|
||||||
|
self.sock_out.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1)
|
||||||
|
# Since only the controllers are sending to this address,
|
||||||
|
# we want the loopback so the local agent can receive it
|
||||||
|
self.sock_out.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
|
||||||
|
|
||||||
|
# Register the multicast group
|
||||||
|
group = socket.inet_pton(socket.AF_INET, self.mcast_addr)
|
||||||
|
mreq = struct.pack('=4s4s', group, interface_addr)
|
||||||
|
|
||||||
|
self.sock_in.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
||||||
|
|
||||||
|
return self.sock_in
|
||||||
|
|
||||||
|
def setup_socket_ipv6(self):
|
||||||
|
mgmt_ip = cfg.get_mgmt_ip()
|
||||||
|
if mgmt_ip is None:
|
||||||
|
# Don't setup socket unless we have a mgmt ip
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.update_config()
|
||||||
|
|
||||||
|
# Close sockets, if necessary
|
||||||
|
for s in [self.sock_out, self.sock_in]:
|
||||||
|
if s is not None:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
self.sock_out = socket.socket(socket.AF_INET6,
|
||||||
|
socket.SOCK_DGRAM)
|
||||||
|
self.sock_in = socket.socket(socket.AF_INET6,
|
||||||
|
socket.SOCK_DGRAM)
|
||||||
|
|
||||||
|
self.sock_out.setblocking(0)
|
||||||
|
self.sock_in.setblocking(0)
|
||||||
|
|
||||||
|
self.sock_out.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
self.sock_in.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
|
||||||
|
self.sock_out.bind((mgmt_ip, 0))
|
||||||
|
self.sock_in.bind(('', self.port))
|
||||||
|
|
||||||
|
# These options are for outgoing multicast messages
|
||||||
|
mgmt_ifindex = utils.if_nametoindex(cfg.get_mgmt_iface())
|
||||||
|
self.sock_out.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, mgmt_ifindex)
|
||||||
|
self.sock_out.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, 1)
|
||||||
|
# Since only the controllers are sending to this address,
|
||||||
|
# we want the loopback so the local agent can receive it
|
||||||
|
self.sock_out.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, 1)
|
||||||
|
|
||||||
|
# Register the multicast group
|
||||||
|
if_index_packed = struct.pack('I', mgmt_ifindex)
|
||||||
|
group = socket.inet_pton(socket.AF_INET6, self.mcast_addr) + if_index_packed
|
||||||
|
self.sock_in.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group)
|
||||||
|
|
||||||
|
return self.sock_in
|
||||||
|
|
||||||
|
def setup_socket(self):
|
||||||
|
self.socket_lock_acquire()
|
||||||
|
|
||||||
|
try:
|
||||||
|
sock_in = None
|
||||||
|
if utils.get_management_version() == constants.ADDRESS_VERSION_IPV6:
|
||||||
|
sock_in = self.setup_socket_ipv6()
|
||||||
|
else:
|
||||||
|
sock_in = self.setup_socket_ipv4()
|
||||||
|
self.socket_lock_release()
|
||||||
|
return sock_in
|
||||||
|
except:
|
||||||
|
LOG.exception("Failed to setup socket")
|
||||||
|
|
||||||
|
# Close sockets, if necessary
|
||||||
|
for s in [self.sock_out, self.sock_in]:
|
||||||
|
if s is not None:
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
self.socket_lock_release()
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def audit_socket(self):
|
||||||
|
# Ensure multicast address is still allocated
|
||||||
|
cmd = "ip maddr show %s | awk 'BEGIN { ORS=\"\" }; {if ($2 == \"%s\") print $2}'" % \
|
||||||
|
(cfg.get_mgmt_iface(), self.mcast_addr)
|
||||||
|
try:
|
||||||
|
result = subprocess.check_output(cmd, shell=True)
|
||||||
|
|
||||||
|
if result == self.mcast_addr:
|
||||||
|
return
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
LOG.error("Command output: %s" % e.output)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Close the socket and set it up again
|
||||||
|
LOG.info("Detected missing multicast addr (%s). Reconfiguring" % self.mcast_addr)
|
||||||
|
while self.setup_socket() is None:
|
||||||
|
LOG.info("Unable to setup sockets. Waiting to retry")
|
||||||
|
time.sleep(5)
|
||||||
|
LOG.info("Multicast address reconfigured")
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
dev_certificate = b"""-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDejCCAmKgAwIBAgICEAQwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UEBhMCQ0Ex
|
||||||
|
EDAOBgNVBAgMB09udGFyaW8xITAfBgNVBAoMGFdpbmQgUml2ZXIgU3lzdGVtcywg
|
||||||
|
SW5jLjAeFw0xNzA4MTgxNDM3MjlaFw0yNzA4MTYxNDM3MjlaMEExCzAJBgNVBAYT
|
||||||
|
AkNBMRAwDgYDVQQIDAdPbnRhcmlvMSAwHgYDVQQKDBdXaW5kIFJpdmVyIFN5c3Rl
|
||||||
|
bXMsIEluYzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALcs0/Te6x69
|
||||||
|
lxQOxudrF+uSC5F9r5bKUnZNWUKHyXKlN4SzZgWGs+fb/DqXIm7piuoQ6GH7GEQd
|
||||||
|
BEN1j/bwp30LZlv0Ur+8jhCvEdqsIP3vUXfv7pv0bomVs0Q8ZRI/FYZhjxYlyFKr
|
||||||
|
gZFV9WPP8S9SwfClHjaYRUudvwvjHHnnnkZ9blVFbXU0Xe83A8fWd0HNqAU1TlmK
|
||||||
|
4CeSi4FI4aRKiXJnOvgv2UoJMI57rBIVKYRUH8uuFpPofOwjOM/Rd6r3Ir+4/CX6
|
||||||
|
+/NALOBIEN6M05ZzoiyiH8NHELknQBqzNs0cXObJWpaSinAOcBnPCc7DNRwgQzjR
|
||||||
|
SdcE9FG1+LcCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3Bl
|
||||||
|
blNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFDRbal2KxU0hQyv4
|
||||||
|
MVnWrW96+aWoMB8GA1UdIwQYMBaAFJaLO1x8+jti7V6pLGbUyqpy0M36MA0GCSqG
|
||||||
|
SIb3DQEBCwUAA4IBAQBmcPFZzEoPtuMPCFvJ/0cmngp8yvCGxWz3JEDkdGYSCVGs
|
||||||
|
TG5e9DeltaHOk6yLvZSRY1so30GQnyB9q8v4DwEGVslKg8u9w/WEU81wl6Q2FZ5s
|
||||||
|
XRP6TASQ0Lbg9e4b3bnTITJJ8jT/zF29NaohgC2fg0UwVuldZLfa7FihJB4//OC1
|
||||||
|
UdNEcmdqTVRqN2oco1n3ZUWKXvG2AvGsoiqu+lsWX1MXacoFvJexSACLrUvOoXMW
|
||||||
|
i38Ofp7XMCAm3rM0cXv7Uc9WCrgnTWbEvDgjGfRAmcM9moWGoWX6E46Xkojpkfle
|
||||||
|
Ss6CHAMK42aZ/+MWQlZEzNK49PtomGMjn5SuoK8u
|
||||||
|
-----END CERTIFICATE-----"""
|
||||||
|
|
||||||
|
formal_certificate=b"""-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDezCCAmOgAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UEBhMCQ0Ex
|
||||||
|
EDAOBgNVBAgMB09udGFyaW8xITAfBgNVBAoMGFdpbmQgUml2ZXIgU3lzdGVtcywg
|
||||||
|
SW5jLjAeFw0xNzA4MTgxNDM1MTJaFw0yNzA4MTYxNDM1MTJaMEIxCzAJBgNVBAYT
|
||||||
|
AkNBMRAwDgYDVQQIDAdPbnRhcmlvMSEwHwYDVQQKDBhXaW5kIFJpdmVyIFN5c3Rl
|
||||||
|
bXMsIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+0fS8ybg8
|
||||||
|
M37lW+lcR9LmQAR2zUJdbnl2L0fj3W/7W+PMm3mJWeQDTf19wf+qHHrgEkjxGp10
|
||||||
|
BSXWZYdPyCdOjAay/Ew1s/waFeAQZpf4vv/9D1Y/4sVkqct9ibo5NVgvVsjqKVnX
|
||||||
|
IVhyzHlhBSUqYhZlS/SOx8JcLQWSUMJoP2XR4Tv28xIXi0Fuyp8QBwUmSwmvfPy4
|
||||||
|
0yxzfON/b8kHld5aTY353KLXh/5YWsn1zRlOYfS1OuJk4LGjm6HvmZtxPNUZk4vI
|
||||||
|
NA24rH4FKkuxyM3x8aPi3LE4G6GSrJDuNi28xzOj864rlFoyLODy/mov1YMR/g4k
|
||||||
|
d3mG6UbRckPxAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9w
|
||||||
|
ZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTjyMN/AX07rEmB
|
||||||
|
6sz6pnyt/m+eSzAfBgNVHSMEGDAWgBSWiztcfPo7Yu1eqSxm1MqqctDN+jANBgkq
|
||||||
|
hkiG9w0BAQsFAAOCAQEASpyCu/adGTvNjyy/tV+sL/kaVEKLA7q36HUrzQkTjMPX
|
||||||
|
y8L8PVZoeWprkz7cvYTyHmVTPLBvFkGEFVn8LWi9fTTp/UrHnxw6fvb+V78mOypi
|
||||||
|
4A1aU9+dh3L6arpd4jZ4hDiLhEClesGCYVTVBdsrh3zSOc51nT4hosyBVpRd/VgQ
|
||||||
|
jhGJBBMEXASZceady4ajK5jnR3wF8oW/he4NYF97qh8WWKVsIYbwgLS0rT58q7qq
|
||||||
|
vpjPxMOahUdACkyPyt/XJICTlkanVD7KgG3oLWpc+3FWPHGr+F7mspPLZqUcEFDV
|
||||||
|
bGF+oDJ7p/tqHsNvPlRDVGqh0QdiAkKeS/SJC9jmAw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
"""
|
|
@ -0,0 +1,126 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import ConfigParser
|
||||||
|
import StringIO
|
||||||
|
import subprocess
|
||||||
|
import logging
|
||||||
|
import socket
|
||||||
|
import cgcs_patch.utils as utils
|
||||||
|
import cgcs_patch.constants as constants
|
||||||
|
import tsconfig.tsconfig as tsc
|
||||||
|
|
||||||
|
controller_mcast_group = None
|
||||||
|
agent_mcast_group = None
|
||||||
|
controller_port = 0
|
||||||
|
agent_port = 0
|
||||||
|
api_port = 0
|
||||||
|
mgmt_if = None
|
||||||
|
nodetype = None
|
||||||
|
platform_conf_mtime = 0
|
||||||
|
patching_conf_mtime = 0
|
||||||
|
patching_conf = '/etc/patching/patching.conf'
|
||||||
|
|
||||||
|
def read_config():
|
||||||
|
global patching_conf_mtime
|
||||||
|
global patching_conf
|
||||||
|
|
||||||
|
if patching_conf_mtime == os.stat(patching_conf).st_mtime:
|
||||||
|
# The file has not changed since it was last read
|
||||||
|
return
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
'controller_mcast_group': "239.1.1.3",
|
||||||
|
'agent_mcast_group': "239.1.1.4",
|
||||||
|
'api_port': "5487",
|
||||||
|
'controller_port': "5488",
|
||||||
|
'agent_port': "5489",
|
||||||
|
}
|
||||||
|
|
||||||
|
global controller_mcast_group
|
||||||
|
global agent_mcast_group
|
||||||
|
global api_port
|
||||||
|
global controller_port
|
||||||
|
global agent_port
|
||||||
|
|
||||||
|
config = ConfigParser.SafeConfigParser(defaults)
|
||||||
|
config.read(patching_conf)
|
||||||
|
patching_conf_mtime = os.stat(patching_conf).st_mtime
|
||||||
|
|
||||||
|
controller_mcast_group = config.get('runtime',
|
||||||
|
'controller_multicast')
|
||||||
|
agent_mcast_group = config.get('runtime', 'agent_multicast')
|
||||||
|
|
||||||
|
api_port = config.getint('runtime', 'api_port')
|
||||||
|
controller_port = config.getint('runtime', 'controller_port')
|
||||||
|
agent_port = config.getint('runtime', 'agent_port')
|
||||||
|
|
||||||
|
# The platform.conf file has no section headers, which causes problems
|
||||||
|
# for ConfigParser. So we'll fake it out.
|
||||||
|
ini_str = '[platform_conf]\n' + open(tsc.PLATFORM_CONF_FILE, 'r').read()
|
||||||
|
ini_fp = StringIO.StringIO(ini_str)
|
||||||
|
config.readfp(ini_fp)
|
||||||
|
|
||||||
|
try:
|
||||||
|
value = config.get('platform_conf', 'nodetype')
|
||||||
|
|
||||||
|
global nodetype
|
||||||
|
nodetype = value
|
||||||
|
except ConfigParser.Error:
|
||||||
|
logging.exception("Failed to read nodetype from config")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_mgmt_ip():
|
||||||
|
# Check if initial config is complete
|
||||||
|
if not os.path.exists('/etc/platform/.initial_config_complete'):
|
||||||
|
return None
|
||||||
|
mgmt_hostname = socket.gethostname()
|
||||||
|
return utils.gethostbyname(mgmt_hostname)
|
||||||
|
|
||||||
|
|
||||||
|
# Because the patching daemons are launched before manifests are
|
||||||
|
# applied, the content of some settings in platform.conf can change,
|
||||||
|
# such as the management interface. As such, we can't just directly
|
||||||
|
# use tsc.management_interface
|
||||||
|
#
|
||||||
|
def get_mgmt_iface():
|
||||||
|
# Check if initial config is complete
|
||||||
|
if not os.path.exists(constants.INITIAL_CONFIG_COMPLETE_FLAG):
|
||||||
|
return None
|
||||||
|
|
||||||
|
global mgmt_if
|
||||||
|
global platform_conf_mtime
|
||||||
|
|
||||||
|
if mgmt_if is not None and \
|
||||||
|
platform_conf_mtime == os.stat(tsc.PLATFORM_CONF_FILE).st_mtime:
|
||||||
|
# The platform.conf file hasn't been modified since we read it,
|
||||||
|
# so return the cached value.
|
||||||
|
return mgmt_if
|
||||||
|
|
||||||
|
config = ConfigParser.SafeConfigParser()
|
||||||
|
|
||||||
|
# The platform.conf file has no section headers, which causes problems
|
||||||
|
# for ConfigParser. So we'll fake it out.
|
||||||
|
ini_str = '[platform_conf]\n' + open(tsc.PLATFORM_CONF_FILE, 'r').read()
|
||||||
|
ini_fp = StringIO.StringIO(ini_str)
|
||||||
|
config.readfp(ini_fp)
|
||||||
|
|
||||||
|
try:
|
||||||
|
value = config.get('platform_conf', 'management_interface')
|
||||||
|
|
||||||
|
global nodetype
|
||||||
|
mgmt_if = value
|
||||||
|
|
||||||
|
platform_conf_mtime = os.stat(tsc.PLATFORM_CONF_FILE).st_mtime
|
||||||
|
except ConfigParser.Error:
|
||||||
|
logging.exception("Failed to read management_interface from config")
|
||||||
|
return None
|
||||||
|
return mgmt_if
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2015-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
try:
|
||||||
|
# The tsconfig module is only available at runtime
|
||||||
|
import tsconfig.tsconfig as tsc
|
||||||
|
|
||||||
|
INITIAL_CONFIG_COMPLETE_FLAG = os.path.join(
|
||||||
|
tsc.PLATFORM_CONF_PATH, ".initial_config_complete")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
PATCH_AGENT_STATE_IDLE = "idle"
|
||||||
|
PATCH_AGENT_STATE_INSTALLING = "installing"
|
||||||
|
PATCH_AGENT_STATE_INSTALL_FAILED = "install-failed"
|
||||||
|
PATCH_AGENT_STATE_INSTALL_REJECTED = "install-rejected"
|
||||||
|
|
||||||
|
ADDRESS_VERSION_IPV4 = 4
|
||||||
|
ADDRESS_VERSION_IPV6 = 6
|
||||||
|
CONTROLLER_FLOATING_HOSTNAME = "controller"
|
||||||
|
|
||||||
|
AVAILABLE = 'Available'
|
||||||
|
APPLIED = 'Applied'
|
||||||
|
PARTIAL_APPLY = 'Partial-Apply'
|
||||||
|
PARTIAL_REMOVE = 'Partial-Remove'
|
||||||
|
COMMITTED = 'Committed'
|
||||||
|
UNKNOWN = 'n/a'
|
||||||
|
|
||||||
|
STATUS_OBSOLETE = 'OBS'
|
||||||
|
STATUS_RELEASED = 'REL'
|
||||||
|
STATUS_DEVELOPEMENT = 'DEV'
|
||||||
|
|
||||||
|
CLI_OPT_ALL = '--all'
|
||||||
|
CLI_OPT_DRY_RUN = '--dry-run'
|
||||||
|
CLI_OPT_RECURSIVE = '--recursive'
|
||||||
|
CLI_OPT_RELEASE = '--release'
|
||||||
|
|
||||||
|
ENABLE_DEV_CERTIFICATE_PATCH_IDENTIFIER = 'ENABLE_DEV_CERTIFICATE'
|
|
@ -0,0 +1,45 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
class PatchError(Exception):
|
||||||
|
"""Base class for patching exceptions."""
|
||||||
|
|
||||||
|
def __init__(self, message=None):
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.message or ""
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataFail(PatchError):
|
||||||
|
"""Metadata error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class RpmFail(PatchError):
|
||||||
|
"""RPM error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class RepoFail(PatchError):
|
||||||
|
"""Repo error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PatchFail(PatchError):
|
||||||
|
"""General patching error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PatchValidationFailure(PatchError):
|
||||||
|
"""Patch validation error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PatchMismatchFailure(PatchError):
|
||||||
|
"""Patch validation error."""
|
||||||
|
pass
|
|
@ -0,0 +1,64 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from cgcs_patch.patch_functions import LOG
|
||||||
|
|
||||||
|
PATCHMSG_UNKNOWN = 0
|
||||||
|
PATCHMSG_HELLO = 1
|
||||||
|
PATCHMSG_HELLO_ACK = 2
|
||||||
|
PATCHMSG_SYNC_REQ = 3
|
||||||
|
PATCHMSG_SYNC_COMPLETE = 4
|
||||||
|
PATCHMSG_HELLO_AGENT = 5
|
||||||
|
PATCHMSG_HELLO_AGENT_ACK = 6
|
||||||
|
PATCHMSG_QUERY_DETAILED = 7
|
||||||
|
PATCHMSG_QUERY_DETAILED_RESP = 8
|
||||||
|
PATCHMSG_AGENT_INSTALL_REQ = 9
|
||||||
|
PATCHMSG_AGENT_INSTALL_RESP = 10
|
||||||
|
PATCHMSG_DROP_HOST_REQ = 11
|
||||||
|
|
||||||
|
PATCHMSG_STR = {
|
||||||
|
PATCHMSG_UNKNOWN: "unknown",
|
||||||
|
PATCHMSG_HELLO: "hello",
|
||||||
|
PATCHMSG_HELLO_ACK: "hello-ack",
|
||||||
|
PATCHMSG_SYNC_REQ: "sync-req",
|
||||||
|
PATCHMSG_SYNC_COMPLETE: "sync-complete",
|
||||||
|
PATCHMSG_HELLO_AGENT: "hello-agent",
|
||||||
|
PATCHMSG_HELLO_AGENT_ACK: "hello-agent-ack",
|
||||||
|
PATCHMSG_QUERY_DETAILED: "query-detailed",
|
||||||
|
PATCHMSG_QUERY_DETAILED_RESP: "query-detailed-resp",
|
||||||
|
PATCHMSG_AGENT_INSTALL_REQ: "agent-install-req",
|
||||||
|
PATCHMSG_AGENT_INSTALL_RESP: "agent-install-resp",
|
||||||
|
PATCHMSG_DROP_HOST_REQ: "drop-host-req",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PatchMessage(object):
|
||||||
|
def __init__(self, msgtype=PATCHMSG_UNKNOWN):
|
||||||
|
self.msgtype = msgtype
|
||||||
|
self.msgversion = 1
|
||||||
|
self.message = {}
|
||||||
|
|
||||||
|
def decode(self, data):
|
||||||
|
if 'msgtype' in data:
|
||||||
|
self.msgtype = data['msgtype']
|
||||||
|
if 'msgversion' in data:
|
||||||
|
self.msgversion = data['msgversion']
|
||||||
|
|
||||||
|
def encode(self):
|
||||||
|
self.message['msgtype'] = self.msgtype
|
||||||
|
self.message['msgversion'] = self.msgversion
|
||||||
|
|
||||||
|
def data(self):
|
||||||
|
return {'msgtype': self.msgtype}
|
||||||
|
|
||||||
|
def msgtype_str(self):
|
||||||
|
if self.msgtype in PATCHMSG_STR:
|
||||||
|
return PATCHMSG_STR[self.msgtype]
|
||||||
|
return "invalid-type"
|
||||||
|
|
||||||
|
def handle(self, sock, addr):
|
||||||
|
LOG.info("Unhandled message type: %s" % self.msgtype)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,66 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from Crypto.Signature import PKCS1_PSS
|
||||||
|
from Crypto.Hash import SHA256
|
||||||
|
from Crypto.PublicKey import RSA
|
||||||
|
from Crypto.Util.asn1 import DerSequence
|
||||||
|
from binascii import a2b_base64
|
||||||
|
from cgcs_patch.patch_verify import read_RSA_key
|
||||||
|
|
||||||
|
# To save memory, read and hash 1M of files at a time
|
||||||
|
default_blocksize=1*1024*1024
|
||||||
|
|
||||||
|
# When we sign patches, look for private keys in the following paths
|
||||||
|
#
|
||||||
|
# The (currently hardcoded) path on the signing server will be replaced
|
||||||
|
# by the capability to specify filename from calling function.
|
||||||
|
private_key_files=['/signing/keys/formal-private-key.pem',
|
||||||
|
os.path.expandvars('$MY_REPO/build-tools/signing/dev-private-key.pem')
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def sign_files(filenames, signature_file, private_key=None):
|
||||||
|
"""
|
||||||
|
Utility function for signing data in files.
|
||||||
|
:param filenames: A list of files containing the data to be signed
|
||||||
|
:param signature_file: The name of the file to which the signature will be
|
||||||
|
stored
|
||||||
|
:param private_key: If specified, sign with this private key. Otherwise,
|
||||||
|
the files in private_key_files will be searched for
|
||||||
|
and used, if found.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Hash the data across all files
|
||||||
|
blocksize=default_blocksize
|
||||||
|
data_hash = SHA256.new()
|
||||||
|
for filename in filenames:
|
||||||
|
with open(filename, 'rb') as infile:
|
||||||
|
data=infile.read(blocksize)
|
||||||
|
while len(data) > 0:
|
||||||
|
data_hash.update(data)
|
||||||
|
data=infile.read(blocksize)
|
||||||
|
|
||||||
|
# Find a private key to use, if not already provided
|
||||||
|
if private_key is None:
|
||||||
|
for filename in private_key_files:
|
||||||
|
# print 'Checking to see if ' + filename + ' exists\n'
|
||||||
|
if os.path.exists(filename):
|
||||||
|
# print 'Getting private key from ' + filename + '\n'
|
||||||
|
private_key = read_RSA_key(open(filename, 'rb').read())
|
||||||
|
|
||||||
|
assert (private_key is not None),"Could not find private signing key"
|
||||||
|
|
||||||
|
# Encrypt the hash (sign the data) with the key we find
|
||||||
|
signer = PKCS1_PSS.new(private_key)
|
||||||
|
signature = signer.sign(data_hash)
|
||||||
|
|
||||||
|
# Save it
|
||||||
|
with open(signature_file, 'wb') as outfile:
|
||||||
|
outfile.write(signature)
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from Crypto.Signature import PKCS1_v1_5
|
||||||
|
from Crypto.Signature import PKCS1_PSS
|
||||||
|
from Crypto.Hash import SHA256
|
||||||
|
from Crypto.PublicKey import RSA
|
||||||
|
from Crypto.Util.asn1 import DerSequence
|
||||||
|
from binascii import a2b_base64
|
||||||
|
|
||||||
|
from cgcs_patch.certificates import dev_certificate, formal_certificate
|
||||||
|
|
||||||
|
# To save memory, read and hash 1M of files at a time
|
||||||
|
default_blocksize=1*1024*1024
|
||||||
|
|
||||||
|
dev_certificate_marker='/etc/pki/wrs/dev_certificate_enable.bin'
|
||||||
|
LOG = logging.getLogger('main_logger')
|
||||||
|
|
||||||
|
|
||||||
|
def verify_hash(data_hash, signature_bytes, certificate_list):
|
||||||
|
"""
|
||||||
|
Checkes that a hash's signature can be validates against an approved
|
||||||
|
certificate
|
||||||
|
:param data_hash: A hash of the data to be validated
|
||||||
|
:param signature_bytes: A pre-generated signature (typically, the hash
|
||||||
|
encrypted with a private key)
|
||||||
|
:param certifcate_list: A list of approved certificates or public keys
|
||||||
|
which the signature is validated against
|
||||||
|
:return: True if the signature was validated against a certificate
|
||||||
|
"""
|
||||||
|
verified = False
|
||||||
|
for cert in certificate_list:
|
||||||
|
if verified:
|
||||||
|
break
|
||||||
|
pub_key = read_RSA_key(cert)
|
||||||
|
x = pub_key.exportKey()
|
||||||
|
|
||||||
|
# PSS is the recommended signature scheme, but some tools (like OpenSSL)
|
||||||
|
# use the older v1_5 scheme. We try to validate against both.
|
||||||
|
#
|
||||||
|
# We use PSS for patch validation, but use v1_5 for ISO validation
|
||||||
|
# since we want to generate detached sigs that a customer can validate
|
||||||
|
# OpenSSL
|
||||||
|
verifier = PKCS1_PSS.new(pub_key)
|
||||||
|
verified = verifier.verify(data_hash, signature_bytes)
|
||||||
|
if not verified:
|
||||||
|
verifier = PKCS1_v1_5.new(pub_key)
|
||||||
|
verified = verifier.verify(data_hash, signature_bytes)
|
||||||
|
return verified
|
||||||
|
|
||||||
|
|
||||||
|
def get_public_certificates():
|
||||||
|
"""
|
||||||
|
Builds a list of accepted certificates which can be used to validate
|
||||||
|
further things. This list may contain multiple certificates depending on
|
||||||
|
the configuration of the system (for instance, should we include the
|
||||||
|
developer certificate in the list).
|
||||||
|
:return: A list of certificates in PEM format
|
||||||
|
"""
|
||||||
|
cert_list = [formal_certificate]
|
||||||
|
|
||||||
|
# We enable the dev certificate based on the presence of a file. This file
|
||||||
|
# contains a hash of an arbitrary string ('Titanum patching') which has been
|
||||||
|
# encrypted with our formal private key. If the file is present (and valid)
|
||||||
|
# then we add the developer key to the approved certificates list
|
||||||
|
if os.path.exists(dev_certificate_marker):
|
||||||
|
with open(dev_certificate_marker) as infile:
|
||||||
|
signature = infile.read()
|
||||||
|
data_hash = SHA256.new()
|
||||||
|
data_hash.update('Titanium patching')
|
||||||
|
if verify_hash(data_hash, signature, cert_list):
|
||||||
|
cert_list.append(dev_certificate)
|
||||||
|
else:
|
||||||
|
msg = "Invalid data found in " + dev_certificate_marker
|
||||||
|
LOG.error(msg)
|
||||||
|
|
||||||
|
return cert_list
|
||||||
|
|
||||||
|
|
||||||
|
def read_RSA_key(key_data):
|
||||||
|
"""
|
||||||
|
Utility function for reading an RSA key half from encoded data
|
||||||
|
:param key_data: PEM data containing raw key or X.509 certificate
|
||||||
|
:return: An RSA key object
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Handle data that is just a raw key
|
||||||
|
key = RSA.importKey(key_data)
|
||||||
|
except ValueError:
|
||||||
|
# The RSA.importKey function cannot read X.509 certificates directly
|
||||||
|
# (depending on the version of the Crypto library). Instead, we
|
||||||
|
# may need to extract the key from the certificate before building
|
||||||
|
# the key object
|
||||||
|
#
|
||||||
|
# We need to strip the BEGIN and END lines from PEM first
|
||||||
|
x509lines = key_data.replace(' ','').split()
|
||||||
|
x509text = ''.join(x509lines[1:-1])
|
||||||
|
x509data = DerSequence()
|
||||||
|
x509data.decode(a2b_base64(x509text))
|
||||||
|
|
||||||
|
# X.509 contains a few parts. The first part (index 0) is the
|
||||||
|
# certificate itself, (TBS or "to be signed" cert) and the 7th field
|
||||||
|
# of that cert is subjectPublicKeyInfo, which can be imported.
|
||||||
|
# RFC3280
|
||||||
|
tbsCert = DerSequence()
|
||||||
|
tbsCert.decode(x509data[0])
|
||||||
|
|
||||||
|
# Initialize RSA key from the subjectPublicKeyInfo field
|
||||||
|
key = RSA.importKey(tbsCert[6])
|
||||||
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
def verify_files(filenames, signature_file):
|
||||||
|
"""
|
||||||
|
Verify data files against a detached signature.
|
||||||
|
:param filenames: A list of files containing the data which was signed
|
||||||
|
:param public_key_file: A file containing the public key or certificate
|
||||||
|
corresponding to the key which signed the data
|
||||||
|
:param signature_file: The name of the file containing the signature
|
||||||
|
:return: True if the signature was verified, False otherwise
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Hash the data across all files
|
||||||
|
blocksize=default_blocksize
|
||||||
|
data_hash = SHA256.new()
|
||||||
|
for filename in filenames:
|
||||||
|
with open(filename, 'rb') as infile:
|
||||||
|
data=infile.read(blocksize)
|
||||||
|
while len(data) > 0:
|
||||||
|
data_hash.update(data)
|
||||||
|
data=infile.read(blocksize)
|
||||||
|
|
||||||
|
# Get the signature
|
||||||
|
with open(signature_file, 'rb') as sig_file:
|
||||||
|
signature_bytes = sig_file.read()
|
||||||
|
|
||||||
|
# Verify the signature
|
||||||
|
certificate_list = get_public_certificates()
|
||||||
|
return verify_hash(data_hash, signature_bytes, certificate_list)
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
|
||||||
|
<br>
|
||||||
|
% if not pd is UNDEFINED and len(pd) > 0:
|
||||||
|
<table border="2" style="width:300px">
|
||||||
|
<tr>
|
||||||
|
<th>Patch ID</th>
|
||||||
|
<th>Patch Data</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
% for patch_id in sorted(pd.keys()):
|
||||||
|
${patchrow(patch_id)}
|
||||||
|
% endfor
|
||||||
|
</table>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
% if not info is UNDEFINED and len(info) > 0:
|
||||||
|
<p>${info}</p>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
% if not warning is UNDEFINED and len(warning) > 0:
|
||||||
|
<p>Warning:<br>${warning}</p>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
% if not error is UNDEFINED and len(error) > 0:
|
||||||
|
<p>Error:<br>${error}</p>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<a href="/patch/query">Show all</a><br>
|
||||||
|
<a href="/patch/query?show=applied">Show applied</a><br>
|
||||||
|
<a href="/patch/query?show=available">Show available</a><br>
|
||||||
|
<a href="/patch/query_hosts">Query Hosts</a><br>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<form action="/patch/upload" method="POST" enctype="multipart/form-data">
|
||||||
|
<input type="file" name="file"/>
|
||||||
|
<button type="submit">Upload Patch</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<%def name="patchrow(patch_id)">
|
||||||
|
<%
|
||||||
|
p = pd[patch_id]
|
||||||
|
%>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><a href="/patch/show/${patch_id}">${patch_id}</a></td>
|
||||||
|
<td valign="top">
|
||||||
|
<table border="1" width=100%>
|
||||||
|
% if p["repostate"] != "":
|
||||||
|
<tr><td valign="top">Repo State:</td><td valign="top">${p["repostate"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["patchstate"] != "":
|
||||||
|
<tr><td valign="top">Patch State:</td><td valign="top">${p["patchstate"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["status"] != "":
|
||||||
|
<tr><td valign="top">Status:</td><td valign="top">${p["status"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["unremovable" != ""]:
|
||||||
|
<tr><td valign="top">Unremovable:</td><td valign="top">${p["unremovable"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["reboot_required" != ""]:
|
||||||
|
<tr><td valign="top">Reboot-Required:</td><td valign="top">${p["reboot_required"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["summary"] != "":
|
||||||
|
<tr><td valign="top">Summary:</td><td valign="top">${p["summary"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["description"] != "":
|
||||||
|
<tr><td valign="top">Description:</td><td valign="top">${p["description"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["install_instructions"] != "":
|
||||||
|
<tr><td valign="top">Install Instructions:</td><td valign="top">${p["install_instructions"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["warnings"] != "":
|
||||||
|
<tr><td valign="top">Warnings:</td><td valign="top">${p["warnings"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["repostate"] == "Applied":
|
||||||
|
<tr>
|
||||||
|
<td valign="top">Actions:</td>
|
||||||
|
<td valign="top"><a href="/patch/remove/${patch_id}">Remove</a></td>
|
||||||
|
</tr>
|
||||||
|
% endif
|
||||||
|
% if p["repostate"] == "Available":
|
||||||
|
<tr>
|
||||||
|
<td valign="top">Actions:</td>
|
||||||
|
<td valign="top"><a href="/patch/apply/${patch_id}">Apply</a><br>
|
||||||
|
<a href="/patch/delete/${patch_id}">Delete</a></td>
|
||||||
|
</tr>
|
||||||
|
% endif
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</%def>
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
% if not pd is UNDEFINED:
|
||||||
|
<pd>
|
||||||
|
% if len(pd) > 0:
|
||||||
|
% for patch_id in sorted(pd.keys()):
|
||||||
|
${patchelem(patch_id)}
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
</pd>
|
||||||
|
% endif
|
||||||
|
% if not info is UNDEFINED or not warning is UNDEFINED or not error is UNDEFINED:
|
||||||
|
<info>
|
||||||
|
% if not info is UNDEFINED and len(info) > 0:
|
||||||
|
${info}
|
||||||
|
% endif
|
||||||
|
</info>
|
||||||
|
<warning>
|
||||||
|
% if not warning is UNDEFINED and len(warning) > 0:
|
||||||
|
${warning}
|
||||||
|
% endif
|
||||||
|
</warning>
|
||||||
|
<error>
|
||||||
|
% if not error is UNDEFINED and len(error) > 0:
|
||||||
|
${error}
|
||||||
|
% endif
|
||||||
|
</error>
|
||||||
|
% endif
|
||||||
|
<%def name="patchelem(patch_id)">\
|
||||||
|
<%p = pd[patch_id] %>\
|
||||||
|
<patch>
|
||||||
|
<patch_id>
|
||||||
|
${patch_id}
|
||||||
|
</patch_id>
|
||||||
|
<status>
|
||||||
|
% if p["status"] != "":
|
||||||
|
${p["status"]}
|
||||||
|
% endif
|
||||||
|
</status>
|
||||||
|
<sw_version>
|
||||||
|
% if p["sw_version"] != "":
|
||||||
|
${p["sw_version"]}
|
||||||
|
% endif
|
||||||
|
</sw_version>
|
||||||
|
<repostate>
|
||||||
|
% if p["repostate"] != "":
|
||||||
|
${p["repostate"]}
|
||||||
|
% endif
|
||||||
|
</repostate>
|
||||||
|
<patchstate>
|
||||||
|
% if p["patchstate"] != "":
|
||||||
|
${p["patchstate"]}
|
||||||
|
% endif
|
||||||
|
</patchstate>
|
||||||
|
<status>
|
||||||
|
% if p["status"] != "":
|
||||||
|
${p["status"]}
|
||||||
|
% endif
|
||||||
|
</status>
|
||||||
|
<unremovable>
|
||||||
|
% if p["unremovable"] != "":
|
||||||
|
${p["unremovable"]}
|
||||||
|
% endif
|
||||||
|
</unremovable>
|
||||||
|
<reboot_required>
|
||||||
|
% if p["reboot_required"] != "":
|
||||||
|
${p["reboot_required"]}
|
||||||
|
% endif
|
||||||
|
</reboot_required>
|
||||||
|
<summary>
|
||||||
|
% if p["summary"] != "":
|
||||||
|
${p["summary"]}
|
||||||
|
% endif
|
||||||
|
</summary>
|
||||||
|
<description>
|
||||||
|
% if p["description"] != "":
|
||||||
|
${p["description"]}
|
||||||
|
% endif
|
||||||
|
</description>
|
||||||
|
<install_instructions>
|
||||||
|
% if p["install_instructions"] != "":
|
||||||
|
${p["install_instructions"]}
|
||||||
|
% endif
|
||||||
|
</install_instructions>
|
||||||
|
<warnings>
|
||||||
|
% if p["warnings"] != "":
|
||||||
|
${p["warnings"]}
|
||||||
|
% endif
|
||||||
|
</warnings>
|
||||||
|
<requires>
|
||||||
|
% if "requires" in p and len(p["requires"]) > 0:
|
||||||
|
% for req in sorted(p["requires"]):
|
||||||
|
<patch>${req}</patch>
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
</requires>
|
||||||
|
</patch></%def>
|
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<table border="2" style="width:300px">
|
||||||
|
<tr>
|
||||||
|
<th>Hostname</th>
|
||||||
|
<th>IP</th>
|
||||||
|
<th>Patch Patch?</th>
|
||||||
|
<th>Requires Reboot</th>
|
||||||
|
<th>Time since last ack</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
% for agent in data:
|
||||||
|
${agentrow(agent)}
|
||||||
|
% endfor
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<a href="/patch/query">Show all</a><br>
|
||||||
|
<a href="/patch/query?show=applied">Show applied</a><br>
|
||||||
|
<a href="/patch/query?show=available">Show available</a><br>
|
||||||
|
|
||||||
|
|
||||||
|
<%def name="agentrow(agent)">
|
||||||
|
<tr>
|
||||||
|
<td>${agent["ip"]}</td>
|
||||||
|
<td>${agent["hostname"]}</td>
|
||||||
|
<td>${agent["patch_current"]}</td>
|
||||||
|
<td>${agent["requires_reboot"]}</td>
|
||||||
|
<td>${agent["secs_since_ack"]}</td>
|
||||||
|
</tr>
|
||||||
|
</%def>
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
% if not data is UNDEFINED and len(data) > 0:
|
||||||
|
<data>
|
||||||
|
% for host in data:
|
||||||
|
${hostelem(host)}
|
||||||
|
% endfor
|
||||||
|
</data>
|
||||||
|
% endif
|
||||||
|
<%def name="hostelem(host)">\
|
||||||
|
<%h = host %>\
|
||||||
|
<host>
|
||||||
|
<hostname>
|
||||||
|
% if h["hostname"] != "":
|
||||||
|
${h["hostname"]}
|
||||||
|
% endif
|
||||||
|
</hostname>
|
||||||
|
<requires_reboot>
|
||||||
|
% if h["requires_reboot"] != "":
|
||||||
|
${h["requires_reboot"]}
|
||||||
|
% endif
|
||||||
|
</requires_reboot>
|
||||||
|
<nodetype>
|
||||||
|
% if h["nodetype"] != "":
|
||||||
|
${h["nodetype"]}
|
||||||
|
% endif
|
||||||
|
</nodetype>
|
||||||
|
<ip>
|
||||||
|
% if h["ip"] != "":
|
||||||
|
${h["ip"]}
|
||||||
|
% endif
|
||||||
|
</ip>
|
||||||
|
<missing_pkgs>
|
||||||
|
% if "missing_pkgs" in h and len(h["missing_pkgs"]) > 0:
|
||||||
|
% for pkg in sorted(h["missing_pkgs"]):
|
||||||
|
<pkg>${pkg}</pkg>
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
</missing_pkgs>
|
||||||
|
<installed>
|
||||||
|
% if "installed" in h and len(h["installed"]) > 0:
|
||||||
|
% for pkg in sorted(h["installed"]):
|
||||||
|
<pkg>
|
||||||
|
<name>${pkg}</name>
|
||||||
|
<pkgname>${h["installed"][pkg]}</pkgname>
|
||||||
|
</pkg>
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
</installed>
|
||||||
|
<to_remove>
|
||||||
|
% if "to_remove" in h and len(h["to_remove"]) > 0:
|
||||||
|
% for pkg in sorted(h["to_remove"]):
|
||||||
|
<pkg>${pkg}</pkg>
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
</to_remove>
|
||||||
|
<secs_since_ack>
|
||||||
|
% if h["secs_since_ack"] != "":
|
||||||
|
${h["secs_since_ack"]}
|
||||||
|
% endif
|
||||||
|
</secs_since_ack>
|
||||||
|
<patch_failed>
|
||||||
|
% if h["patch_failed"] != "":
|
||||||
|
${h["patch_failed"]}
|
||||||
|
% endif
|
||||||
|
</patch_failed>
|
||||||
|
<stale_details>
|
||||||
|
% if h["stale_details"] != "":
|
||||||
|
${h["stale_details"]}
|
||||||
|
% endif
|
||||||
|
</stale_details>
|
||||||
|
<patch_current>
|
||||||
|
% if h["patch_current"] != "":
|
||||||
|
${h["patch_current"]}
|
||||||
|
% endif
|
||||||
|
</patch_current>
|
||||||
|
</host></%def>
|
|
@ -0,0 +1,83 @@
|
||||||
|
|
||||||
|
<br>
|
||||||
|
% if not metadata is UNDEFINED and len(metadata) > 0:
|
||||||
|
% for patch_id in sorted(metadata.keys()):
|
||||||
|
${showpatch(patch_id)}
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
|
||||||
|
% if not info is UNDEFINED and len(info) > 0:
|
||||||
|
<p>${info}</p>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
% if not warning is UNDEFINED and len(warning) > 0:
|
||||||
|
<p>Warning:<br>${warning}</p>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
% if not error is UNDEFINED and len(error) > 0:
|
||||||
|
<p>Error:<br>${error}</p>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<a href="/patch/query">Show all</a><br>
|
||||||
|
<a href="/patch/query?show=applied">Show applied</a><br>
|
||||||
|
<a href="/patch/query?show=available">Show available</a><br>
|
||||||
|
<a href="/patch/query_hosts">Query Hosts</a><br>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<form action="/patch/upload" method="POST" enctype="multipart/form-data">
|
||||||
|
<input type="file" name="file"/>
|
||||||
|
<button type="submit">Upload Patch</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<%def name="showpatch(patch_id)">
|
||||||
|
<%
|
||||||
|
p = metadata[patch_id]
|
||||||
|
%>
|
||||||
|
<h2>${patch_id}</h2>
|
||||||
|
<table border="2">
|
||||||
|
% if p["repostate"] != "":
|
||||||
|
<tr><td valign="top">Repo State:</td><td valign="top">${p["repostate"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["patchstate"] != "":
|
||||||
|
<tr><td valign="top">Patch State:</td><td valign="top">${p["patchstate"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["status"] != "":
|
||||||
|
<tr><td valign="top">Status:</td><td valign="top">${p["status"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["unremovable"] != "":
|
||||||
|
<tr><td valign="top">Unremovable:</td><td valign="top">${p["unremovable"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["reboot_required"] != "":
|
||||||
|
<tr><td valign="top">Reboot-Required:</td><td valign="top">${p["reboot_required"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["summary"] != "":
|
||||||
|
<tr><td valign="top">Summary:</td><td valign="top">${p["summary"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["description"] != "":
|
||||||
|
<tr><td valign="top">Description:</td><td valign="top">${p["description"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["install_instructions"] != "":
|
||||||
|
<tr><td valign="top">Install Instructions:</td><td valign="top">${p["install_instructions"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if p["warnings"] != "":
|
||||||
|
<tr><td valign="top">Warnings:</td><td valign="top">${p["warnings"]}</td></tr>
|
||||||
|
% endif
|
||||||
|
% if "requires" in p and len(p["requires"]) > 0:
|
||||||
|
<tr><td valign="top">Requires:</td><td valign="top">
|
||||||
|
% for req in sorted(p["requires"]):
|
||||||
|
${req}<br>
|
||||||
|
% endfor
|
||||||
|
</td></tr>
|
||||||
|
% endif
|
||||||
|
% if not contents is UNDEFINED and patch_id in contents:
|
||||||
|
<tr><td valign="top">Contents:</td><td valign="top">
|
||||||
|
% for pkg in sorted(contents[patch_id]):
|
||||||
|
${pkg}<br>
|
||||||
|
% endfor
|
||||||
|
</td></tr>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</%def>
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
<contents>
|
||||||
|
% if not contents is UNDEFINED and len(contents) > 0:
|
||||||
|
% for patch_id in sorted(contents.keys()):
|
||||||
|
<patch id=${patch_id}>
|
||||||
|
% for pkg in sorted(contents[patch_id]):
|
||||||
|
<pkg>${pkg}</pkg>
|
||||||
|
% endfor
|
||||||
|
</patch>
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
</contents>
|
||||||
|
<error>
|
||||||
|
% if not error is UNDEFINED and len(error) > 0:
|
||||||
|
${error}
|
||||||
|
% endif
|
||||||
|
</error>
|
||||||
|
<metadata>
|
||||||
|
% if not metadata is UNDEFINED and len(metadata) > 0:
|
||||||
|
% for patch_id in sorted(metadata.keys()):
|
||||||
|
${showpatch(patch_id)}
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
</metadata>
|
||||||
|
<%def name="showpatch(patch_id)">\
|
||||||
|
<% p = metadata[patch_id] %>\
|
||||||
|
<patch>
|
||||||
|
<patch_id>
|
||||||
|
${patch_id}
|
||||||
|
</patch_id>
|
||||||
|
<status>
|
||||||
|
% if p["status"] != "":
|
||||||
|
${p["status"]}
|
||||||
|
% endif
|
||||||
|
</status>
|
||||||
|
<unremovable>
|
||||||
|
% if p["unremovable"] != "":
|
||||||
|
${p["unremovable"]}
|
||||||
|
% endif
|
||||||
|
</unremovable>
|
||||||
|
<reboot_required>
|
||||||
|
% if p["reboot_required"] != "":
|
||||||
|
${p["reboot_required"]}
|
||||||
|
% endif
|
||||||
|
</reboot_required>
|
||||||
|
<sw_version>
|
||||||
|
% if p["sw_version"] != "":
|
||||||
|
${p["sw_version"]}
|
||||||
|
% endif
|
||||||
|
</sw_version>
|
||||||
|
<repostate>
|
||||||
|
% if p["repostate"] != "":
|
||||||
|
${p["repostate"]}
|
||||||
|
% endif
|
||||||
|
</repostate>
|
||||||
|
<patchstate>
|
||||||
|
% if p["patchstate"] != "":
|
||||||
|
${p["patchstate"]}
|
||||||
|
% endif
|
||||||
|
</patchstate>
|
||||||
|
<status>
|
||||||
|
% if p["status"] != "":
|
||||||
|
${p["status"]}
|
||||||
|
% endif
|
||||||
|
</status>
|
||||||
|
<summary>
|
||||||
|
% if p["summary"] != "":
|
||||||
|
${p["summary"]}
|
||||||
|
% endif
|
||||||
|
</summary>
|
||||||
|
<description>
|
||||||
|
% if p["description"] != "":
|
||||||
|
${p["description"]}
|
||||||
|
% endif
|
||||||
|
</description>
|
||||||
|
<install_instructions>
|
||||||
|
% if p["install_instructions"] != "":
|
||||||
|
${p["install_instructions"]}
|
||||||
|
% endif
|
||||||
|
</install_instructions>
|
||||||
|
<warnings>
|
||||||
|
% if p["warnings"] != "":
|
||||||
|
${p["warnings"]}
|
||||||
|
% endif
|
||||||
|
</warnings>
|
||||||
|
<requires>
|
||||||
|
% if "requires" in p and len(p["requires"]) > 0:
|
||||||
|
% for req in sorted(p["requires"]):
|
||||||
|
<patch>${req}</patch>
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
</requires>
|
||||||
|
</patch></%def>
|
|
@ -0,0 +1,74 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2016-2017 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from netaddr import IPAddress
|
||||||
|
import cgcs_patch.constants as constants
|
||||||
|
import socket
|
||||||
|
|
||||||
|
import ctypes
|
||||||
|
import ctypes.util
|
||||||
|
|
||||||
|
libc = ctypes.CDLL(ctypes.util.find_library('c'))
|
||||||
|
|
||||||
|
|
||||||
|
def if_nametoindex(name):
|
||||||
|
return libc.if_nametoindex(name)
|
||||||
|
|
||||||
|
|
||||||
|
def gethostbyname(hostname):
|
||||||
|
""" gethostbyname with IPv6 support """
|
||||||
|
try:
|
||||||
|
return socket.getaddrinfo(hostname, None)[0][4][0]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_management_version():
|
||||||
|
""" Determine whether management is IPv4 or IPv6 """
|
||||||
|
controller_ip_string = gethostbyname(constants.CONTROLLER_FLOATING_HOSTNAME)
|
||||||
|
if controller_ip_string:
|
||||||
|
controller_ip_address = IPAddress(controller_ip_string)
|
||||||
|
return controller_ip_address.version
|
||||||
|
else:
|
||||||
|
return constants.ADDRESS_VERSION_IPV4
|
||||||
|
|
||||||
|
|
||||||
|
def get_management_family():
|
||||||
|
ip_version = get_management_version()
|
||||||
|
if ip_version == constants.ADDRESS_VERSION_IPV6:
|
||||||
|
return socket.AF_INET6
|
||||||
|
else:
|
||||||
|
return socket.AF_INET
|
||||||
|
|
||||||
|
|
||||||
|
def get_versioned_address_all():
|
||||||
|
ip_version = get_management_version()
|
||||||
|
if ip_version == constants.ADDRESS_VERSION_IPV6:
|
||||||
|
return "::"
|
||||||
|
else:
|
||||||
|
return "0.0.0.0"
|
||||||
|
|
||||||
|
|
||||||
|
def ip_to_url(ip_address_string):
|
||||||
|
""" Add brackets if an IPv6 address """
|
||||||
|
try:
|
||||||
|
ip_address = IPAddress(ip_address_string)
|
||||||
|
if ip_address.version == constants.ADDRESS_VERSION_IPV6:
|
||||||
|
return "[%s]" % ip_address_string
|
||||||
|
else:
|
||||||
|
return ip_address_string
|
||||||
|
except:
|
||||||
|
return ip_address_string
|
||||||
|
|
||||||
|
|
||||||
|
def ip_to_versioned_localhost(ip_address_string):
|
||||||
|
""" Add brackets if an IPv6 address """
|
||||||
|
ip_address = IPAddress(ip_address_string)
|
||||||
|
if ip_address.version == constants.ADDRESS_VERSION_IPV6:
|
||||||
|
return "::1"
|
||||||
|
else:
|
||||||
|
return "localhost"
|
|
@ -0,0 +1,34 @@
|
||||||
|
Intended to run on a single build server. Currently yow-cgts2-lx
|
||||||
|
|
||||||
|
# On other build servers
|
||||||
|
mkdir -p /localdisk/designer/jenkins/bin
|
||||||
|
cp patch_id_allocator_client.py /localdisk/designer/jenkins/bin
|
||||||
|
|
||||||
|
|
||||||
|
# On the intended server: e.g. yow-cgts2-lx
|
||||||
|
mkdir -p /localdisk/designer/jenkins/bin
|
||||||
|
cp *py /localdisk/designer/jenkins/bin/
|
||||||
|
mkdir -p /localdisk/designer/jenkins/patch_ids
|
||||||
|
sudo cp patch_id_allocator_server.conf /etc/init
|
||||||
|
sudo initctl reload-configuration
|
||||||
|
sudo start script
|
||||||
|
|
||||||
|
# Change to a different server
|
||||||
|
edit patch_id_allocator_client.py
|
||||||
|
change the line ...
|
||||||
|
server = 'yow-cgts2-lx.wrs.com'
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
Need to back up the /localdisk/designer/jenkins/patch_ids directory
|
||||||
|
|
||||||
|
# Quick test
|
||||||
|
Point your browser at this url:
|
||||||
|
http://yow-cgts2-lx:8888/get_patch_id
|
||||||
|
|
||||||
|
expected result is:
|
||||||
|
CGCS_None_PATCH_0000
|
||||||
|
|
||||||
|
on each reload of the page, the number increments:
|
||||||
|
CGCS_None_PATCH_0001
|
||||||
|
CGCS_None_PATCH_0002
|
||||||
|
....
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-2014 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
import posixfile
|
||||||
|
import string
|
||||||
|
import time
|
||||||
|
|
||||||
|
directory="/localdisk/designer/jenkins/patch_ids"
|
||||||
|
|
||||||
|
def get_unique_id(filename, digits=4):
|
||||||
|
counter = 1
|
||||||
|
path = "%s/%s" % (directory, filename)
|
||||||
|
try:
|
||||||
|
# open for update
|
||||||
|
file = posixfile.open(path, "r+")
|
||||||
|
file.lock("w|", digits)
|
||||||
|
counter = int(file.read(digits)) + 1
|
||||||
|
except IOError:
|
||||||
|
# create it
|
||||||
|
try:
|
||||||
|
file = posixfile.open(path, "w")
|
||||||
|
file.lock("w|", digits)
|
||||||
|
except IOError:
|
||||||
|
print "creation of file '%s' failed" % path
|
||||||
|
return -1
|
||||||
|
|
||||||
|
file.seek(0) # rewind
|
||||||
|
format = "%%0%dd" % digits
|
||||||
|
file.write(format % counter)
|
||||||
|
|
||||||
|
# Note: close releases lock
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
return counter
|
||||||
|
|
||||||
|
def get_patch_id(version, prefix="CGCS", digits=4):
|
||||||
|
filename = "%s_%s_patchid" % (prefix, version)
|
||||||
|
id = get_unique_id(filename)
|
||||||
|
if id < 0:
|
||||||
|
return None
|
||||||
|
patch_id_format = "%%s_%%s_PATCH_%%0%dd" % digits
|
||||||
|
patch_id = patch_id_format % (prefix, version, id)
|
||||||
|
return patch_id
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-2014 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
import urllib
|
||||||
|
import urllib2
|
||||||
|
import getopt
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
opts = ['sw_version=', 'prefix=' ]
|
||||||
|
|
||||||
|
server = 'yow-cgts2-lx.wrs.com'
|
||||||
|
port = 8888
|
||||||
|
|
||||||
|
def request_patch_id(sw_version="1.01", prefix="CGCS"):
|
||||||
|
raw_parms = {}
|
||||||
|
raw_parms['sw_version'] = sw_version
|
||||||
|
raw_parms['prefix'] = prefix
|
||||||
|
print "raw_parms = %s" % str(raw_parms)
|
||||||
|
|
||||||
|
url = "http://%s:%d/get_patch_id" % (server, port)
|
||||||
|
params = urllib.urlencode(raw_parms)
|
||||||
|
response = urllib2.urlopen(url, params).read()
|
||||||
|
return response
|
||||||
|
|
||||||
|
def main():
|
||||||
|
optlist, remainder = getopt.getopt(sys.argv[1:], '', opts)
|
||||||
|
|
||||||
|
sw_version = None
|
||||||
|
prefix = None
|
||||||
|
raw_parms = {}
|
||||||
|
|
||||||
|
print "optlist = %s" % str(optlist)
|
||||||
|
print "remainder = %s" % str(remainder)
|
||||||
|
for key, val in optlist:
|
||||||
|
print "key = %s, val = %s" % (key, val)
|
||||||
|
if key == '--sw_version':
|
||||||
|
sw_version = val
|
||||||
|
print "sw_version = %s" % sw_version
|
||||||
|
raw_parms['sw_version'] = sw_version
|
||||||
|
|
||||||
|
if key == '--prefix':
|
||||||
|
prefix = val
|
||||||
|
print "prefix = %s" % prefix
|
||||||
|
raw_parms['prefix'] = prefix
|
||||||
|
|
||||||
|
# response = request_patch_id(sw_version=sw_version, prefix=prefix)
|
||||||
|
response = request_patch_id(**raw_parms)
|
||||||
|
print "response = %s" % str(response)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -0,0 +1,16 @@
|
||||||
|
# upstart script for patch_id_allocator_server
|
||||||
|
#
|
||||||
|
# Intallation
|
||||||
|
# sudo cp patch_id_allocator_server.conf /etc/init
|
||||||
|
# sudo initctl reload-configuration
|
||||||
|
# sudo start script
|
||||||
|
|
||||||
|
description "patch_id service"
|
||||||
|
author "Scott Little <scott.little@windriver.com>"
|
||||||
|
|
||||||
|
start on runlevel [234]
|
||||||
|
stop on runlevel [0156]
|
||||||
|
|
||||||
|
chdir /tmp
|
||||||
|
exec /localdisk/designer/jenkins/bin/patch_id_allocator_server.py
|
||||||
|
respawn
|
|
@ -0,0 +1,43 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-2014 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import web
|
||||||
|
import patch_id_allocator as pida
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
port = 8888
|
||||||
|
|
||||||
|
urls = (
|
||||||
|
'/get_patch_id', 'get_patch_id',
|
||||||
|
)
|
||||||
|
|
||||||
|
class get_patch_id:
|
||||||
|
def GET(self):
|
||||||
|
data = web.input(sw_version=None, prefix="CGCS")
|
||||||
|
output = pida.get_patch_id(data.sw_version, data.prefix)
|
||||||
|
return output
|
||||||
|
|
||||||
|
def POST(self):
|
||||||
|
data = web.input(sw_version=None, prefix="CGCS")
|
||||||
|
output = pida.get_patch_id(data.sw_version, data.prefix)
|
||||||
|
return output
|
||||||
|
|
||||||
|
class MyApplication(web.application):
|
||||||
|
def run(self, port=8080, *middleware):
|
||||||
|
func = self.wsgifunc(*middleware)
|
||||||
|
return web.httpserver.runsimple(func, ('0.0.0.0', port))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app = MyApplication(urls, globals())
|
||||||
|
app.run(port=port)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-2015 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
setuptools.setup(name='cgcs_patch',
|
||||||
|
version='1.0',
|
||||||
|
description='CGCS Patch',
|
||||||
|
packages=setuptools.find_packages(),
|
||||||
|
package_data = {
|
||||||
|
# Include templates
|
||||||
|
'': ['templates/*'],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,712 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid black;
|
||||||
|
border-collapse: collapse;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<caption>
|
||||||
|
<font size=10>Process restart information</font>
|
||||||
|
</caption>
|
||||||
|
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Process/Service</th>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>In service patchable</th>
|
||||||
|
<th>Managed by</th>
|
||||||
|
<th>Restart command</th>
|
||||||
|
<th>Patch Restart command</th>
|
||||||
|
<th>Restart dependency</th>
|
||||||
|
<th>Impact(if restarted while in operation)</th>
|
||||||
|
<th>Special handling required</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">ceilometer-polling</font></td>
|
||||||
|
<td>Daemon that polls Openstack services and build meters</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>PMON</td>
|
||||||
|
<td><b>/etc/init.d/openstack-ceilometer-polling restart</b></td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>As batch_polled_samples is set to True, may lose some samples that
|
||||||
|
are in the pollsters memory if the process is restarted exactly
|
||||||
|
when they have just finished polling for samples and are about to
|
||||||
|
publish these samples to RabbitMQ. This is about 10 millisecond
|
||||||
|
window for cpu_source and 0.03 millisecond 1 second window for
|
||||||
|
meter related sources.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">ceilometer-agent-notification</font></td>
|
||||||
|
<td>Daemon that listens to notifications on message queue, converts
|
||||||
|
them to Events and Samples and applies pipeline actions
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service ceilometer-agent-notification</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/ceilometer-agent-notification stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/ceilometer-agent-notification start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>May lose some samples/events if the process is restarted while they
|
||||||
|
are being transformed or converted.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">ceilometer-collector</font></td>
|
||||||
|
<td>Daemon that gathers and records event and metering data created by
|
||||||
|
notification and polling agents
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service ceilometer-collector</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/ceilometer-collector stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/ceilometer-collector
|
||||||
|
start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>May lose some samples/events if the process is restarted while they
|
||||||
|
are being persisted in Postgres DB. This is a tiny window
|
||||||
|
especially with recent optimization work (no message signature
|
||||||
|
verification, one single call to create_sample stored proc).<br>
|
||||||
|
Note: Making sure that child processes and their database
|
||||||
|
connections are released when a parent process is stopped is part
|
||||||
|
of collector functionality. It is not specific to in-service
|
||||||
|
patching.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">ceilometer-api</font></td>
|
||||||
|
<td>Service to query and view data recorded by the collector</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service ceilometer-api</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/ceilometer-api stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/ceilometer-api start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, horizon or CLI ceilometer request
|
||||||
|
will fail. Horizon request will be re-established automatically in
|
||||||
|
its next polling interval. CLI command needs to be re-issued.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">ceilometer-expirer-active</font></td>
|
||||||
|
<td>Cron job that purges expired samples and events as well as related
|
||||||
|
meter and resource data
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>CRON</td>
|
||||||
|
<td><b>N/A</b><br><br>
|
||||||
|
To run the expirer manually: /usr/bin/ceilometer-expirer-active
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>There is no need to restart after patch. The change will take
|
||||||
|
effect next time the expirer cron job is run.<br>
|
||||||
|
Unless there are new features specifically planned for expirer,
|
||||||
|
this code is very stable.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">haproxy</font></td>
|
||||||
|
<td>A Proxy service that is responsible for forwarding external REST
|
||||||
|
API requests to Open Stack and Titanium Cloud services that listening on the
|
||||||
|
internal interfaces.
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service haproxy</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /etc/init.d/haproxy stop<br>
|
||||||
|
/bin/sh /etc/init.d/haproxy start
|
||||||
|
</td>
|
||||||
|
<td><b>/usr/local/sbin/patch-restart-haproxy</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will fail
|
||||||
|
and new requests will get connection error until the service is
|
||||||
|
re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">sm</font></td>
|
||||||
|
<td>Service management daemon</td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>PMON</td>
|
||||||
|
<td><b>/etc/init.d/sm restart</b></td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>Will cause all services disabled on the active controller before
|
||||||
|
the standby controller takes over the control.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">sm-api</font></td>
|
||||||
|
<td>Daemon that provides sm api</td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>PMON</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td></td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">sm-eru</font></td>
|
||||||
|
<td>Daemon that records sm eru data</td>
|
||||||
|
<td>N</td>
|
||||||
|
<td></td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td></td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">sm-watchdog</font></td>
|
||||||
|
<td>Daemon that loads NFS watchdog module to look for and handle
|
||||||
|
stalled NFS threads
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
<td></td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td></td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">neutron-server</font></td>
|
||||||
|
<td>Service that manages network functions</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service neutron-server</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/neutron-server stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/neutron-server start
|
||||||
|
</td>
|
||||||
|
<td><b>/bin/neutron-restart neutron-server</b><br/>or<br/><b>/bin/neutron-restart --all</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>Will cause neutron services to not be available while restarting,
|
||||||
|
which will prevent instances from being created while it is down.
|
||||||
|
Could cause RPCs from computes to fail while it is restarting.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">neutron-dhcp-agent</font></td>
|
||||||
|
<td>Agent on compute node that manages DHCP servers for tenant
|
||||||
|
networks
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>PMON</td>
|
||||||
|
<td><b>/etc/init.d/neutron-dhcp-agent restart</b></td>
|
||||||
|
<td><b>/bin/neutron-restart neutron-dhcp-agent</b><br/>or<br/><b>/bin/neutron-restart --all</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>Will prevent binding new DHCP servers while it is down. Requires
|
||||||
|
special handling to kill metadata haproxy processes for networks.
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">neutron-metadata-agent</font></td>
|
||||||
|
<td>Agent on compute node serving metadata to nodes</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>PMON</td>
|
||||||
|
<td><b>/etc/init.d/neutron-metadata-agent restart</b></td>
|
||||||
|
<td><b>/bin/neutron-restart neutron-metadata-agent</b><br/>or<br/><b>/bin/neutron-restart --all</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>Nodes will not be able to receive metadata while it is down</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">neutron-sriov-nic-agent</font></td>
|
||||||
|
<td>Agent on compute node responsible for setting SR-IOV port
|
||||||
|
information
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>PMON</td>
|
||||||
|
<td><b>/etc/init.d/neutron-sriov-nic-agent restart</b></td>
|
||||||
|
<td><b>/bin/neutron-restart neutron-sriov-nic-agent</b><br/>or<br/><b>/bin/neutron-restart --all</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>Will not be able to set device parameters while restarting</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">neutron-bgp-dragent</font></td>
|
||||||
|
<td>BGP dynamic routing agent on controller node
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>PMON</td>
|
||||||
|
<td><b>/etc/init.d/neutron-bgp-dragent restart</b></td>
|
||||||
|
<td><b>/bin/neutron-restart neutron-bgp-dragent</b><br/>or<br/><b>/bin/neutron-restart --all</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>Will not be able to set device parameters while restarting</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">keystone-all</font></td>
|
||||||
|
<td>Keystone provides services that support an identity, token
|
||||||
|
management, and service catalog and policy functionality.
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service keystone</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/keystone stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/keystone start
|
||||||
|
</td>
|
||||||
|
<td><b>/usr/local/sbin/patch-restart-processes keystone-all</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will fail
|
||||||
|
and new requests will get connection error until the service is
|
||||||
|
re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">aodh-api</font></td>
|
||||||
|
<td>Aodh service that handles API requests for openstack alarming.</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service aodh-api</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/aodh-api stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/aodh-api start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will fail
|
||||||
|
and new requests will get connection error until the service is
|
||||||
|
re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">aodh-evaluator</font></td>
|
||||||
|
<td>Aodh service that performs threshold evaluation for openstack
|
||||||
|
alarming.
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service aodh-evaluator</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/aodh-evaluator stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/aodh-evaluator start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted no openstack alarm threshold
|
||||||
|
evaluations will be executed until the service is re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">aodh-listener</font></td>
|
||||||
|
<td>Aodh service that generates alarms based on events.</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service aodh-listener</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/aodh-listener stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/aodh-listener start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted no openstack event based alarms will
|
||||||
|
be generated until the service is re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">aodh-notifier</font></td>
|
||||||
|
<td>Aodh service that sends openstack alarm notifications.</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service aodh-notifier</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/aodh-notifier stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/aodh-notifier start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted no openstack alarm threshold
|
||||||
|
notifications will be issued until the service is re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">aodh-expirer-active</font></td>
|
||||||
|
<td>Cron job that purges expired openstack alarms</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>CRON</td>
|
||||||
|
<td><b>N/A</b><br><br>
|
||||||
|
To run the expirer manually: /usr/bin/aodh-expirer-active
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>There is no need to restart after patch. The change will take
|
||||||
|
effect next time the expirer cron job is run.<br>
|
||||||
|
Unless there are new features specifically planned for expirer,
|
||||||
|
this code is very stable.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">heat-api</font></td>
|
||||||
|
<td>Heat service for API requests for openstack orchestration.</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service heat-api</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/heat-api stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/heat-api start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, horizon or CLI heat requests will
|
||||||
|
fail. Horizon will re-established automatically. CLI commands needs
|
||||||
|
to be re-issued. Heat stack updates in progress may fail.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">heat-api-cfn</font></td>
|
||||||
|
<td>Heat service for AWS Cloudformation API requests.</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service heat-api-cfn</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/heat-api-cfn stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/heat-api-cfn start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, cloudformation API requests such as
|
||||||
|
autoscaling will not be processed.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">heat-api-cloudwatch</font></td>
|
||||||
|
<td>Heat service for AWS Cloudwatch metric collection.</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service heat-api-cloudwatch</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/heat-api-cloudwatch stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/heat-api-cloudwatch start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, stats sent from VMs will not be
|
||||||
|
processed.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">heat-engine</font></td>
|
||||||
|
<td>Heat service for AWS Cloudwatch metric collection.</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service heat-engine</b><br>
|
||||||
|
which runs the following:<br><br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/heat-engine stop<br>
|
||||||
|
/bin/sh /usr/lib/ocf/resource.d/openstack/heat-engine start
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, openstrack heat orchestration
|
||||||
|
commands will not be processed. Stacks being created, deleted or
|
||||||
|
updated will fail and need to be re-initiated.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">heat-purge-deleted-active</font></td>
|
||||||
|
<td>Cron job that purges deleted openstack heat stacks from the
|
||||||
|
database
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>CRON</td>
|
||||||
|
<td><b>N/A</b><br><br>
|
||||||
|
To run the expirer manually: /usr/bin/heat-purge-deleted-active
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>There is no need to restart after patch. The change will take
|
||||||
|
effect next time the cron job is run.<br>
|
||||||
|
Unless there are new features specifically planned, this code is
|
||||||
|
very stable.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">Glance</font></td>
|
||||||
|
<td>Glance imaging service - a single script restarts both glance-api
|
||||||
|
and glance-registry.
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>/usr/bin/restart-glance</b><br>
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will
|
||||||
|
continue and new requests will get connection error until the
|
||||||
|
service is re-enabled. The graceful restart takes more than 30
|
||||||
|
secs the process is killed. Timers are configurable from the
|
||||||
|
restart script
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">Cinder</font></td>
|
||||||
|
<td>Cinder volume service - a single script restarts cinder-volume,
|
||||||
|
cinder-scheduler and cinder-api.
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>/usr/bin/restart-cinder</b><br>
|
||||||
|
</td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will
|
||||||
|
continue and new requests will get connection error until the
|
||||||
|
service is re-enabled. Timers are configurable from the restart
|
||||||
|
script
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">Horizon</font></td>
|
||||||
|
<td>Horizon - Openstack Dashboard GUI used to control openstack and Titanium Cloud
|
||||||
|
operations
|
||||||
|
</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart service horizon</b><br>
|
||||||
|
</td>
|
||||||
|
<td><b>/usr/bin/horizon-patching-restart</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>When horizon is restarted via the patch restart command all users
|
||||||
|
will be logged out. If they try to log back in before the server is
|
||||||
|
up again they will see an internal server error. It usually takes
|
||||||
|
less than a minute for the service to restart
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">IO-Monitor</font></td>
|
||||||
|
<td>Daemon which monitors cinder devices and raises alarms for excessive storage IO load.</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>PMON</td>
|
||||||
|
<td><b>pmon-restart io-monitor-manager</b></td>
|
||||||
|
<td><b>/usr/local/sbin/patch-restart-processes io-monitor-manager</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>Generally there should be no impact. It is very unlikely for
|
||||||
|
the system to encounter an excessive storage IO load which will
|
||||||
|
only last a couple of seconds until the io-monitor process is restarted,
|
||||||
|
such that it will not be detected.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">vim</font></td>
|
||||||
|
<td>Virtual Infrastructure Manager</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service vim</b></td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarting, requests through the VIM API or
|
||||||
|
through the Nova API Proxy will fail. Any instance actions normally
|
||||||
|
triggered due to instance state changes (from nova) will not occur
|
||||||
|
until the process starts up again and audits the instance states.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">vim-api</font></td>
|
||||||
|
<td>Virtual Infrastructure Manager API</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service vim-api</b></td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarting, requests through the external VIM
|
||||||
|
API will fail.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">vim-webserver</font></td>
|
||||||
|
<td>Virtual Infrastructure Manager Web Server</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service vim-webserver</b></td>
|
||||||
|
<td><b></b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>No impact. This service is for design use only.</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">nova-api</font></td>
|
||||||
|
<td>Nova API Service</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service nova-api</b><br></td>
|
||||||
|
<td><b>/bin/nova-restart</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will
|
||||||
|
fail and new requests will get connection error until the service
|
||||||
|
is re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">nova-placement-api</font></td>
|
||||||
|
<td>Nova Placement API Service</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service nova-placement-api</b><br></td>
|
||||||
|
<td><b>/bin/nova-restart</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will
|
||||||
|
fail and new requests will get connection error until the service
|
||||||
|
is re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">nova-conductor</font></td>
|
||||||
|
<td>Nova Conductor Service</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service nova-conductor</b><br></td>
|
||||||
|
<td><b>/bin/nova-restart</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will
|
||||||
|
fail and new requests will get connection error until the service
|
||||||
|
is re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">nova-scheduler</font></td>
|
||||||
|
<td>Nova Scheduler Service</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service nova-scheduler</b><br></td>
|
||||||
|
<td><b>/bin/nova-restart</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will
|
||||||
|
fail and new requests will get connection error until the service
|
||||||
|
is re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">nova-console-auth</font></td>
|
||||||
|
<td>Nova Console Auth Service</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service nova-console-auth</b><br></td>
|
||||||
|
<td><b>/bin/nova-restart</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will
|
||||||
|
fail and new requests will get connection error until the service
|
||||||
|
is re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">nova-novnc</font></td>
|
||||||
|
<td>Nova VNC Service</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>SM</td>
|
||||||
|
<td><b>sm-restart-safe service nova-novnc</b><br></td>
|
||||||
|
<td><b>/bin/nova-restart</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the service is restarted, the outstanding requests will
|
||||||
|
fail and new requests will get connection error until the service
|
||||||
|
is re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">nova-compute</font></td>
|
||||||
|
<td>Nova Compute Service</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>PMON</td>
|
||||||
|
<td><b>/usr/local/sbin/pmon-restart nova-compute</b><br></td>
|
||||||
|
<td><b>/bin/nova-restart</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>While the services is restarted, the outstanding requests will
|
||||||
|
fail and new requests will get connection error until the service
|
||||||
|
is re-enabled.
|
||||||
|
</td>
|
||||||
|
<td>N</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><font color="blue">ceph-osd & ceph-mon</font></td>
|
||||||
|
<td>Ceph OSD and Monitor processes</td>
|
||||||
|
<td>Y</td>
|
||||||
|
<td>PMON</td>
|
||||||
|
<td><b>/etc/ceph/ceph_pmon_wrapper.sh restart</b><br></td>
|
||||||
|
<td><b>/etc/ceph/ceph_pmon_wrapper.sh restart</b></td>
|
||||||
|
<td>N</td>
|
||||||
|
<td>Ceph processes on a node will restart (ceph-mon and ceph-osd). The restart
|
||||||
|
will take at most 30s and functionality should not be affected. Note that this
|
||||||
|
command should not be executed at the same time on storage-0 and any of the
|
||||||
|
controller nodes as we do not support restarting two of the three ceph-mon at
|
||||||
|
the same time.
|
||||||
|
</td>
|
||||||
|
<td>Restarting it on controller-0, controller-1 & storage-0,
|
||||||
|
at the same time with glance, cinder, nova, ceph-rest-api, sysinv or ceph-manager
|
||||||
|
on the active controller should be avoided due to ~30 secs delay to ceph APIs.
|
||||||
|
This delay happens when any of the ceph-mon changes state and may cause timeouts
|
||||||
|
when dependent services restart. Recommendations: (1) On the active controller,
|
||||||
|
restart Ceph before the other service; (2) updating ctrl-0,ctrl-1 & storage-0
|
||||||
|
at the same time should be avoided.</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th>Process/Service</th>
|
||||||
|
<th>Function</th>
|
||||||
|
<th>In service patchable</th>
|
||||||
|
<th>Managed by</th>
|
||||||
|
<th>Restart command</th>
|
||||||
|
<th>Patch Restart command</th>
|
||||||
|
<th>Restart dependency</th>
|
||||||
|
<th>Impact(if restarted while in operation)</th>
|
||||||
|
<th>Special handling required</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,10 @@
|
||||||
|
cgcs/middleware/sysinv/recipes-common|sysinv
|
||||||
|
cgcs/middleware/patching/recipes-common/cgcs-patch|cgcs-patch
|
||||||
|
cgcs/middleware/patching/recipes-common/patch-alarm|patch-alarm
|
||||||
|
cgcs/middleware/patching/recipes-common/patch-boot-args|patch-boot-args
|
||||||
|
cgcs/middleware/patching/recipes-common/patch-scripts|patch-scripts
|
||||||
|
cgcs/middleware/patching/recipes-common/requests-toolbelt|requests-toolbelt
|
||||||
|
cgcs/middleware/patching/recipes-common/smart-helper|smart-helper
|
||||||
|
cgcs/middleware/config/recipes-compute/computeconfig/computeconfig|computeconfig
|
||||||
|
cgcs/middleware/config/recipes-control/controllerconfig/controllerconfig|controllerconfig
|
||||||
|
cgcs/middleware/config/recipes-common/tsconfig|tsconfig
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,13 @@
|
||||||
|
Metadata-Version: 1.1
|
||||||
|
Name: patch-alarm
|
||||||
|
Version: 1.0
|
||||||
|
Summary: Patch alarm management
|
||||||
|
Home-page:
|
||||||
|
Author: Windriver
|
||||||
|
Author-email: info@windriver.com
|
||||||
|
License: Apache-2.0
|
||||||
|
|
||||||
|
Description: Patch alarm management
|
||||||
|
|
||||||
|
|
||||||
|
Platform: UNKNOWN
|
|
@ -0,0 +1,95 @@
|
||||||
|
source "$SRC_BASE/build-tools/spec-utils"
|
||||||
|
|
||||||
|
if [ "x$DATA" == "x" ]; then
|
||||||
|
echo "ERROR: Environment variable 'DATA' not defined."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$DATA" ]; then
|
||||||
|
echo "ERROR: Couldn't find '$PWD/$DATA'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
unset TIS_PATCH_VER # Ensure there's nothing in the env already
|
||||||
|
|
||||||
|
source $DATA
|
||||||
|
|
||||||
|
if [ -z "$TIS_PATCH_VER" ]; then
|
||||||
|
echo "ERROR: TIS_PATCH_VER must be defined"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SRC_DIR="patch-alarm"
|
||||||
|
EXTRA_DIR="scripts"
|
||||||
|
|
||||||
|
VERSION=$(grep '^Version:' PKG-INFO | awk -F ': ' '{print $2}' | sed -e 's/^[[:space:]]*//')
|
||||||
|
TAR_NAME=$(grep '^Name:' PKG-INFO | awk -F ': ' '{print $2}' | sed -e 's/^[[:space:]]*//')
|
||||||
|
CUR_DIR=`pwd`
|
||||||
|
BUILD_DIR="$RPMBUILD_BASE"
|
||||||
|
|
||||||
|
mkdir -p $BUILD_DIR/SRPMS
|
||||||
|
|
||||||
|
TAR="$TAR_NAME-$VERSION.tar.gz"
|
||||||
|
TAR_PATH="$BUILD_DIR/SOURCES/$TAR"
|
||||||
|
|
||||||
|
TAR_NEEDED=0
|
||||||
|
if [ -f $TAR_PATH ]; then
|
||||||
|
n=`find . -cnewer $TAR_PATH -and ! -path './.git*' \
|
||||||
|
-and ! -path './build/*' \
|
||||||
|
-and ! -path './.pc/*' \
|
||||||
|
-and ! -path './patches/*' \
|
||||||
|
-and ! -path "./$DISTRO/*" \
|
||||||
|
-and ! -path './pbr-*.egg/*' \
|
||||||
|
| wc -l`
|
||||||
|
if [ $n -gt 0 ]; then
|
||||||
|
TAR_NEEDED=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
TAR_NEEDED=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $TAR_NEEDED -gt 0 ]; then
|
||||||
|
tar czvf $TAR_PATH $SRC_DIR $EXTRA_DIR \
|
||||||
|
--exclude='.git*' \
|
||||||
|
--exclude='build' \
|
||||||
|
--exclude='.pc' \
|
||||||
|
--exclude='patches' \
|
||||||
|
--exclude="$DISTRO" \
|
||||||
|
--exclude='pbr-*.egg' \
|
||||||
|
--transform "s,^$SRC_DIR,$TAR_NAME-$VERSION,"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
for SPEC in `ls $BUILD_DIR/SPECS`; do
|
||||||
|
SPEC_PATH="$BUILD_DIR/SPECS/$SPEC"
|
||||||
|
RELEASE=`spec_find_tag Release "$SPEC_PATH" 2>> /dev/null`
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "ERROR: 'Release' not found in '$SPEC_PATH'"
|
||||||
|
fi
|
||||||
|
NAME=`spec_find_tag Name "$SPEC_PATH" 2>> /dev/null`
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "ERROR: 'Name' not found in '$SPEC_PATH'"
|
||||||
|
fi
|
||||||
|
SRPM="$NAME-$VERSION-$RELEASE.src.rpm"
|
||||||
|
SRPM_PATH="$BUILD_DIR/SRPMS/$SRPM"
|
||||||
|
|
||||||
|
BUILD_NEEDED=0
|
||||||
|
if [ -f $SRPM_PATH ]; then
|
||||||
|
n=`find . -cnewer $SRPM_PATH | wc -l`
|
||||||
|
if [ $n -gt 0 ]; then
|
||||||
|
BUILD_NEEDED=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
BUILD_NEEDED=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $BUILD_NEEDED -gt 0 ]; then
|
||||||
|
echo "SPEC file: $SPEC_PATH"
|
||||||
|
echo "SRPM build directory: $BUILD_DIR"
|
||||||
|
echo "TIS_PATCH_VER: $TIS_PATCH_VER"
|
||||||
|
|
||||||
|
sed -i -e "1 i%define tis_patch_ver $TIS_PATCH_VER" $SPEC_PATH
|
||||||
|
rpmbuild -bs $SPEC_PATH --define="%_topdir $BUILD_DIR" --define="_tis_dist .tis"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
TIS_PATCH_VER=2
|
|
@ -0,0 +1,55 @@
|
||||||
|
Summary: Patch alarm management
|
||||||
|
Name: patch-alarm
|
||||||
|
Version: 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
|
||||||
|
|
||||||
|
%define debug_package %{nil}
|
||||||
|
|
||||||
|
BuildRequires: python-setuptools
|
||||||
|
Requires: python-devel
|
||||||
|
Requires: /bin/bash
|
||||||
|
|
||||||
|
%description
|
||||||
|
TIS Platform Patching
|
||||||
|
|
||||||
|
%define pythonroot /usr/lib64/python2.7/site-packages
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup
|
||||||
|
|
||||||
|
%build
|
||||||
|
%{__python} setup.py build
|
||||||
|
|
||||||
|
%install
|
||||||
|
%{__python} setup.py install --root=$RPM_BUILD_ROOT \
|
||||||
|
--install-lib=%{pythonroot} \
|
||||||
|
--prefix=/usr \
|
||||||
|
--install-data=/usr/share \
|
||||||
|
--single-version-externally-managed
|
||||||
|
|
||||||
|
install -m 755 -d %{buildroot}%{_bindir}
|
||||||
|
install -m 755 -d %{buildroot}%{_sysconfdir}/init.d
|
||||||
|
|
||||||
|
install -m 700 ${RPM_BUILD_DIR}/scripts/bin/patch-alarm-manager \
|
||||||
|
%{buildroot}%{_bindir}/patch-alarm-manager
|
||||||
|
|
||||||
|
install -m 700 ${RPM_BUILD_DIR}/scripts/init.d/patch-alarm-manager \
|
||||||
|
%{buildroot}%{_sysconfdir}/init.d/patch-alarm-manager
|
||||||
|
|
||||||
|
%clean
|
||||||
|
rm -rf $RPM_BUILD_ROOT
|
||||||
|
|
||||||
|
|
||||||
|
%files
|
||||||
|
%defattr(-,root,root,-)
|
||||||
|
%doc LICENSE
|
||||||
|
%{pythonroot}/patch_alarm
|
||||||
|
%{pythonroot}/patch_alarm-*.egg-info
|
||||||
|
"%{_bindir}/patch-alarm-manager"
|
||||||
|
"%{_sysconfdir}/init.d/patch-alarm-manager"
|
||||||
|
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,6 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
|
@ -0,0 +1,223 @@
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
###################
|
||||||
|
# IMPORTS
|
||||||
|
###################
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
from daemon import runner
|
||||||
|
from fm_api import fm_api
|
||||||
|
from fm_api import constants as fm_constants
|
||||||
|
|
||||||
|
import cgcs_patch.config as cfg
|
||||||
|
from cgcs_patch.patch_functions import configure_logging
|
||||||
|
from cgcs_patch.constants import ENABLE_DEV_CERTIFICATE_PATCH_IDENTIFIER
|
||||||
|
|
||||||
|
###################
|
||||||
|
# CONSTANTS
|
||||||
|
###################
|
||||||
|
LOG_FILE = '/var/log/patch-alarms.log'
|
||||||
|
PID_FILE = '/var/run/patch-alarm-manager.pid'
|
||||||
|
|
||||||
|
#logging.basicConfig(filename=LOG_FILE, level=logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# METHODS
|
||||||
|
###################
|
||||||
|
def start_polling():
|
||||||
|
cfg.read_config()
|
||||||
|
patch_alarm_daemon = PatchAlarmDaemon()
|
||||||
|
alarm_runner = runner.DaemonRunner(patch_alarm_daemon)
|
||||||
|
alarm_runner.daemon_context.umask = 0o022
|
||||||
|
alarm_runner.do_action()
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# CLASSES
|
||||||
|
###################
|
||||||
|
class PatchAlarmDaemon():
|
||||||
|
""" Daemon process representation of
|
||||||
|
the patch monitoring program
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
# Daemon-specific init
|
||||||
|
self.stdin_path = '/dev/null'
|
||||||
|
self.stdout_path = '/dev/null'
|
||||||
|
self.stderr_path = '/dev/null'
|
||||||
|
self.pidfile_path = PID_FILE
|
||||||
|
self.pidfile_timeout = 5
|
||||||
|
|
||||||
|
self.api_addr = "127.0.0.1:%d" % cfg.api_port
|
||||||
|
|
||||||
|
self.fm_api = fm_api.FaultAPIs()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
configure_logging()
|
||||||
|
|
||||||
|
requests_logger = logging.getLogger('requests')
|
||||||
|
requests_logger.setLevel(logging.CRITICAL)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# start monitoring patch status
|
||||||
|
self.check_patch_alarms()
|
||||||
|
|
||||||
|
# run/poll every 1 min
|
||||||
|
time.sleep(60)
|
||||||
|
|
||||||
|
def check_patch_alarms(self):
|
||||||
|
self._handle_patch_alarms()
|
||||||
|
self._get_handle_failed_hosts()
|
||||||
|
|
||||||
|
def _handle_patch_alarms(self):
|
||||||
|
url = "http://%s/patch/query" % self.api_addr
|
||||||
|
|
||||||
|
try:
|
||||||
|
req = requests.get(url)
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
entity_instance_id = "%s=%s" % (fm_constants.FM_ENTITY_TYPE_HOST, "controller")
|
||||||
|
|
||||||
|
raise_pip_alarm = False
|
||||||
|
raise_obs_alarm = False
|
||||||
|
raise_cert_alarm = False
|
||||||
|
if req.status_code == 200:
|
||||||
|
data = json.loads(req.text)
|
||||||
|
|
||||||
|
if 'pd' in data:
|
||||||
|
for patch_id, metadata in data['pd'].iteritems():
|
||||||
|
if 'patchstate' in metadata and \
|
||||||
|
(metadata['patchstate'] == 'Partial-Apply' or metadata['patchstate'] == 'Partial-Remove'):
|
||||||
|
raise_pip_alarm = True
|
||||||
|
if 'status' in metadata and \
|
||||||
|
(metadata['status'] == 'OBS' or metadata['status'] == 'Obsolete'):
|
||||||
|
raise_obs_alarm = True
|
||||||
|
# If there is a patch in the system (in any state) that is
|
||||||
|
# named some variation of "enable-dev-certificate", raise
|
||||||
|
# the 'developer certificate could allow for untrusted
|
||||||
|
# patches' alarm
|
||||||
|
if ENABLE_DEV_CERTIFICATE_PATCH_IDENTIFIER in patch_id:
|
||||||
|
raise_cert_alarm = True
|
||||||
|
|
||||||
|
pip_alarm = self.fm_api.get_fault(fm_constants.FM_ALARM_ID_PATCH_IN_PROGRESS,
|
||||||
|
entity_instance_id)
|
||||||
|
if raise_pip_alarm and pip_alarm is None:
|
||||||
|
logging.info("Raising patch-in-progress alarm")
|
||||||
|
fault = fm_api.Fault(alarm_id = fm_constants.FM_ALARM_ID_PATCH_IN_PROGRESS,
|
||||||
|
alarm_type = fm_constants.FM_ALARM_TYPE_5,
|
||||||
|
alarm_state = fm_constants.FM_ALARM_STATE_SET,
|
||||||
|
entity_type_id = fm_constants.FM_ENTITY_TYPE_HOST,
|
||||||
|
entity_instance_id = entity_instance_id,
|
||||||
|
severity = fm_constants.FM_ALARM_SEVERITY_MINOR,
|
||||||
|
reason_text = 'Patching operation in progress',
|
||||||
|
probable_cause = fm_constants.ALARM_PROBABLE_CAUSE_65,
|
||||||
|
proposed_repair_action = 'Complete reboots of affected hosts',
|
||||||
|
service_affecting = False)
|
||||||
|
|
||||||
|
self.fm_api.set_fault(fault)
|
||||||
|
elif not raise_pip_alarm and pip_alarm is not None:
|
||||||
|
logging.info("Clearing patch-in-progress alarm")
|
||||||
|
self.fm_api.clear_fault(fm_constants.FM_ALARM_ID_PATCH_IN_PROGRESS,
|
||||||
|
entity_instance_id)
|
||||||
|
|
||||||
|
obs_alarm = self.fm_api.get_fault(fm_constants.FM_ALARM_ID_PATCH_OBS_IN_SYSTEM,
|
||||||
|
entity_instance_id)
|
||||||
|
if raise_obs_alarm and obs_alarm is None:
|
||||||
|
logging.info("Raising obsolete-patch-in-system alarm")
|
||||||
|
fault = fm_api.Fault(alarm_id = fm_constants.FM_ALARM_ID_PATCH_OBS_IN_SYSTEM,
|
||||||
|
alarm_type = fm_constants.FM_ALARM_TYPE_5,
|
||||||
|
alarm_state = fm_constants.FM_ALARM_STATE_SET,
|
||||||
|
entity_type_id = fm_constants.FM_ENTITY_TYPE_HOST,
|
||||||
|
entity_instance_id = entity_instance_id,
|
||||||
|
severity = fm_constants.FM_ALARM_SEVERITY_WARNING,
|
||||||
|
reason_text = 'Obsolete patch in system',
|
||||||
|
probable_cause = fm_constants.ALARM_PROBABLE_CAUSE_65,
|
||||||
|
proposed_repair_action = 'Remove and delete obsolete patches',
|
||||||
|
service_affecting = False)
|
||||||
|
|
||||||
|
self.fm_api.set_fault(fault)
|
||||||
|
elif not raise_obs_alarm and obs_alarm is not None:
|
||||||
|
logging.info("Clearing obsolete-patch-in-system alarm")
|
||||||
|
self.fm_api.clear_fault(fm_constants.FM_ALARM_ID_PATCH_OBS_IN_SYSTEM,
|
||||||
|
entity_instance_id)
|
||||||
|
|
||||||
|
cert_alarm = self.fm_api.get_fault(fm_constants.FM_ALARM_ID_NONSTANDARD_CERT_PATCH,
|
||||||
|
entity_instance_id)
|
||||||
|
if raise_cert_alarm and cert_alarm is None:
|
||||||
|
logging.info("Raising developer-certificate-enabled alarm")
|
||||||
|
fault = fm_api.Fault(alarm_id = fm_constants.FM_ALARM_ID_NONSTANDARD_CERT_PATCH,
|
||||||
|
alarm_type = fm_constants.FM_ALARM_TYPE_9,
|
||||||
|
alarm_state = fm_constants.FM_ALARM_STATE_SET,
|
||||||
|
entity_type_id = fm_constants.FM_ENTITY_TYPE_HOST,
|
||||||
|
entity_instance_id = entity_instance_id,
|
||||||
|
severity = fm_constants.FM_ALARM_SEVERITY_CRITICAL,
|
||||||
|
reason_text = 'Developer patch certificate is enabled',
|
||||||
|
probable_cause = fm_constants.ALARM_PROBABLE_CAUSE_65,
|
||||||
|
proposed_repair_action = 'Reinstall system to disable certificate and remove untrusted patches',
|
||||||
|
suppression = False,
|
||||||
|
service_affecting = False)
|
||||||
|
|
||||||
|
self.fm_api.set_fault(fault)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_handle_failed_hosts(self):
|
||||||
|
url = "http://%s/patch/query_hosts" % self.api_addr
|
||||||
|
|
||||||
|
try:
|
||||||
|
req = requests.get(url)
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
entity_instance_id = "%s=%s" % (fm_constants.FM_ENTITY_TYPE_HOST, "controller")
|
||||||
|
|
||||||
|
failed_hosts = []
|
||||||
|
if req.status_code == 200:
|
||||||
|
data = json.loads(req.text)
|
||||||
|
|
||||||
|
if 'data' in data:
|
||||||
|
for host in data['data']:
|
||||||
|
if 'hostname' in host and 'patch_failed' in host and host['patch_failed']:
|
||||||
|
failed_hosts.append(host['hostname'])
|
||||||
|
|
||||||
|
# Query existing alarms
|
||||||
|
patch_failed_alarm = self.fm_api.get_fault(fm_constants.FM_ALARM_ID_PATCH_HOST_INSTALL_FAILED,
|
||||||
|
entity_instance_id)
|
||||||
|
|
||||||
|
if len(failed_hosts) > 0:
|
||||||
|
reason_text = "Patch installation failed on the following hosts: %s" % ", ".join(sorted(failed_hosts))
|
||||||
|
|
||||||
|
if patch_failed_alarm is None or reason_text != patch_failed_alarm.reason_text:
|
||||||
|
if patch_failed_alarm is None:
|
||||||
|
logging.info("Raising patch-host-install-failure alarm")
|
||||||
|
else:
|
||||||
|
logging.info("Updating patch-host-install-failure alarm")
|
||||||
|
|
||||||
|
fault = fm_api.Fault(alarm_id = fm_constants.FM_ALARM_ID_PATCH_HOST_INSTALL_FAILED,
|
||||||
|
alarm_type = fm_constants.FM_ALARM_TYPE_5,
|
||||||
|
alarm_state = fm_constants.FM_ALARM_STATE_SET,
|
||||||
|
entity_type_id = fm_constants.FM_ENTITY_TYPE_HOST,
|
||||||
|
entity_instance_id = entity_instance_id,
|
||||||
|
severity = fm_constants.FM_ALARM_SEVERITY_MAJOR,
|
||||||
|
reason_text = reason_text,
|
||||||
|
probable_cause = fm_constants.ALARM_PROBABLE_CAUSE_65,
|
||||||
|
proposed_repair_action = 'Undo patching operation',
|
||||||
|
service_affecting = False)
|
||||||
|
self.fm_api.set_fault(fault)
|
||||||
|
|
||||||
|
elif patch_failed_alarm is not None:
|
||||||
|
logging.info("Clearing patch-host-install-failure alarm")
|
||||||
|
self.fm_api.clear_fault(fm_constants.FM_ALARM_ID_PATCH_HOST_INSTALL_FAILED,
|
||||||
|
entity_instance_id)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
setuptools.setup(name='patch_alarm',
|
||||||
|
version='1.0.0',
|
||||||
|
description='CEPH alarm',
|
||||||
|
license='Apache-2.0',
|
||||||
|
packages=['patch_alarm'],
|
||||||
|
entry_points={
|
||||||
|
}
|
||||||
|
)
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
from patch_alarm import patch_alarm_manager
|
||||||
|
except EnvironmentError as e:
|
||||||
|
print >> sys.stderr, "Error importing patch_alarm_manager: ", str(e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
patch_alarm_manager.start_polling()
|
|
@ -0,0 +1,98 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: patch-alarm-manager
|
||||||
|
# Required-Start: $patch
|
||||||
|
# Required-Stop: $patch
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: Daemon for polling patch status
|
||||||
|
# Description: Daemon for polling patch status
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
DESC="patch-alarm-manager"
|
||||||
|
DAEMON="/usr/bin/patch-alarm-manager"
|
||||||
|
RUNDIR="/var/run"
|
||||||
|
PIDFILE=$RUNDIR/$DESC.pid
|
||||||
|
|
||||||
|
start()
|
||||||
|
{
|
||||||
|
if [ -e $PIDFILE ]; then
|
||||||
|
PIDDIR=/prod/$(cat $PIDFILE)
|
||||||
|
if [ -d ${PIDFILE} ]; then
|
||||||
|
echo "$DESC already running."
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "Removing stale PID file $PIDFILE"
|
||||||
|
rm -f $PIDFILE
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Starting $DESC..."
|
||||||
|
mkdir -p $RUNDIR
|
||||||
|
start-stop-daemon --start --quiet \
|
||||||
|
--pidfile ${PIDFILE} --exec ${DAEMON} start
|
||||||
|
|
||||||
|
#--make-pidfile
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "done."
|
||||||
|
else
|
||||||
|
echo "failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
stop()
|
||||||
|
{
|
||||||
|
echo -n "Stopping $DESC..."
|
||||||
|
start-stop-daemon --stop --quiet --pidfile $PIDFILE
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "done."
|
||||||
|
else
|
||||||
|
echo "failed."
|
||||||
|
fi
|
||||||
|
rm -f $PIDFILE
|
||||||
|
}
|
||||||
|
|
||||||
|
status()
|
||||||
|
{
|
||||||
|
pid=`cat $PIDFILE 2>/dev/null`
|
||||||
|
if [ -n "$pid" ]; then
|
||||||
|
if ps -p $pid &>/dev/null ; then
|
||||||
|
echo "$DESC is running"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "$DESC is not running but has pid file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "$DESC is not running"
|
||||||
|
exit 3
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
start
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop
|
||||||
|
;;
|
||||||
|
restart|force-reload|reload)
|
||||||
|
stop
|
||||||
|
start
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
status
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {start|stop|force-reload|restart|reload|status}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,27 @@
|
||||||
|
Name: EXAMPLE_0001
|
||||||
|
Summary: TIS In-Service Patch Scripts Example
|
||||||
|
Version: 1.0
|
||||||
|
Release: %{tis_patch_ver}%{?_tis_dist}
|
||||||
|
License: Apache-2.0
|
||||||
|
Group: base
|
||||||
|
Packager: Wind River <info@windriver.com>
|
||||||
|
Source0: example-restart
|
||||||
|
|
||||||
|
%install
|
||||||
|
install -Dp -m 700 %{S:0} %{buildroot}%{_patch_scripts}/%{name}
|
||||||
|
|
||||||
|
%description
|
||||||
|
%{summary}
|
||||||
|
|
||||||
|
%files
|
||||||
|
%defattr(-,root,root,-)
|
||||||
|
%{_patch_scripts}/*
|
||||||
|
|
||||||
|
%post
|
||||||
|
cp -f %{_patch_scripts}/%{name} %{_runtime_patch_scripts}/
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
%preun
|
||||||
|
cp -f %{_patch_scripts}/%{name} %{_runtime_patch_scripts}/
|
||||||
|
exit 0
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
COPY_LIST="scripts/*"
|
||||||
|
TIS_PATCH_VER=0
|
|
@ -0,0 +1,128 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# This script provides an example in-service patching restart
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# The patching subsystem provides a patch-functions bash source file
|
||||||
|
# with useful function and variable definitions.
|
||||||
|
#
|
||||||
|
. /etc/patching/patch-functions
|
||||||
|
|
||||||
|
#
|
||||||
|
# We can now check to see what type of node we're on, if it's locked, etc,
|
||||||
|
# and act accordingly
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Declare an overall script return code
|
||||||
|
#
|
||||||
|
declare -i GLOBAL_RC=$PATCH_STATUS_OK
|
||||||
|
|
||||||
|
# NOTE: The following restart example code could be implemented in scripts
|
||||||
|
# owned by the various domains, with a single high-level call in the patch-script.
|
||||||
|
# This would be the preferred method, in fact, to ensure the patch-scripts
|
||||||
|
# themselves are simple and clean.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# First up, we'll handle restarting the sysinv-agent, which runs on all nodes
|
||||||
|
#
|
||||||
|
if [ ! -f $PATCH_FLAGDIR/sysinv-agent.restarted ]
|
||||||
|
then
|
||||||
|
# The sysinv-agent has not yet been restarted in this patch operation
|
||||||
|
systemctl status sysinv-agent.service
|
||||||
|
if [ $? -eq 0 ]
|
||||||
|
then
|
||||||
|
# The daemon is running, so restart it
|
||||||
|
loginfo "$0: Restarting sysinv-agent"
|
||||||
|
pmon-restart sysinv-agent
|
||||||
|
touch $PATCH_FLAGDIR/sysinv-agent.restarted
|
||||||
|
|
||||||
|
# Wait up to 15 seconds for service to recover
|
||||||
|
let -i UNTIL=$SECONDS+15
|
||||||
|
while [ $UNTIL -ge $SECONDS ]
|
||||||
|
do
|
||||||
|
# Check to make sure it's running
|
||||||
|
systemctl status sysinv-agent.service
|
||||||
|
if [ $? -eq 0 ]
|
||||||
|
then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Not running... Let's wait a couple of seconds and check again
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
systemctl status sysinv-agent.service
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
# Still not running! Clear the flag and mark the RC as failed
|
||||||
|
rm -f $PATCH_FLAGDIR/sysinv-agent.restarted
|
||||||
|
GLOBAL_RC=$PATCH_STATUS_FAILED
|
||||||
|
loginfo "$0: Failed to restart sysinv-agent"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Next, handle restarting horizon.
|
||||||
|
# TODO: There will be some SM enhancements coming to provide
|
||||||
|
# utilities we can use to facilitate in-service patching.
|
||||||
|
# For now, we'll do this a slightly uglier fashion
|
||||||
|
#
|
||||||
|
if is_controller
|
||||||
|
then
|
||||||
|
# Horizon only runs on the controller
|
||||||
|
|
||||||
|
if [ ! -f $PATCH_FLAGDIR/horizon.restarted ]
|
||||||
|
then
|
||||||
|
# Check SM to see if Horizon is running
|
||||||
|
sm-query service horizon | grep -q 'enabled-active'
|
||||||
|
if [ $? -eq 0 ]
|
||||||
|
then
|
||||||
|
loginfo "$0: Restarting horizon"
|
||||||
|
|
||||||
|
# Ask SM to restart Horizon
|
||||||
|
sm-restart service horizon
|
||||||
|
touch $PATCH_FLAGDIR/horizon.restarted
|
||||||
|
|
||||||
|
# Wait up to 30 seconds for service to recover
|
||||||
|
let -i UNTIL=$SECONDS+30
|
||||||
|
while [ $UNTIL -ge $SECONDS ]
|
||||||
|
do
|
||||||
|
# Check to see if it's running
|
||||||
|
sm-query service horizon | grep -q 'enabled-active'
|
||||||
|
if [ $? -eq 0 ]
|
||||||
|
then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Still not running? Let's wait 5 seconds and check again
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
sm-query service horizon | grep -q 'enabled-active'
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
# Still not running! Clear the flag and mark the RC as failed
|
||||||
|
loginfo "$0: Failed to restart horizon"
|
||||||
|
rm -f $PATCH_FLAGDIR/horizon.restarted
|
||||||
|
GLOBAL_RC=$PATCH_STATUS_FAILED
|
||||||
|
sm-query service horizon
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Exit the script with the overall return code
|
||||||
|
#
|
||||||
|
exit $GLOBAL_RC
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue