diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index d0bed96..0000000 --- a/.coveragerc +++ /dev/null @@ -1,13 +0,0 @@ -# .coveragerc to control coverage.py -[run] -branch = True -omit = tests/coverage/* - -[path] -source = freezer_dr - -[html] -directory = term - -[report] -ignore_errors = True diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 5fcfa3f..0000000 --- a/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -__pycache__ -dist -build -.venv -.idea -.autogenerated -.coverage -cover/ -coverage.xml -*.sw? -.tox -*.egg* -*.py[co] -.DS_Store -*.log -.stestr/ -subunit.log -.eggs -AUTHORS -ChangeLog - -# Coverage data -.coverage.* - -# sphinx -doc/source/_static/*.sample -doc/source/api/* -doc/build/* - diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index 5406bd3..0000000 --- a/.pylintrc +++ /dev/null @@ -1,333 +0,0 @@ -[MASTER] - -# Specify a configuration file. -#rcfile= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Profiled execution. -profile=no - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS - -# Pickle collected data for later comparisons. -persistent=no - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# DEPRECATED -include-ids=no - -# DEPRECATED -symbols=no - - -[MESSAGES CONTROL] - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time. See also the "--disable" option for examples. -#enable= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -disable=W,C,R,E1120,import-error - - -[REPORTS] - -# Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html. You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". -files-output=no - -# Tells whether to display a full report or only the messages -reports=no - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Add a comment according to your evaluation note. This is used by the global -# evaluation report (RP0004). -comment=no - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - - -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=4 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - - -[TYPECHECK] - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus extisting member attributes cannot be deduced by static analysis -ignored-modules=distutils - -# List of classes names for which member attributes should not be checked -# (useful for classes with attributes dynamically set). -ignored-classes=SQLObject - -# When zope mode is activated, add a predefined set of Zope acquired attributes -# to generated-members. -zope=no - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E0201 when accessed. Python regular -# expressions are accepted. -generated-members=REQUEST,acl_users,aq_parent - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -[BASIC] - -# Required attributes for module, separated by a comma -required-attributes= - -# List of builtins function names that should not be used, separated by a comma -bad-functions=map,filter,apply,input,file - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Regular expression matching correct function names -function-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for function names -function-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for variable names -variable-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression matching correct attribute names -attr-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for attribute names -attr-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for argument names -argument-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression matching correct method names -method-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for method names -method-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=__.*__ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - - -[VARIABLES] - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_$|dummy - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[FORMAT] - -# Maximum number of characters on a single line. -max-line-length=80 - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - -# List of optional constructs for which whitespace checking is disabled -no-space-check=trailing-comma,dict-separator - -# Maximum number of lines in a module -max-module-lines=1000 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.* - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of statements in function / method body -max-statements=50 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - - -[CLASSES] - -# List of interface methods to ignore, separated by a comma. This is used for -# instance to not check methods defines in Zope's Interface base class. -ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,TERMIOS,Bastion,rexec - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/.stestr.conf b/.stestr.conf deleted file mode 100644 index 5228f20..0000000 --- a/.stestr.conf +++ /dev/null @@ -1,4 +0,0 @@ -[DEFAULT] -test_path=${OS_TEST_PATH:-./tests/unit} -top_dir=./ - diff --git a/.zuul.yaml b/.zuul.yaml deleted file mode 100644 index 1c108e7..0000000 --- a/.zuul.yaml +++ /dev/null @@ -1,10 +0,0 @@ -- project: - templates: - - openstack-python3-yoga-jobs - - publish-openstack-docs-pti - check: - jobs: - - openstack-tox-pylint - gate: - jobs: - - openstack-tox-pylint diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index c403e45..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,19 +0,0 @@ -The source repository for this project can be found at: - - https://opendev.org/openstack/freezer-dr - -Pull requests submitted through GitHub are not monitored. - -To start contributing to OpenStack, follow the steps in the contribution guide -to set up and use Gerrit: - - https://docs.openstack.org/contributors/code-and-documentation/quick-start.html - -Bugs should be filed on Storyboard,: - - https://storyboard.openstack.org/#!/project/openstack/freezer-dr - -For more specific information about contributing to this repository, see the -freezer-dr contributor guide: - - https://docs.openstack.org/freezer-dr/latest/contributor/contributing.html diff --git a/CREDITS.rst b/CREDITS.rst deleted file mode 100644 index 6e26f0a..0000000 --- a/CREDITS.rst +++ /dev/null @@ -1,30 +0,0 @@ -Authors -======= - -- Fabrizio Fresco -- Pierre-Arthur Mathieu -- Saad Zaher Saad -- Thibaut Lapierre - -Maintainers -=========== - -- Fabrizio Fresco -- Pierre-Arthur Mathieu -- Saad Zaher Saad -- Thibaut Lapierre - -Contributors -============ - -- Saad Zaher Saad -- Pierre-Arthur Mathieu -- Stefano Canepa - -Reviewers -========= - -- Fabrizio Fresco -- Pierre-Arthur Mathieu -- Saad Zaher Saad -- Thibaut Lapierre diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index c4ec01f..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,41 +0,0 @@ -Freezer DR Style Commandments -============================= - -- Step 1: Read the OpenStack Style Commandments - https://docs.openstack.org/hacking/latest/ -- Step 2: Read on - -Freezer DR Specific Commandments --------------------------------- - -Logging -------- - -Use the common logging module, and ensure you ``getLogger``:: - - from oslo_log import log - - LOG = log.getLogger(__name__) - - LOG.debug('Foobar') - - - -Properly Calling Callables --------------------------- - -Methods, functions and classes can specify optional parameters (with default -values) using Python's keyword arg syntax. When providing a value to such a -callable we prefer that the call also uses keyword arg syntax. For example:: - - def f(required, optional=None): - pass - - # GOOD - f(0, optional=True) - - # BAD - f(0, True) - -This gives us the flexibility to re-order arguments and more importantly -to add new required arguments. It's also more explicit and easier to read. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 5e81d2a..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2013, Rackspace (http://www.rackspace.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. diff --git a/README.rst b/README.rst index 55e422a..ca3eb0f 100644 --- a/README.rst +++ b/README.rst @@ -1,51 +1,13 @@ -======================== -Team and repository tags -======================== +This project is no longer maintained. -.. image:: https://governance.openstack.org/tc/badges/freezer-dr.svg - :target: https://governance.openstack.org/tc/reference/tags/index.html +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". -.. Change things from this point on - -========================= -Freezer Disaster Recovery -========================= - -freezer-dr, OpenStack Compute node High Available provides compute node high availability for OpenStack. -Simply freezer-dr monitors all compute nodes running in a cloud deployment and if there is any failure -in one of the compute nodes freezer-dr will fence this compute node then freezer-dr will try to evacuate all -running instances on this compute node, finally freezer-dr will notify all users who have workload/instances -running on this compute node as well as will notify the cloud administrators. - -freezer-dr has a pluggable architecture so it can be used with: - -1. Any monitoring system to monitor the compute nodes (currently we support only native OpenStack services status) -2. Any fencing driver (currently supports IPMI, libvirt, ...) -3. Any evacuation driver (currently supports evacuate api call, may be migrate ??) -4. Any notification system (currently supports email based notifications, ...) - -just by adding a simple plugin and adjust the configuration file to use this -plugin or in future a combination of plugins if required - -freezer-dr should run in the control plane, however the architecture supports different scenarios. -For running freezer-dr under high availability mode, it should run with active passive mode. - - ------------- -How it works ------------- - -Starting freezer-dr: - -1. freezer-dr Monitoring manager is going to load the required monitoring driver according to the configuration -2. freezer-dr will query the monitoring system to check if it considers any compute nodes to be down ? -3. if no, freezer-dr will exit displaying No failed nodes -4. if yes, freezer-dr will call the fencing manager to fence the failed compute node -5. Fencing manager will load the correct fencer according to the configuration -6. once the compute node is fenced and is powered off now we will start the evacuation process -7. freezer-dr will load the correct evacuation driver -8. freezer-dr will evacuate all instances to another computes -9. Once the evacuation process completed, freezer-dr will call the notification manager -10. The notification manager will load the correct driver based on the configurations -11. freezer-dr will start the notification process ... +For an alternative project, please see Masakari at +https://docs.openstack.org/masakari/. +For any further questions, please email +openstack-discuss@lists.openstack.org or join #openstack-freezer on +OFTC. diff --git a/bindep.txt b/bindep.txt deleted file mode 100644 index a6e42f4..0000000 --- a/bindep.txt +++ /dev/null @@ -1,6 +0,0 @@ -pkg-config [platform:dpkg platform:suse] -pkgconfig [platform:redhat] -libvirt-dev [platform:dpkg] -libvirt-devel [platform:rpm] -app-emulation/libvirt [platform:gentoo] -libvirt-python [platform:rpm] diff --git a/config-generator/freezer-dr.conf b/config-generator/freezer-dr.conf deleted file mode 100644 index 8ccefe1..0000000 --- a/config-generator/freezer-dr.conf +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -output_file = etc/freezer-dr.conf.sample -wrap_width = 79 -namespace = freezer-dr -namespace = oslo.log diff --git a/doc/freezer_dr_diagram.pdf b/doc/freezer_dr_diagram.pdf deleted file mode 100644 index c3e2c4d..0000000 Binary files a/doc/freezer_dr_diagram.pdf and /dev/null differ diff --git a/doc/freezer_dr_diagram.xml b/doc/freezer_dr_diagram.xml deleted file mode 100644 index c755376..0000000 --- a/doc/freezer_dr_diagram.xml +++ /dev/null @@ -1 +0,0 @@ -5V1fc6rIEv80qbr3ISkRQX1MzmZ3T9U9d09VtmrvPhIlyi6CFzF/9tOfHugfMANG1BkkxgeVcYChp//8uqenvbK/rF5/Sbz18ls898Or4WD+emX/dDUcWhNnTB+i5Y1bbNfKWxZJMOe2suEh+MfnxgG3boO5v5E6pnEcpsFabpzFUeTPUqnNS5L4Re72FIfyXdfeAncsGx5mXlhv/SOYp8u8dTJ0y/Zf/WCxxJ0td5r/8ujN/l4k8Tbi+10N7afslf+88nCt7EHte6JiEsd0GfFt9frFDwUlQaOcGj/v+LUYZOJHPJA9Jwx5XjbpG57Un9OD82GcpMt4EUdeeF+23mVP44tLDOhoma5C+mrRV7pr8vY/0X7j4PBP7vaXn6ZvPK/eNo2pqbz6f+J4zdfIxyMGsfOZuGkTb5MZ9xoxS3jJwi+moCAosaUfr3waDfVJ/NBLg2f58h6zx6LoV1KNvjDhmonI9372wi1f9GrohjSKu3nwLK4dBoso+8H9/1bM7F3oP6XlEX1b8Ke3IjLcRY8b8fE1Wm+p/ZYucS0e10+e/eTmjag9HMQJvX39/u2rYPnEn29wy0f6ofly/T/OHvPXeJNG3srPBFxwwrM323opHV/IA/629qOHlLQCT52fBl7YPH9ZC7Ffxkdya7WfIsCleAp5elkGqf+w9jJJeSHtLIvsTukiXkt96O9mScKvfAZU+5Q130upJ60Jq/FlRUe63HaK7ME8aNJfr0FaUV90JLTXPs3WSkGBSJKGYuWrKLsOVBZGU9FZ30nXCPO5IqUjhC+IMusURKkfeRE9Bh2RWW/Bf+Y5biRznG1N6hzHlk8/xzkmOA7fM54qWSznuKHEcu/SUGI5Zq8qy024nz6W41O/x8Qp5QwVpOYpGo14inCJfFB8Vkn92yTxxO3RbS06kHLceR9MvXKfcjLzK5ZTWzxjq9me0LUUQfkvWSWFAYhthSRU5jXxN8E/3mPWQUw5Pwf1du6unJ/EFNp3AAYzmkU/oQYhAQFhzlv+YRXM5xn/hN6jH94VSPJLHBIAELcGlmxkCebUmlwVKJkHKIHPJnm7HtxYrsvsxJS+tvPDYxkFsiufED89bYhXVXk8bNIsBuV6RPQgWTMtV9ZAVn1OS7k6hor8SBXW/0qSOIgyK7DbPhD5fm6DUpbx6nFLo+4AocBLA89NG+yF02AvrIEGgwFDVKHjG3myOnSI8KOoj+ggToA+ydyLujZJhY91tyFCB9Hi98zhuh5pgoADWTk4A9Y9FQrbDQQGbU6ibx3LsGP0sNym8/iFGLUHmMVhSwIKOXyFKg8OWBtqJxFft/+YhU6rYxZ2sPfqVszDWGZG11Z05OHwpXYJXfAFwQPlPtrgC7tiHxG+gGlPgC8nYhNmI63YBBNu2mE9SNq6Ri1ji5WhAdQCW2+SwKLTroiAOEt3rFP7hAAAwRhNFPWWM0ltPvbD0bEyFH0TC17dAUfZ5G/SLFQ42JDpvyaB7SUcBRJSqV+FAghx6IejfLPLhqMyf7vTDuEom9wOnU88ShU02axhu48tYjQS5nj2pFD+IF2K91x2+xBQlMH5BILWRUDRxox2yDDamWOXeZDpOkU4Tb95wCNVuO5hO5v5m83TNuvYPzMADxBMN+VHkDxCbqsyHSIVJzGdEY/QwLqJ3bCyCw1zBt1WX+v9RbgEgzDYiI9YAI4gIhRCETGBTmIRJcuVXbG00j99N0aouBN91/0CimO7EvPdTCkaww3f/SSgZxAO7PtcKYUk2MloHZJwFUWI4OrxIYnJWJmLHbq0rpQdORpaG8sO8H9wbEMZMO6jLbZRB7IfJrYBGThDbANLOnAwtEY3ECarzMmfl+dcKLLs1PMdRoacC7sez/ttm4o0IdkEAWnPZXPUu9SREcuBig+7sEOYo4a8rac4E5WSMEjVEj9c51wo0rIsZ/3amMeVXWVby9lBw30+PUGGDn6nNMZ3s3+K0ypttWtTWz7qHTP7oUXOkaPkFtZSqmxiyp+Hnmxgk90TrIeRvsVRkMYJkfNd/pDnvS3bXBR/jGU9AtGu8MfUFHsYCTe/g2atmwE5bxKanZB8HIpmpeRZttpVhDs2EyI4FESOEfYtFpalBbK9/bGsrwt0WmaWUo9cv2maOEQVuneOMZqKpryNxJ04RJ8vxfcxEANXCvkhgLEV/dGUwIq2k4hmbIW2N9rZdRXt3LDeYcp6I1Zmfn9DK4GFcEoC2za9QbvAYjQV3vvDC3IfsOPkmImSP4QE5apPxVwksQi3nUQFtnRdWnB6PDkeRT7lKRYcPNRHC674eC5vBdtpwZX+igWv9x+wBm1j8etnI/KJs1XPUt8KhaMVORzNFg4rX9NrP66yLWQMFW+AsvWo/McEHi5CsR0AD6eeT3HpwMNF2LUL4MF+4SVHQh2sWALYjVkQO4iEYkNxX4BdgyfmssI/A7Cre2JfvKyHFHkUG6j7kRsNmF6sR7L07IsDAyucRCytCTu78V8rPtLPMzusMzKisJqIlQX91hlLnz2RVFBYklR++O4lFaOR01Z6nbWiLGWPGzbTgLkkzKKk/hxFrTrQuzjMAsMGwUSqdAeYBXCpQw/FbZtIcaK+GysZocV2L80bOsYK5NzvvTaPS1e8GvSt6hfBvWKzXrm4RBlKQSWX2qNaJaJsBTGt+JyvxF6/HsCEmtGC69/FcjG2v14yoC/8TzhMDZFaU4De/QSpI67F5h4M3JDvYIq+FhL/teOw+lY/s7V+gNYkBJfpuS4AW3295lZWlKw+s23RojlYEStlqTg99LSmDYF2c6UzerX5DfHxKhthCdO4IxA//iWqlFHWlkgf5AosmTtORjjbLOGtg4KXIn+bJnF0nbdlZZFmSz+rILR8W1NdqGCTFYSSeotcsGdh1ak0WcaIRI5sy37yd5YXlkdFM0KFxHFLqojmJ3KVNExcTip5UrtlW0sO8iMAKpUYakiVP8LpoEOenGYmRqrJ+z6IH80JuMUvIoU09DabYNaSJm0ziqkkx8BRzDWuUaFKU1UDtJ0KqVF7CdAVluvQTYS1C+FYNzZHyFsZ8M5xqf15XHtWlrQm1E61bg46MTiF4kFVjYm8qu5DJxhN1bUJfX/9L8qgfgoW2yTDhHSPFZGjyIxNaXG11JTb1SMttPJPiRjBv89glC0QEfknwMJV9QahkIyyhpjKpB6BOlibtdglrSx4n8RzwCx7ea4bRaioL3Vxrq0aVJOh7ZYLpgfvy1DvoztFDrVgutvgcyxvNVUNxY72Myi0enTzwyo0eYtR4XV0otDqAO14hSYxXenoNmg0woUnsF1r+HcWlVaU7zxUpylbwIokfQN1P/QWfTOpdXigskU7n9ZpiBB/TK1D2ygUQ9wQ2zCmderh4cO1zjFg6aiN0d1okSHKKBSLzHrUyMicGkHt4t5rEbgMki+mvZxTW+7HaE7ZS2c1bYEqazg0VNdutfGt08I+lrxRzcaCdUXeEECWFJCSfHHUFBjz41pHVFvHArpRPzbSoIBC1WKz7atcKQWb1DpMmjwzG5tBlPvo8symdQfj4ko/2cpcjcbdbTaB/q3Q955kKEvjESrunmRPLP70oYC6vBBpAwVWFVUTlTTk28E3rFApogD6rg2u79DpYzMqAm+YgpaMqmKf4/41oU85j0XIRY7DnG1bVDGez45m1DqF2OvcAZopimycEc60DwWCnKj9h/QZVJBtiXcOgDbKfrlxyxo+e6HN2BS0UfLicB99Qec6/L08bINSgeCvcT3/zRS2KZJCemIytFuHZr4toH5Rq9VYgdvimT4AfFQtQ8OCpSn4aOGvBT45fhypnNkQazCGH2FuzhUma7/YUkTW5XD7+cBlw19vfU5wqW4jqWMlY+ASeyrOCS5br/iAnEiveid3WBO4VKrDT5EpeSq4nCKhSju4lNEw7qMNXCJactHgUtmvPwXY7ARc9inNzYB1aAcui38TNrE8/mHB5QTS1wW4LP4z77ODS3kha9JQINocuKxvsTjaOh+pAlqvpHazkjVC4YqigtaRK1njI4tIH2qRVc1m87r6rnGp/Sn09n5utouMpLYnqE+unqChMmBddVzgBjZZLxT/I6B/Axsdlv+Dn88HWZvlN9qiKnr8AA== \ No newline at end of file diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 8c1088d..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,263 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Freezer documentation build configuration file, created by -# sphinx-quickstart on Thu Feb 4 22:27:35 2016. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ['sphinxcontrib.apidoc', - 'sphinx.ext.viewcode', - 'openstackdocstheme'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Freezer' -copyright = u'2016, OpenStack' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Freezerdrdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'Freezerdr.tex', u'Freezer DR Documentation', - u'OpenStack', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'freezer-dr', u'Freezer DR Documentation', - [u'OpenStack'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'Freezer DR', u'Freezer Disaster Recovery Documentation', - u'OpenStack', 'Freezer Disaster Recovery', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} - -# -- sphinxcontrib.apidoc configuration -------------------------------------- - -apidoc_module_dir = '../../freezer_dr' -apidoc_output_dir = 'api' -apidoc_excluded_paths = [ - 'tests', -] diff --git a/doc/source/contributor/contributing.rst b/doc/source/contributor/contributing.rst deleted file mode 100644 index 190f029..0000000 --- a/doc/source/contributor/contributing.rst +++ /dev/null @@ -1,47 +0,0 @@ -============================ -So You Want to Contribute... -============================ -For general information on contributing to OpenStack, please check out the -`contributor guide `_ to get started. -It covers all the basics that are common to all OpenStack projects: the accounts -you need, the basics of interacting with our Gerrit review system, how we -communicate as a community, etc. -Below will cover the more project specific information you need to get started -with freezer-dr. - -Communication -~~~~~~~~~~~~~ -* IRC channel #openstack-freezer at OFTC -* Mailing list (prefix subjects with ``[freezer]`` for faster responses) - http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-discuss - -Contacting the Core Team -~~~~~~~~~~~~~~~~~~~~~~~~ -Please refer the `freezer-dr Core Team -`_ contacts. - -New Feature Planning -~~~~~~~~~~~~~~~~~~~~ -freezer-dr features are tracked on `Storyboard `_. - -Task Tracking -~~~~~~~~~~~~~ -We track our tasks in `Storyboard `_. -If you're looking for some smaller, easier work item to pick up and get started -on, search for the 'low-hanging-fruit' tag. - -Reporting a Bug -~~~~~~~~~~~~~~~ -You found an issue and want to make sure we are aware of it? You can do so on -`Storyboard `_. - -Getting Your Patch Merged -~~~~~~~~~~~~~~~~~~~~~~~~~ -All changes proposed to the freezer-dr project require one +2 votes -from freezer-dr core reviewers with approving patch by giving -``Workflow +1`` vote. - -Project Team Lead Duties -~~~~~~~~~~~~~~~~~~~~~~~~ -All common PTL duties are enumerated in the `PTL guide -`_. diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 0787706..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,32 +0,0 @@ -===================================================== -Welcome to Freezer's Disaster Recovery documentation! -===================================================== - -freezer-dr, OpenStack Compute node High Available provides compute node high -availability for OpenStack. Simply freezer-dr monitors all compute nodes running -in a cloud deployment and if there is any failure in one of the compute nodes -freezer-dr will fence this compute node then freezer-dr will try to evacuate -all running instances on this compute node, finally freezer-dr will notify all -users who have workload/instances running on this compute node as well as will -notify the cloud administrators. - -For Contributors -================ - -* If you are a new contributor to freezer-dr please refer: :doc:`contributor/contributing` - - .. toctree:: - :hidden: - - contributor/contributing - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`search` - -.. toctree:: - :maxdepth: 1 - - api/modules diff --git a/etc/freezer-dr.conf.sample b/etc/freezer-dr.conf.sample deleted file mode 100644 index a638f47..0000000 --- a/etc/freezer-dr.conf.sample +++ /dev/null @@ -1,270 +0,0 @@ -[DEFAULT] - -# -# From freezer-dr -# - -# Time to wait between different operations (integer value) -#wait = 30 - -# -# From oslo.log -# - -# If set to true, the logging level will be set to DEBUG instead of the default -# INFO level. (boolean value) -# Note: This option can be changed without restarting. -#debug = false - -# The name of a logging configuration file. This file is appended to any -# existing logging configuration files. For details about logging configuration -# files, see the Python logging module documentation. Note that when logging -# configuration files are used then all logging configuration is set in the -# configuration file and other logging configuration options are ignored (for -# example, logging_context_format_string). (string value) -# Note: This option can be changed without restarting. -# Deprecated group/name - [DEFAULT]/log_config -#log_config_append = - -# Defines the format string for %%(asctime)s in log records. Default: -# %(default)s . This option is ignored if log_config_append is set. (string -# value) -#log_date_format = %Y-%m-%d %H:%M:%S - -# (Optional) Name of log file to send logging output to. If no default is set, -# logging will go to stderr as defined by use_stderr. This option is ignored if -# log_config_append is set. (string value) -# Deprecated group/name - [DEFAULT]/logfile -#log_file = - -# (Optional) The base directory used for relative log_file paths. This option -# is ignored if log_config_append is set. (string value) -# Deprecated group/name - [DEFAULT]/logdir -#log_dir = - -# Uses logging handler designed to watch file system. When log file is moved or -# removed this handler will open a new log file with specified path -# instantaneously. It makes sense only if log_file option is specified and -# Linux platform is used. This option is ignored if log_config_append is set. -# (boolean value) -#watch_log_file = false - -# Use syslog for logging. Existing syslog format is DEPRECATED and will be -# changed later to honor RFC5424. This option is ignored if log_config_append -# is set. (boolean value) -#use_syslog = false - -# Enable journald for logging. If running in a systemd environment you may wish -# to enable journal support. Doing so will use the journal native protocol -# which includes structured metadata in addition to log messages.This option is -# ignored if log_config_append is set. (boolean value) -#use_journal = false - -# Syslog facility to receive log lines. This option is ignored if -# log_config_append is set. (string value) -#syslog_log_facility = LOG_USER - -# Log output to standard error. This option is ignored if log_config_append is -# set. (boolean value) -#use_stderr = false - -# Format string to use for log messages with context. (string value) -#logging_context_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s - -# Format string to use for log messages when context is undefined. (string -# value) -#logging_default_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s - -# Additional data to append to log message when logging level for the message -# is DEBUG. (string value) -#logging_debug_format_suffix = %(funcName)s %(pathname)s:%(lineno)d - -# Prefix each line of exception output with this format. (string value) -#logging_exception_prefix = %(asctime)s.%(msecs)03d %(process)d ERROR %(name)s %(instance)s - -# Defines the format string for %(user_identity)s that is used in -# logging_context_format_string. (string value) -#logging_user_identity_format = %(user)s %(tenant)s %(domain)s %(user_domain)s %(project_domain)s - -# List of package logging levels in logger=LEVEL pairs. This option is ignored -# if log_config_append is set. (list value) -#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,oslo_messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO - -# Enables or disables publication of error events. (boolean value) -#publish_errors = false - -# The format for an instance that is passed with the log message. (string -# value) -#instance_format = "[instance: %(uuid)s] " - -# The format for an instance UUID that is passed with the log message. (string -# value) -#instance_uuid_format = "[instance: %(uuid)s] " - -# Interval, number of seconds, of log rate limiting. (integer value) -#rate_limit_interval = 0 - -# Maximum number of logged messages per rate_limit_interval. (integer value) -#rate_limit_burst = 0 - -# Log level name used by rate limiting: CRITICAL, ERROR, INFO, WARNING, DEBUG -# or empty string. Logs with level greater or equal to rate_limit_except_level -# are not filtered. An empty string means that all levels are filtered. (string -# value) -#rate_limit_except_level = CRITICAL - -# Enables or disables fatal status of deprecations. (boolean value) -#fatal_deprecations = false - - -[evacuation] - -# -# From freezer-dr -# - -# Time in seconds to wait between retries to disable compute node or put it in -# maintenance mode. Default 10 seconds (string value) -#driver = freezer_dr.evacuators.drivers.default.standard.StandardEvacuator - -# Time in seconds to wait between retries to disable compute node or put it in -# maintenance mode. Default 10 seconds (integer value) -#wait = 10 - -# Number of retries to put node in maintenance mode before reporting failure to -# evacuate the node (integer value) -#retries = 1 - -# Set this option to True in case your compute nodes are running on a shared -# storage or False if not (boolean value) -#shared_storage = false - -# Dict contains kwargs to be passed to the evacuator driver. In case you have -# additional args needs to be passed to your evacuator please, list them as -# key0:value0, key1:value1, .... (dict value) -#options = - - -[fencer] - -# -# From freezer-dr -# - -# YAML File contains the required credentials for compute nodes (string value) -#credentials_file = - -# Number of retries to fence the each compute node. Must be at least 1 to try -# first the soft shutdown (integer value) -#retries = 1 - -# Time in seconds to wait between retries. Should be reasonable amount of time -# as different servers take different times to shut off (integer value) -#hold_period = 10 - -# Choose the best fencer driver i.e.(ipmi, libvirt, .. (string value) -#driver = freezer_dr.fencers.drivers.ipmi.driver.IpmiDriver - -# List of kwargs to customize the fencer operation. You fencer driver should -# support these options. Options should be in key:value format (dict value) -#options = - - -[keystone_authtoken] - -# -# From freezer-dr -# - -# OpenStack auth URI i.e. http://controller:5000 (string value) -#auth_uri = - -# OpenStack auth URL i.e. http://controller:35357/v3 (string value) -#auth_url = - -# OpenStack auth plugin i.e. ( password, token, ...) password is the only -# available plugin for the time being (string value) -#auth_plugin = - -# OpenStack username (string value) -#username = - -# OpenStack Password (string value) -#password = - -# OpenStack Project Name. (string value) -#project_name = - -# OpenStack domain Name. (string value) -#domain_name = - -# OpenStack Project Domain id, default is Default (string value) -#project_domain_id = - -# OpenStack user Domain id, default is Default (string value) -#user_domain_id = - -# OpenStack Project Domain name, default is Default (string value) -#project_domain_name = - -# OpenStack user Domain name, default is Default (string value) -#user_domain_name = - -# OpenStack Authentication arguments you can pass it here as Key:Value, -# Key1:Value1, ... (dict value) -#kwargs = - - -[monitoring] - -# -# From freezer-dr -# - -# Driver used to get a status updates of compute nodes (string value) -#driver = freezer_dr.monitors.drivers.default.driver.StandardDriver - -# configuration section name. This should contain your monitoring specific -# configuration options. (string value) -#backend_name = - - -[notifiers] - -# -# From freezer-dr -# - -# Notification driver to load it to notify users if something went wrong -# (string value) -#driver = freezer_dr.notifiers.drivers.default.default_email.StandardEmail - -# Endpoint URL for the notification system. If you the driver you are using -# doesnot require any URL just comment it or use none (string value) -#endpoint = localhost - -# Username to authenticate against the notification system. If the driver you -# are using doesnot require any authentications comment or use None (string -# value) -#username = - -# Password to authenticate against the notification system. If the driver you -# are using doesnot require any authentications comment or use None (string -# value) -#password = - -# Path to Jinja2 templates directory that contains message templates (string -# value) -#templates-dir = /etc/freezer/templates - -# Key:Value Kwargs to pass it to the notification driver, if you want to pass -# any special arguments for your driver. (dict value) -#options = - -# List of emails to sent them notification if something went wrong and Freezer -# DR wasnot able to send an email to the tenant admin (list value) -#notify-list = - -# The sender address, it can be email address if we used default email driver, -# or phone number if we use sms gateway for example. (string value) -#notify-from = diff --git a/etc/servers.yml b/etc/servers.yml deleted file mode 100644 index 84f90ab..0000000 --- a/etc/servers.yml +++ /dev/null @@ -1,62 +0,0 @@ -# -# (c) Copyright 2015 Hewlett Packard Enterprise Development Company LP -# -# 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. -# ---- - - servers: - - - id: deployer - ip-addr: 192.168.10.254 - hostname: padawan-cp1-c0-m1-mgmt - fencer-ip: 192.168.9.2 - fencer-password: password - fencer-user: admin - - - id: ccn-0001 - ip-addr: 192.168.10.3 - hostname: padawan-cp1-c1-m1-mgmt - fencer-ip: 192.168.9.3 - fencer-password: password - fencer-user: admin - - - id: ccn-0002 - ip-addr: 192.168.10.4 - hostname: padawan-cp1-c1-m2-mgmt - fencer-ip: 192.168.9.4 - fencer-password: password - fencer-user: admin - - - id: ccn-0003 - ip-addr: 192.168.10.5 - hostname: padawan-cp1-c1-m3-mgmt - fencer-ip: 192.168.9.5 - fencer-password: password - fencer-user: admin - - - id: COMPUTE-0001 - ip-addr: 192.168.10.6 - hostname: padawan-ccp-comp0001-mgmt - domain-name: padawan-vagrant_cpn-0001 # used for libvirt driver only ! - fencer-ip: 192.168.9.6 - fencer-password: password - fencer-user: admin - - - id: COMPUTE-0002 - ip-addr: 192.168.10.7 - hostname: padawan-ccp-comp0002-mgmt - domain-name: padawan-vagrant_cpn-0002 # name of VM in kvm - fencer-ip: 192.168.9.7 - fencer-password: password - fencer-user: admin \ No newline at end of file diff --git a/etc/templates/error.jinja b/etc/templates/error.jinja deleted file mode 100644 index 6adb789..0000000 --- a/etc/templates/error.jinja +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - {{ title }} - - - - -
-

Dear Administrators,
- A compute node failed and freezer-dr DID NOT successfully evacuate. - Please, find the following details about the host:
- Host: {{ host }}
-

- Tenants: - {% for tenant in tenants %} - {{ tenant.get('id') }}
- {% endfor %} -

-
-

- Instances:
- - - - - - {% for instance in instances %} - - - - - {% endfor %} -
- Instance Name - - IP -
{{ instance.get('name') }} - {% for key, value in instance.get('addresses').iteritems() %} - {{ key }} : - {{ value[0].get('addr', 'No IP') }} - {% endfor %} -
-

-

- Host INFO: - - {% for key, value in hypervisor.iteritems() %} - - - - - {% endfor %} -
{{ key }} {{ value }}
-

- - TimeStamp: {{ evacuation_time }}
-

-
-

- Thanks for using Freezer-DR ! -

-
- - - diff --git a/etc/templates/original.jinja b/etc/templates/original.jinja deleted file mode 100644 index dd6e7e5..0000000 --- a/etc/templates/original.jinja +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - {{ title }} - - - - -
-

Dear {{ name }},
- One of our compute nodes failed due to some technical problem. Your - instances (listed below) running in tenant {{ tenant }} is being evacuated to another compute host.
- Instances:
- - - - - - {% for instance in instances%} - - - - - {% endfor %} -
- Instance Name - - IP -
{{ instance.get('name') }} - {% for key, value in instance.get('addresses').iteritems() %} - {{ key }} : - {{ value[0].get('addr', 'No IP') }} - {% endfor %} -
- TimeStamp: {{ evacuation_time }}
-

-
-

- Thanks for using Freezer-DR ! -

-
- - - diff --git a/etc/templates/success.jinja b/etc/templates/success.jinja deleted file mode 100644 index 248bb21..0000000 --- a/etc/templates/success.jinja +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - {{ title }} - - - - -
-

Dear Administrators,
- A compute node failed and freezer-dr successfully evacuated these instances running - on this compute node to another node. Please, find the following details - about the evacuated host:
- Host: {{ host }}
-

- Tenants: - {% for tenant in tenants %} - {{ tenant.get('id') }}
- {% endfor %} -

-
-

- Instances:
- - - - - - {% for instance in instances %} - - - - - {% endfor %} -
- Instance Name - - IP -
{{ instance.get('name') }} - {% for key, value in instance.get('addresses').iteritems() %} - {{ key }} : - {{ value[0].get('addr', 'No IP') }} - {% endfor %} -
-

-

- Host INFO: - - {% for key, value in hypervisor.iteritems() %} - - - - - {% endfor %} -
{{ key }} {{ value }}
-

- - TimeStamp: {{ evacuation_time }}
-

-
-

- Thanks for using Freezer-DR ! -

-
- - - diff --git a/etc/templates/user_error.jinja b/etc/templates/user_error.jinja deleted file mode 100644 index 79ca132..0000000 --- a/etc/templates/user_error.jinja +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - {{ title }} - - - - -
-

Dear {{ name }},
- One of our compute nodes failed due to some technical problem. Your - instances (listed below) are running in tenant {{ tenant }} Failed to Evacuate
- Instances:
- - - - - - {% for instance in instances%} - - - - - {% endfor %} -
- Instance Name - - IP -
{{ instance.get('name') }} - {% for key, value in instance.get('addresses').iteritems() %} - {{ key }} : - {{ value[0].get('addr', 'No IP') }} - {% endfor %} -
- TimeStamp: {{ evacuation_time }}
-

-
-

- Thanks for using freezer-dr ! -

-
- - - \ No newline at end of file diff --git a/etc/templates/user_success.jinja b/etc/templates/user_success.jinja deleted file mode 100644 index 426525d..0000000 --- a/etc/templates/user_success.jinja +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - {{ title }} - - - - -
-

Dear {{ name }},
- One of our compute nodes failed due to some technical problem. Your - instances (listed below) running in tenant {{ tenant }} Evacuated to another compute host
- Instances:
- - - - - - {% for instance in instances%} - - - - - {% endfor %} -
- Instance Name - - IP -
{{ instance.get('name') }} - {% for key, value in instance.get('addresses').iteritems() %} - {{ key }} : - {{ value[0].get('addr', 'No IP') }} - {% endfor %} -
- TimeStamp: {{ evacuation_time }}
-

-
-

- Thanks for using Freezer-DR ! -

-
- - - \ No newline at end of file diff --git a/freezer_dr/__init__.py b/freezer_dr/__init__.py deleted file mode 100644 index 8ea7402..0000000 --- a/freezer_dr/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Freezer-DR Versions - -import pbr.version - - -__version__ = pbr.version.VersionInfo('freezer-dr').version_string() diff --git a/freezer_dr/common/__init__.py b/freezer_dr/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/common/config.py b/freezer_dr/common/config.py deleted file mode 100644 index 383dd56..0000000 --- a/freezer_dr/common/config.py +++ /dev/null @@ -1,347 +0,0 @@ -"""Manage all configuration the OpenStack way.""" - -# (c) Copyright 2016 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import sys - -from oslo_config import cfg -from oslo_log import log - -from freezer_dr import __version__ as FREEZER_DR_VERSION -from freezer_dr.common.utils import env - - -CONF = cfg.CONF - - -_MONITORS = [ - cfg.StrOpt('driver', - default='freezer_dr.monitors.drivers.default.driver.' - 'StandardDriver', - help='Driver used to get a status updates of compute nodes'), - cfg.StrOpt('backend_name', - help='configuration section name. This should contain your ' - 'monitoring specific configuration options.') -] - -_COMMON = [ - cfg.IntOpt('wait', - default=30, - help='Time to wait between different operations') -] - -_FENCER = [ - cfg.StrOpt('credentials-file', - help='YAML File contains the required credentials for compute ' - 'nodes'), - cfg.IntOpt('retries', - default=1, - help='Number of retries to fence the each compute node. Must be' - ' at least 1 to try first the soft shutdown'), - cfg.IntOpt('hold-period', - default=10, - help='Time in seconds to wait between retries. Should be ' - 'reasonable amount of time as different servers take ' - 'different times to shut off'), - cfg.StrOpt('driver', - default='freezer_dr.fencers.drivers.ipmi.driver.IpmiDriver', - help='Choose the best fencer driver i.e.(ipmi, libvirt, ..'), - cfg.DictOpt('options', - default={}, - help='List of kwargs to customize the fencer operation. You ' - 'fencer driver should support these options. Options ' - 'should be in key:value format') -] - -_KEYSTONE_AUTH_TOKEN = [ - cfg.StrOpt('auth_uri', - help='OpenStack auth URI i.e. http://controller:5000', - dest='auth_uri'), - cfg.StrOpt('auth_url', - help='OpenStack auth URL i.e. http://controller:35357/v3', - dest='auth_url'), - cfg.StrOpt('auth_plugin', - help='OpenStack auth plugin i.e. ( password, token, ...) ' - 'password is the only available plugin for the time ' - 'being', - dest='auth_plugin'), - cfg.StrOpt('username', - help='OpenStack username', - dest='username'), - cfg.StrOpt('password', - help='OpenStack Password', - dest='password'), - cfg.StrOpt('project_name', - help='OpenStack Project Name.', - dest='project_name'), - cfg.StrOpt('domain_name', - help='OpenStack domain Name.', - dest='domain_name'), - cfg.StrOpt('project_domain_id', - help='OpenStack Project Domain id, default is Default', - dest='project_domain_id'), - cfg.StrOpt('user_domain_id', - help='OpenStack user Domain id, default is Default', - dest='user_domain_id'), - cfg.StrOpt('project_domain_name', - help='OpenStack Project Domain name, default is Default', - dest='project_domain_name'), - cfg.StrOpt('user_domain_name', - help='OpenStack user Domain name, default is Default', - dest='user_domain_name'), - cfg.DictOpt('kwargs', - help='OpenStack Authentication arguments you can pass it here' - ' as Key:Value, Key1:Value1, ... ', - dest='kwargs', - default={}) -] - -_EVACUATION = [ - cfg.StrOpt('driver', - default='freezer_dr.evacuators.drivers.default.standard.' - 'StandardEvacuator', - help='Time in seconds to wait between retries to disable ' - 'compute node or put it in maintenance mode. Default ' - '10 seconds', - dest='driver'), - cfg.IntOpt('wait', - default=10, - help='Time in seconds to wait between retries to disable ' - 'compute node or put it in maintenance mode. Default ' - '10 seconds', - dest='wait'), - cfg.IntOpt('retries', - default=1, - help='Number of retries to put node in maintenance mode before' - ' reporting failure to evacuate the node', - dest='retries'), - cfg.BoolOpt('shared-storage', - default=False, - help='Set this option to True in case your compute nodes are ' - 'running on a shared storage or False if not', - dest='shared_storage'), - cfg.DictOpt('options', - default={}, - help='Dict contains kwargs to be passed to the evacuator ' - 'driver. In case you have additional args needs to be ' - 'passed to your evacuator please, list them as ' - 'key0:value0, key1:value1, ...', - dest='options') -] - -_NOTIFIERS = [ - cfg.StrOpt('driver', - default='freezer_dr.notifiers.drivers.default.default_email.' - 'StandardEmail', - dest='driver', - help='Notification driver to load it to notify users ' - 'if something went wrong. There are two supported drivers' - ': freezer_dr.notifiers.drivers.default.default_email.' - 'StandardEmail and freezer_dr.notifiers.drivers.default.' - 'slack.slack.SlackNotifier'), - cfg.StrOpt('endpoint', - default='localhost', - dest='endpoint', - help='Endpoint URL for the notification system. If you the ' - 'driver you are using doesnot require any URL just comment' - ' it or use none'), - cfg.StrOpt('username', - default=None, - dest='username', - help='Username to authenticate against the notification system.' - ' If the driver you are using doesnot require any ' - 'authentications comment or use None'), - cfg.StrOpt('password', - default=None, - dest='password', - help='Password to authenticate against the notification system. ' - 'If the driver you are using doesnot require any ' - 'authentications comment or use None'), - cfg.StrOpt('templates-dir', - dest='templates-dir', - default='/etc/freezer/templates', - help='Path to Jinja2 templates directory that contains ' - 'message templates'), - cfg.DictOpt('options', - default={}, - dest='options', - help='Key:Value Kwargs to pass it to the notification driver, ' - 'if you want to pass any special arguments for your ' - 'driver. If you want to use the SlackNotifier driver, ' - 'set as: options = slack_timeout:512,' - 'slack_ca_certs:/ca.crt,slack_insecured:True'), - cfg.ListOpt('notify-list', - default=[], - dest='notify-list', - help='List of emails to sent them notification if something ' - 'went wrong and Freezer DR wasnot able to send an email ' - 'to the tenant admin'), - cfg.StrOpt('notify-from', - dest='notify-from', - help='The sender address, it can be email address if we used ' - 'default email driver, or phone number if we use sms ' - 'gateway for example.') -] - - -def build_os_options(): - """Build oslo options related to OpenStack environment.""" - osclient_opts = [ - cfg.StrOpt('os-username', - default=env('OS_USERNAME'), - help='Name used for authentication with the OpenStack ' - 'Identity service. Defaults to env[OS_USERNAME].', - dest='os_username'), - cfg.StrOpt('os-password', - default=env('OS_PASSWORD'), - help='Password used for authentication with the OpenStack ' - 'Identity service. Defaults to env[OS_PASSWORD].', - dest='os_password'), - cfg.StrOpt('os-project-name', - default=env('OS_PROJECT_NAME'), - help='Project name to scope to. Defaults to ' - 'env[OS_PROJECT_NAME].', - dest='os_project_name'), - cfg.StrOpt('os-project-domain-name', - default=env('OS_PROJECT_DOMAIN_NAME'), - help='Domain name containing project. Defaults to ' - 'env[OS_PROJECT_DOMAIN_NAME].', - dest='os_project_domain_name'), - cfg.StrOpt('os-user-domain-name', - default=env('OS_USER_DOMAIN_NAME'), - help='User\'s domain name. Defaults to ' - 'env[OS_USER_DOMAIN_NAME].', - dest='os_user_domain_name'), - cfg.StrOpt('os-auth-url', - default=env('OS_AUTH_URL'), - help='Specify the Identity endpoint to use for ' - 'authentication. Defaults to env[OS_AUTH_URL].', - dest='os_auth_url'), - cfg.StrOpt('os-backup-url', - default=env('OS_BACKUP_URL'), - help='Specify the Freezer backup service endpoint to use. ' - 'Defaults to env[OS_BACKUP_URL].', - dest='os_backup_url'), - cfg.StrOpt('os-region-name', - default=env('OS_REGION_NAME'), - help='Specify the region to use. Defaults to ' - 'env[OS_REGION_NAME].', - dest='os_region_name'), - cfg.StrOpt('os-token', - default=env('OS_TOKEN'), - help='Specify an existing token to use instead of ' - 'retrieving one via authentication (e.g. ' - 'with username & password). Defaults to ' - 'env[OS_TOKEN].', - dest='os_token'), - cfg.StrOpt('os-identity-api-version', - default=env('OS_IDENTITY_API_VERSION'), - help='Identity API version: 2.0 or 3. ' - 'Defaults to env[OS_IDENTITY_API_VERSION]', - dest='os_identity_api_version'), - cfg.StrOpt('os-endpoint-type', - choices=['public', 'publicURL', 'internal', 'internalURL', - 'admin', 'adminURL'], - default=env('OS_ENDPOINT_TYPE') or 'public', - help='Endpoint type to select. Valid endpoint types: ' - '"public" or "publicURL", "internal" or "internalURL"' - ', "admin" or "adminURL". Defaults to ' - 'env[OS_ENDPOINT_TYPE] or "public"', - dest='os_endpoint_type'), - ] - - return osclient_opts - - -def configure(): - """Register configuration.""" - CONF.register_cli_opts(build_os_options()) - CONF.register_opts(_COMMON) - monitors_grp = cfg.OptGroup('monitoring', - title='Monitoring', - help='Monitoring Driver/plugin to be used to ' - 'monitor compute nodes') - CONF.register_group(monitors_grp) - CONF.register_opts(_MONITORS, group='monitoring') - - fencers_grp = cfg.OptGroup('fencer', - title='fencer Options', - help='fencer Driver/plugin to be used to ' - 'fence compute nodes') - CONF.register_group(fencers_grp) - CONF.register_opts(_FENCER, group='fencer') - - # Evacuation Section :) - evacuators_grp = cfg.OptGroup('evacuation', - title='Evacuation Options', - help='Evacuation Driver/plugin opts to be ' - 'used to Evacuate compute nodes') - CONF.register_group(evacuators_grp) - CONF.register_opts(_EVACUATION, group='evacuation') - - # Notification Section :) - notifiers_grp = cfg.OptGroup('notifiers', - title='Notification Options', - help='Notification Driver/plugin opts to be ' - 'used to Notify admins/users if failure' - ' happens') - CONF.register_group(notifiers_grp) - CONF.register_opts(_NOTIFIERS, group='notifiers') - - # Keystone Auth - keystone_grp = cfg.OptGroup('keystone_authtoken', - title='Keystone Auth Options', - help='OpenStack Credentials to call the nova ' - 'APIs to evacuate ') - CONF.register_group(keystone_grp) - CONF.register_opts(_KEYSTONE_AUTH_TOKEN, group='keystone_authtoken') - - default_conf = cfg.find_config_files('freezer', 'freezer-dr', '.conf') - log.register_options(CONF) - - CONF(args=sys.argv[1:], - project='freezer', - default_config_files=default_conf, - version=FREEZER_DR_VERSION) - - -def setup_logging(): - """Set some oslo log defaults.""" - _DEFAULT_LOG_LEVELS = ['amqp=WARN', 'amqplib=WARN', 'boto=WARN', - 'qpid=WARN', 'stevedore=WARN', 'oslo_log=INFO', - 'iso8601=WARN', - 'requests.packages.urllib3.connectionpool=WARN', - 'urllib3.connectionpool=WARN', 'websocket=WARN', - 'keystonemiddleware=WARN', 'freezer-dr=INFO'] - - _DEFAULT_LOGGING_CONTEXT_FORMAT = ( - '%(asctime)s.%(msecs)03d %(process)d ' - '%(levelname)s %(name)s [%(request_id)s ' - '%(user_identity)s] %(instance)s' - '%(message)s') - log.set_defaults(_DEFAULT_LOGGING_CONTEXT_FORMAT, _DEFAULT_LOG_LEVELS) - log.setup(CONF, 'freezer-dr', version=FREEZER_DR_VERSION) - - -def list_opts(): - _OPTS = { - None: _COMMON, - 'monitoring': _MONITORS, - 'keystone_authtoken': _KEYSTONE_AUTH_TOKEN, - 'fencer': _FENCER, - 'evacuation': _EVACUATION, - 'notifiers': _NOTIFIERS - } - - return _OPTS.items() diff --git a/freezer_dr/common/daemon.py b/freezer_dr/common/daemon.py deleted file mode 100644 index d0bcf13..0000000 --- a/freezer_dr/common/daemon.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python -"""Generic deamon.""" -# (c) Copyright 2016 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -import atexit -import logging as log -import os -import sys -import time - -from signal import SIGTERM - - -class Daemon(object): - - """A generic daemon class. - - Usage: subclass the Daemon class and override the run() method - """ - - def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', - stderr='/dev/null'): - """Instantiantion.""" - self.stdin = stdin - self.stdout = stdout - self.stderr = stderr - self.pidfile = pidfile - - def daemonize(self): - """Do the UNIX double-fork magic. - - See Stevens' "Advanced Programming in the UNIX Environment" for - details (ISBN 0201563177) - http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 - """ - try: - pid = os.fork() - if pid > 0: - # exit first parent - sys.exit(0) - except OSError as e: - sys.stderr.write("fork #1 failed: %d (%s)\n" % - (e.errno, e.strerror)) - log.error(e) - sys.exit(1) - - # decouple from parent environment - os.chdir("/") - os.setsid() - os.umask(0) - - # do second fork - try: - pid = os.fork() - if pid > 0: - # exit from second parent - sys.exit(0) - except OSError as e: - sys.stderr.write("fork #2 failed: %d (%s)\n" - % (e.errno, e.strerror)) - log.error(e) - sys.exit(1) - - # redirect standard file descriptors - sys.stdout.flush() - sys.stderr.flush() - si = open(self.stdin, 'r') - so = open(self.stdout, 'a+') - se = open(self.stderr, 'a+', 0) - os.dup2(si.fileno(), sys.stdin.fileno()) - os.dup2(so.fileno(), sys.stdout.fileno()) - os.dup2(se.fileno(), sys.stderr.fileno()) - - # write pidfile - atexit.register(self.delpid) - - pid = str(os.getpid()) - f = open(self.pidfile, 'w+') - f.write("%s\n" % pid) - f.close() - - def delpid(self): - """Delete PID file.""" - os.remove(self.pidfile) - - def start(self): - """Start the daemon.""" - log.error("Test") - # Check for a pidfile to see if the daemon already runs - try: - pf = open(self.pidfile, 'r') - pid = int(pf.read().strip()) - pf.close() - except IOError: - pid = None - - if pid: - message = "pidfile %s already exist. Daemon" \ - " already running?\n" - sys.stderr.write(message % self.pidfile) - sys.exit(1) - - # Start the daemon - self.daemonize() - self.run() - - # @todo needs some enhancement like check /proc/%pid/status if it's - # really running or not ! may be it's killed by external process - # the PID won't be updated ! - def status(self): - """Check daemon status.""" - try: - pf = open(self.pidfile, 'r') - pid = int(pf.read().strip()) - pf.close() - except IOError: - pid = None - - if pid: - message = "pidfile %s already exist. Daemon already " \ - "running. PID: %d \n" - sys.stdout.write(message % (self.pidfile, pid)) - sys.exit(0) - else: - message = "Service not running!\n" - sys.stdout.write(message) - sys.exit(0) - - def stop(self): - """Stop the daemon.""" - # Get the pid from the pidfile - try: - pf = open(self.pidfile, 'r') - pid = int(pf.read().strip()) - pf.close() - except IOError: - pid = None - - if not pid: - message = "pidfile %s does not exist." \ - " Daemon not running?\n" - sys.stderr.write(message % self.pidfile) - return # not an error in a restart - - # Try killing the daemon process - try: - while 1: - os.kill(pid, SIGTERM) - time.sleep(0.1) - except OSError as err: - err = str(err) - if err.find("No such process") > 0: - if os.path.exists(self.pidfile): - os.remove(self.pidfile) - else: - print(str(err)) - sys.exit(1) - - def restart(self): - """Restart the daemon.""" - self.stop() - self.start() - - def run(self): - """You should override this method when you subclass Daemon. - - It will be called after the process has been - daemonized by start() or restart(). - """ diff --git a/freezer_dr/common/osclient.py b/freezer_dr/common/osclient.py deleted file mode 100644 index 38efe22..0000000 --- a/freezer_dr/common/osclient.py +++ /dev/null @@ -1,311 +0,0 @@ -"""OpenStack client class.""" -# (c) Copyright 2016 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from keystoneclient import session - -from keystoneclient.auth.identity import v3 - -from keystoneclient import client as keystoneclient - -from neutronclient.v2_0 import client as neutronclient - -from novaclient import client as novaclient - -from oslo_log import log - - -LOG = log.getLogger(__name__) - - -class OSClient: - """Provide OpenStack credentials to initalize the connection.""" - - def __init__(self, authurl, authmethod='password', ** kwargs): - """Initialize the all class vars. - - :param authmethod: string authmethod should be password or token but - currently we support only password ! - :param kwargs: username, user_id, project_name, project_id, - default_domain_id, - """ - self.authmethod = authmethod - self.authurl = authurl - self.auth_session = None - self.endpoint_type = 'internalURL' - self.interface = 'internal' - self.verify = True - self.insecure = kwargs.pop('insecure', False) - if self.insecure: - self.verify = not bool(self.insecure) - - if authmethod == 'password': - if 'endpoint_type' in kwargs: - self.endpoint_type = kwargs.pop('endpoint_type', 'internalURL') - if 'interface' in kwargs: - self.interface = kwargs.pop('interface', 'internal') - self.kwargs = kwargs - # self.username = kwargs.get('username', None) - # self.password = kwargs.get('password') - # self.project_name = kwargs.get('project_name', None) - # self.project_id = kwargs.get('project_id', None) - # self.user_id = kwargs.get('user_id', None) - # self.user_domain_id = kwargs.get('user_domain_id', None) - # self.user_domain_name = kwargs.get('user_domain_name', None) - # self.project_domain_name = - # kwargs.get('project_domain_name', None) - # self.endpoint_type = kwargs.get('endpoint_type', 'internalURL') - else: - print("The available authmethod is password for the time being") - print("Please, provide a password credential.") - - self.auth() - - def auth(self): - """Create a session.""" - auth = v3.Password(auth_url=self.authurl, reauthenticate=True, - **self.kwargs) - self.auth_session = session.Session(auth=auth, verify=self.verify) - - def get_novaclient(self): - if not hasattr(self, 'nova'): - self.auth() - self.nova = novaclient.Client('2', session=self.auth_session, - endpoint_type=self.endpoint_type, - insecure=self.insecure) - return self.nova - - def get_neutronclient(self): - if not hasattr(self, 'neutron'): - self.auth() - self.neutron = neutronclient.Client( - session=self.auth_session, - endpoint_type=self.endpoint_type, - insecure=self.insecure - ) - return self.neutron - - def novacomputes(self): - nova = self.get_novaclient() - services = nova.services.list() - compute_nodes = [] - compute_hosts = [] - for service in services: - service = service.to_dict() - if service.get('binary') == 'nova-compute': - compute_nodes.append(service) - compute_hosts.append(service.get('host')) - self.compute_hosts = compute_hosts - return compute_nodes - - def novahypervisors(self): - nova = self.get_novaclient() - hypervisors = nova.hypervisors.list() - nova_hypervisors = [] - - for hypervisor in hypervisors: - nova_hypervisors.append(hypervisor.to_dict()) - return nova_hypervisors - - def neutronagents(self, hosts=[]): - if not hosts: - hosts = self.compute_hosts - neutron = self.get_neutronclient() - agents = neutron.list_agents() - neutron_agents = [] - for agent in agents.get('agents'): - if agent.get('host') in hosts and agent.get('binary') == \ - 'neutron-openvswitch-agent': - neutron_agents.append(agent) - - return neutron_agents - - def evacuate(self, nodes, shared_storage=False): - """ - Will get the hypervisors and list all running VMs on it and then start - Evacuating one by one ... - :param nodes: List of nodes to be evacuated ! - :param shared_storage: Boolean, True if your compute nodes are running - under shared storage and False otherwise - :return: List of nodes with VMs that were running on that node - """ - nova = self.get_novaclient() - evacuated_nodes = [] - for node in nodes: - hypervisors = nova.hypervisors.search(node.get('host'), True) - for hypervisor in hypervisors: - if not hasattr(hypervisor, 'servers'): - break - for server in hypervisor.servers: - try: - nova.servers.evacuate(server.get('uuid'), - on_shared_storage=shared_storage) - except Exception as e: - LOG.error(e) - host = {'host': node.get( - 'host'), 'servers': hypervisor.servers} - evacuated_nodes.append(host) - return evacuated_nodes - - def set_in_maintenance(self, nodes): - """Set compute nodes in maintenance mode.""" - nova = self.get_novaclient() - for node in nodes: - output = [] - host = nova.hosts.get(node)[0] - values = {"maintenance_mode": "enable"} - try: - output.append(host.update(values)) - except Exception as e: - LOG.error(e) - return output - - def get_session(self): - """Get the authentication section.""" - auth_session = session.Session(auth=self.auth_session.auth, - verify=self.verify) - return auth_session - - def get_node_status(self, node): - """ - Check the node nova-service status and if it's disabled or not. - :param node: dict contains node info - :return: True or False. True => node disabled, False => node is enabled - or unknow status ! - """ - nova = self.get_novaclient() - try: - node_service = nova.services.find(host=node.get('host')) - del nova - except Exception as e: - LOG.error(e) - return False - - if not node_service: - return False - node = node_service.to_dict() - if node.get('status') == 'disabled': - return True - return False - - def disable_node(self, node): - """Disable nova on the failing node.""" - nova = self.get_novaclient() - try: - node_service = nova.services.find(host=node.get('host')) - except Exception as e: - LOG.error(e) - return False - - if not node_service: - return False - node = node_service.to_dict() - del node_service - try: - nova.services.disable_log_reason( - host=node.get('host'), - binary=node.get('binary'), - reason='Host failed and needs to be evacuated.' - ) - del nova - LOG.info('Compute host: %s has been disabled to be evacuated. ' - 'Host details: %s' % (node.get('host'), str(node))) - except Exception as e: - LOG.error(e) - return False - return True - - def get_hypervisor_instances(self, node): - """Get instances from an hypervisor.""" - nova = self.get_novaclient() - hypervisors = nova.hypervisors.search(node.get('host'), True) - if not hypervisors: - return [] - return hypervisors[0].servers - - def get_hypervisor(self, node): - """Get an instance of the hypervisor. - - :param node: dict contains host index - :return: Hypervisor - """ - nova = self.get_novaclient() - hypervisors = nova.hypervisors.search(node.get('host'), True) - if not hypervisors: - return None - return hypervisors[0] - - def get_instances_list(self, node): - """Get instances running on a node for all tenants.""" - nova = self.get_novaclient() - servers = nova.servers.list(detailed=True, - search_opts={'host': node.get('host'), - 'all_tenants': True}) - servers_data = [] - for server in servers: - servers_data.append(server.to_dict()) - - return servers_data - - def get_affected_tenants(self, node): - return self.get_instances_list(node) - - def list_tenants(self): - """List tenants.""" - auth_session = session.Session(auth=self.auth_session.auth) - keystone = keystoneclient.Client(session=auth_session, - endpoint_type=self.endpoint_type) - projects = keystone.projects.list() - - projects_data = [] - for project in projects: - projects_data.append(project.to_dict()) - - return projects_data - - def users_on_tenant(self, tenant): - """List user per project.""" - auth_session = session.Session(auth=self.auth_session.auth, - verify=self.verify) - keystone = keystoneclient.Client(session=auth_session, - endpoint_type=self.endpoint_type, - interface='internal', - insecure=self.insecure) - users = [] - try: - users = keystone.users.list(default_project=tenant) - except Exception as e: - print(e) - users_list = [] - for user in users: - users_list.append(user.to_dict()) - - return users_list - - def get_hypervisors_stats(self): - """Get stats for all hypervisors.""" - nova = self.get_novaclient() - stats = nova.hypervisor_stats.statistics() - return stats.to_dict() - - def get_hypervisor_details(self, node): - """Get details about hypervisor running on the provided node.""" - nova = self.get_novaclient() - hypervisors = nova.hypervisors.list(detailed=True) - for hypervisor in hypervisors: - hypervisor = hypervisor.to_dict() - if hypervisor.get('hypervisor_hostname') == node.get('host'): - return hypervisor - - return None diff --git a/freezer_dr/common/utils.py b/freezer_dr/common/utils.py deleted file mode 100644 index abe69b6..0000000 --- a/freezer_dr/common/utils.py +++ /dev/null @@ -1,97 +0,0 @@ -"""Utility functions shared from all modules into the project.""" -# (c) Copyright 2016 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import os - -import jinja2 - -from oslo_config import cfg -from oslo_log import log - -from freezer_dr.common.osclient import OSClient - - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -def env(*env_vars, **kwargs): - """Get all environment variables.""" - for variable in env_vars: - value = os.environ.get(variable, None) - if value: - return value - return kwargs.get('default', '') - - -def get_os_client(): - """Return the OpenStack client. - - Loads credentials from [keystone_authtoken] section in the configuration - file and initialize the client and return an instance of the client - :return: Initialized instance of OS Client - """ - credentials = CONF.get('keystone_authtoken') - client = OSClient( - authurl=credentials.get('auth_url'), - username=credentials.get('username'), - password=credentials.get('password'), - project_name=credentials.get('project_name'), - user_domain_id=credentials.get('user_domain_id'), - project_domain_id=credentials.get('project_domain_id'), - project_domain_name=credentials.get('project_domain_name'), - user_domain_name=credentials.get('user_domain_name'), - **credentials.get('kwargs') - ) - - return client - - -def load_jinja_templates(template_dir, template_name, template_vars): - """Load and render existing Jinja2 templates. - - The main purpose of the function is to prepare the message to be sent and - render it for the driver to send it directly. - - :param template_dir: Location where jinja2 templates are stored - :param template_name: name of the template to load it - :param template_vars: Dict to replace existing vars in the template with - values. - :return: String message - """ - template_loader = jinja2.FileSystemLoader(searchpath=template_dir) - template_env = jinja2.Environment(loader=template_loader) - template = template_env.get_template(template_name) - return template.render(template_vars) - - -def get_admin_os_client(): - """Return admin client data. - - Loads credentials from [keystone_authtoken] section in the configuration - file and initialize the client with admin privileges and return - an instance of the client - :return: Initialized instance of OS Client - """ - credentials = CONF.get('keystone_authtoken') - client = OSClient( - authurl=credentials.get('auth_url'), - username=credentials.get('username'), - password=credentials.get('password'), - domain_name=credentials.get('domain_name'), - user_domain_id=credentials.get('user_domain_id'), - user_domain_name=credentials.get('user_domain_name'), - **credentials.get('kwargs') - ) - return client diff --git a/freezer_dr/common/yaml_parser.py b/freezer_dr/common/yaml_parser.py deleted file mode 100644 index 9a42b98..0000000 --- a/freezer_dr/common/yaml_parser.py +++ /dev/null @@ -1,72 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import os -import yaml - - -class YamlParser(object): - - _INDEX = 'servers' - - def __init__(self, yml_file, index='servers'): - """ - Provide Yaml file to parse it and process data - :param yml_file: path to yaml file - :param index: the key in the .yml file to get all servers listed under - this key. the default 'is servers' - """ - self.file = yml_file - self._INDEX = index - self.data = self.parse() - - def parse(self): - if not self.file: - raise Exception('No file specified !') - if not os.path.exists(self.file) or not os.path.isfile(self.file): - raise Exception('File desnot exists') - - stream = open(self.file, 'r') - data = yaml.load(stream) - return data - - def find_server_by_ip(self, ip): - """ - get server information ilo username, password and ip - :param ip: mgmt ip address of the server, this should be the same like - the ip in the .yml file - :return: dict contains server information - """ - return self.find_server('ip-addr', ip) - - def find_server_by_hostname(self, hostname): - """ - get server information ilo username, password and ip - :param hostname: hostname matches one of the ones in the .yml file - :return: dict contains the server information - """ - return self.find_server(key='hostname', value=hostname) - - def find_server(self, key, value): - """ - Generic function to query the .yml file to get server information by any - key. - :param key: - :param value: - :return: - """ - for server in self.data.get(self._INDEX): - if server.get(key) == value: - return server - - return None diff --git a/freezer_dr/evacuators/__init__.py b/freezer_dr/evacuators/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/evacuators/common/__init__.py b/freezer_dr/evacuators/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/evacuators/common/driver.py b/freezer_dr/evacuators/common/driver.py deleted file mode 100644 index 8fc6d8a..0000000 --- a/freezer_dr/evacuators/common/driver.py +++ /dev/null @@ -1,49 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import abc - - -class EvacuatorBaseDriver(object, metaclass=abc.ABCMeta): - """ - Abstract class for all evacuation drivers should implement to have - a unified interface - """ - - def __init__(self, nodes, evacuator_conf, fencer): - """ - Initialize Evacuation driver with the config args - :param nodes: A list of nodes to be evacuated! - :param evacuator_conf: A dict of arguments that got loaded from the - configuration file! - :return: None - """ - self.nodes = nodes - self.evacuator_conf = evacuator_conf - self.fencer = fencer - - @abc.abstractmethod - def evacuate(self, enable_fencing=True): - """Evacuate the infected node. - :return: Two lists; the first one will be the succeeded nodes and the - other is the failed nodes - """ - pass - - @abc.abstractmethod - def get_info(self): - """ - Get Driver Information - :return: Dict contains driver information - """ - pass diff --git a/freezer_dr/evacuators/common/manager.py b/freezer_dr/evacuators/common/manager.py deleted file mode 100644 index 880ccda..0000000 --- a/freezer_dr/evacuators/common/manager.py +++ /dev/null @@ -1,48 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from freezer_dr.evacuators.common.utils import get_nodes_details -from freezer_dr.fencers.common.manager import FencerManager -from oslo_config import cfg -from oslo_log import log -from oslo_utils import importutils -from time import sleep - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -class EvacuationManager(object): - - def __init__(self, enable_fencing=True): - self.enable_fencing = enable_fencing - - def evacuate(self, nodes): - fencer = FencerManager(nodes) - evacuation_conf = CONF.get('evacuation') - driver = importutils.import_object( - evacuation_conf['driver'], - nodes, - evacuation_conf, - fencer - ) - - return driver.evacuate(self.enable_fencing) - - def get_nodes_details(self, nodes): - """ - To be re-structured after fixing the nova bug ! - :param nodes: list of nodes - :return: list of node with more details - """ - return get_nodes_details(nodes) diff --git a/freezer_dr/evacuators/common/utils.py b/freezer_dr/evacuators/common/utils.py deleted file mode 100644 index a514b7c..0000000 --- a/freezer_dr/evacuators/common/utils.py +++ /dev/null @@ -1,62 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from freezer_dr.common.utils import get_admin_os_client -from freezer_dr.common.utils import get_os_client - - -def get_nodes_details(nodes): - """ - Get the hypervisor details, instances running on it, tenants - :param nodes: list of hypervisors - :return: List of hypervisors with detailed information - """ - nodes_details = [] - client = get_os_client() - for node in nodes: - instances = client.get_instances_list(node) - tenants = set([instance.get('tenant_id') for instance in instances]) - node['instances'] = instances - node['tenants'] = tenants - node['details'] = client.get_hypervisor_details(node) - nodes_details.append(node) - nodes_details = get_users_on_tenants(nodes_details) - return nodes_details - - -def get_users_on_tenants(nodes): - """ - Lists all users that have access to a certain tenant. - REQUIRE ADMIN PRIVILEGES ! - :param nodes: list of hypervisors - :return: List of hypervisors with detailed tenant info - """ - details = [] - client = get_admin_os_client() - for node in nodes: - if 'tenants' in node: - tenants = [] - for tenant in node.get('tenants'): - users = client.users_on_tenant(tenant) - tenants.append( - {'id': tenant, - 'users': users, - 'instances': [instance for instance in - node.get('instances') if - instance.get('tenant_id') == tenant]}) - node['tenants'] = tenants - details.append(node) - return details - - - diff --git a/freezer_dr/evacuators/drivers/__init__.py b/freezer_dr/evacuators/drivers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/evacuators/drivers/default/__init__.py b/freezer_dr/evacuators/drivers/default/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/evacuators/drivers/default/standard.py b/freezer_dr/evacuators/drivers/default/standard.py deleted file mode 100644 index 885e20f..0000000 --- a/freezer_dr/evacuators/drivers/default/standard.py +++ /dev/null @@ -1,117 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from freezer_dr.common.utils import get_os_client -from freezer_dr.evacuators.common.driver import EvacuatorBaseDriver -from oslo_config import cfg -from oslo_log import log -import time - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -class StandardEvacuator(EvacuatorBaseDriver): - - def __init__(self, nodes, evacuator_conf, fencer): - super(StandardEvacuator, self).__init__(nodes, evacuator_conf, fencer) - # initialize the OS client! - self.client = get_os_client() - self.wait = evacuator_conf.get('wait') - self.retires = evacuator_conf.get('retries', 1) - if self.retires <= 0: - self.retires = 1 - - def _disable_node(self, node): - if not self.is_node_disabled(node): - return self.disable_node(node) - else: - True - - def evacuate(self, enable_fencing=True): - # try to disable node - # @todo needs more error handling like if the status didn't update or - # we are unable to disable the node ??? - failed_nodes = [] # maintain nodes that are going to fail at any state - succeeded_nodes = [] - for node in self.nodes: - status = False - for i in range(0, self.retires): - status = self._disable_node(node) - # if True ( node disabled ) break the loop - if status: - break - else: - status = False - node['status'] = status - # make sure the disable request was successful - if not self.get_node_status(node): - # if the node failed at any step no reason to move it to - # the next step - failed_nodes.append(node) - self.nodes.remove(node) # - else: - succeeded_nodes.append(node) - - nodes = succeeded_nodes - if enable_fencing: - nodes = self.fencer.fence(nodes=nodes) - """ - @todo this code needs to be commented for the time being till we fix - nova bug found in state, which always go up afer enable or disable. We - will use get_node_details for the time being from the main script to - get nodes details before evacuating ... - succeeded_nodes = [] - for node in nodes: - node['instances'] = self.driver.get_node_instances(node) - succeeded_nodes.append(node) - - nodes = succeeded_nodes - """ - # Start evacuation calls ... - evacuated_nodes = [] - for i in range(0, self.retires): - try: - time.sleep(self.wait) - nodes = self.evacuate_nodes(nodes) - if not nodes: - break - evacuated_nodes = nodes - except Exception as e: - LOG.error(e) - - return evacuated_nodes, failed_nodes - - def get_node_instances(self, node): - return self.client.get_hypervisor_instances(node) - - def disable_node(self, node): - return self.client.disable_node(node) - - def get_node_status(self, node): - return self.client.get_node_status(node) - - def is_node_disabled(self, node): - return self.client.get_node_status(node) - - def evacuate_nodes(self, nodes): - return self.client.evacuate( - nodes, shared_storage=self.evacuator_conf['shared_storage']) - - def get_info(self): - """ - To be implemented. - Get Driver Information - :return: Dict contains driver information - """ - raise NotImplementedError diff --git a/freezer_dr/evacuators/drivers/dummy/__init__.py b/freezer_dr/evacuators/drivers/dummy/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/evacuators/drivers/dummy/dummy.py b/freezer_dr/evacuators/drivers/dummy/dummy.py deleted file mode 100644 index 615dc65..0000000 --- a/freezer_dr/evacuators/drivers/dummy/dummy.py +++ /dev/null @@ -1,41 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from freezer_dr.evacuators.common.driver import EvacuatorBaseDriver - - -class DummyEvacuator(EvacuatorBaseDriver): - """Evacuation driver that does nothing. Useful for testing other parts - of Freezer-DR. - """ - - def __init__(self, nodes, evacuator_conf, fencer): - super(DummyEvacuator, self).__init__(nodes, evacuator_conf, fencer) - - def disable_node(self, node): - return True - - def get_node_status(self, node): - return False - - def is_node_disabled(self, node): - return True - - def evacuate_nodes(self, nodes): - return nodes - - def get_node_instances(self, node): - raise NotImplementedError - - def get_info(self): - raise NotImplementedError diff --git a/freezer_dr/fencers/__init__.py b/freezer_dr/fencers/__init__.py deleted file mode 100644 index f920945..0000000 --- a/freezer_dr/fencers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'saad' diff --git a/freezer_dr/fencers/common/__init__.py b/freezer_dr/fencers/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/fencers/common/driver.py b/freezer_dr/fencers/common/driver.py deleted file mode 100644 index b1dfb9b..0000000 --- a/freezer_dr/fencers/common/driver.py +++ /dev/null @@ -1,53 +0,0 @@ -# (c) Copyright 2016 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Abstract fencer""" - -import abc - - -class FencerBaseDriver(object, metaclass=abc.ABCMeta): - - """Abstract class that all fencer plugins. - - Should be implemented to have a unified interface and as many plugins as - needed. - """ - - def __init__(self, nodes, fencer_conf): - """Initialize the driver. - - Any fencer driver requires the following parameters to do the api - calls. All these parameters can be passed from the configuration - file in /etc/freezer/dr.conf (default). - - :param nodes: A list of failed nodes to be fenced! - :param fencer_conf: dict contains configuration options loaded - from the config file. - """ - self.nodes = nodes - self.fencer_conf = fencer_conf - - @abc.abstractmethod - def fence(self): - """This function to be implemented by each driver. Each driver will - implement its own fencing logic and the manager will just load it and - call the fence function""" - - @abc.abstractmethod - def get_info(self): - """Get Driver information. - - :return: dict of name, version, author, ... - """ diff --git a/freezer_dr/fencers/common/manager.py b/freezer_dr/fencers/common/manager.py deleted file mode 100644 index 6a3431f..0000000 --- a/freezer_dr/fencers/common/manager.py +++ /dev/null @@ -1,46 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from oslo_config import cfg -from oslo_log import log -from oslo_utils import importutils - - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -class FencerManager(object): - - def __init__(self, nodes): - self.fencer_conf = CONF.get('fencer') - self.nodes = nodes - - def fence(self, nodes=None): - """ - Try to shutdown nodes and wait for configurable amount of times - :return: list of nodes and either they are shutdown or failed - """ - # update the list of nodes if required! - if nodes: - self.nodes = nodes - driver_name = self.fencer_conf['driver'] - driver = importutils.import_object( - driver_name, - self.nodes, - self.fencer_conf - ) - LOG.debug('Loaded fencing driver {0} with config: ' - '{1}'.format(driver.get_info(), self.fencer_conf)) - - return driver.fence() diff --git a/freezer_dr/fencers/drivers/__init__.py b/freezer_dr/fencers/drivers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/fencers/drivers/ipmi/__init__.py b/freezer_dr/fencers/drivers/ipmi/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/fencers/drivers/ipmi/driver.py b/freezer_dr/fencers/drivers/ipmi/driver.py deleted file mode 100644 index 3229395..0000000 --- a/freezer_dr/fencers/drivers/ipmi/driver.py +++ /dev/null @@ -1,115 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from freezer_dr.common.yaml_parser import YamlParser -from freezer_dr.fencers.common.driver import FencerBaseDriver -from freezer_dr.fencers.drivers.ipmi.ipmitool import IpmiInterface -from oslo_config import cfg -from oslo_log import log -import time - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -class IpmiDriver(FencerBaseDriver): - - def __init__(self, nodes, fencer_conf): - - super(IpmiDriver, self).__init__(nodes, fencer_conf) - self.parser = YamlParser(self.fencer_conf['credentials_file']) - - def prepare_node(self, node): - """Prepares the subprocess to call ``ipmitool`` with the node details! - :param node: dict contains node fencing information - """ - self.interface = IpmiInterface( - node.get('fencer-ip'), - node.get('fencer-user'), - node.get('fencer-password'), - verbose=CONF.debug) - - def force_shutdown(self): - try: - self.interface.power_down() - except Exception as e: - LOG.error(e) - - def graceful_shutdown(self): - try: - self.interface.power_soft() - except Exception as e: - LOG.error(e) - - def status(self): - return self.interface.get_power_status() - - # @todo remove this fn as it's for testing purposes only :) - def power_on(self): - self.interface.power_on() - - def get_node_details(self, node): - """Loads the node's fencing information from ``credentials_file`` - :param node: a dict contains node ip or hostname - :return: a dict contains node fencing information - """ - node_details = self.parser.find_server_by_ip(node.get('ip')) or \ - self.parser.find_server_by_hostname(node.get('host')) - - return node_details - - def fence(self): - """Implements the fencing procedure for server fencing using ipmi - :return: a list of nodes and weather they're fenced or not! - """ - fenced_nodes = [] - for node in self.nodes: - LOG.debug("fencing node {0}".format(node)) - # load node details - node_details = self.get_node_details(node) - # loop on the node number of n times trying to fence it gently, - # if not force it! - self.prepare_node(node_details) - for retry in range(0, self.fencer_conf['retries']): - if self.status(): - try: - self.graceful_shutdown() - except Exception as e: - LOG.debug(e) - else: - node['status'] = True - break - time.sleep(self.fencer_conf['hold_period']) - LOG.info('wait for %d seconds before retrying to gracefully ' - 'shutdown' % self.fencer_conf['hold_period']) - - try: - self.force_shutdown() - except Exception as e: - LOG.error(e) - - if not self.status(): - node['status'] = True - else: - node['status'] = False - fenced_nodes.append(node) - - return fenced_nodes - - def get_info(self): - return { - 'name': 'IPMI Interface driver', - 'version': 1.1, - 'author': 'Hewlett-Packard Enterprise Company, L.P' - } diff --git a/freezer_dr/fencers/drivers/ipmi/ipmitool.py b/freezer_dr/fencers/drivers/ipmi/ipmitool.py deleted file mode 100644 index 8533765..0000000 --- a/freezer_dr/fencers/drivers/ipmi/ipmitool.py +++ /dev/null @@ -1,150 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from distutils import spawn -from oslo_log import log - -import subprocess -import sys - - -LOG = log.getLogger(__name__) - - -class IpmiInterface: - - _IPMI = 'ipmitool' - _RAW_CMD = '{0} -I {1} -H {2} -U {3} -P {4} ' - _SUPPORTED_INTERFACES = ['lan', 'lanplus'] - - def __init__(self, host, username, password, verbose=False, - interface='lanplus'): - self._IPMI = spawn.find_executable('ipmitool') - if not self._IPMI: - self._IPMI = spawn.find_executable('ipmitool', - path=':'.join(sys.path)) - if interface not in self._SUPPORTED_INTERFACES: - raise Exception("Provided Interface is not supported") - - self._host = host - self._username = username - self._password = password - self._verbose = verbose - self._interface = interface - - self._update_cmd_credentials( - host=host, - username=username, - password=password, - interface=interface - ) - LOG.debug('IPMI Interface initialized') - - def _update_cmd_credentials(self, host, username, password, interface): - """ - Update credentials to work with different server - :param host: IPMI IP address of the server - :param username: IPMI username - :param password: IPMI password - :param interface: IPMI Interface lan, lanplus - """ - cmd = self._RAW_CMD.format( - self._IPMI, - interface, - host, - username, - password - ) - self._cmd = cmd - - def get_power_status(self): - """ - get the machine power status - :return: 1 if the power is on and 0 if the power is off. otherwise it - will return -1 for unknown state - """ - cmd = self._cmd + ' chassis power status' - output = self._process_request(cmd) - if self._verbose: - LOG.debug(output) - if 'is on'.lower() in output.lower(): - return 1 - elif 'is off'.lower() in output.lower(): - return 0 - return -1 # power status unknown - - def power_down(self): - """ - Force shutdown the machine - """ - cmd = self._cmd + ' chassis power down' - output = self._process_request(cmd) - LOG.info('IPMI interface force shutdown node: %s, output: %s' % - (self._host, output)) - return output - - def power_soft(self): - """ - Softly shutdown the machine - """ - cmd = self._cmd + 'chassis power soft' - output = self._process_request(cmd) - LOG.info('IPMI interface soft shutdown node: %s, output: %s' % - (self._host, output)) - return output - - def power_reset(self): - """ - restart the machine - """ - cmd = self._cmd + ' chassis power reset' - return self._process_request(cmd) - - def power_on(self): - """ - power on the machine - """ - cmd = self._cmd + ' chassis power on' - return self._process_request(cmd) - - def _process_request(self, cmd): - if self._verbose: - LOG.debug('Executing IPMI command:', cmd) - - process = subprocess.Popen(cmd, shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - output, error = process.communicate() - - if self._verbose: - LOG.debug('IPMI Output: ', output) - LOG.debug('IPMI Error', error) - - if process.returncode: - LOG.error(cmd) - raise Exception(error) - return output - - def _custom_cmd(self, cmd): - """ - execute custom ipmitool commands - :param cmd: string contains the command, for credentials and interface - you should _update_cmd_credentials to update them first - :return: output of the command you sent or raise error - """ - cmd = self._cmd + cmd - output = self._process_request(cmd) - LOG.info('Executing IPMI custom command: %s with output: %s' % - (cmd, output)) - return output diff --git a/freezer_dr/fencers/drivers/libvirt/__init__.py b/freezer_dr/fencers/drivers/libvirt/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/fencers/drivers/libvirt/driver.py b/freezer_dr/fencers/drivers/libvirt/driver.py deleted file mode 100644 index 2749357..0000000 --- a/freezer_dr/fencers/drivers/libvirt/driver.py +++ /dev/null @@ -1,100 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from freezer_dr.common.yaml_parser import YamlParser -from freezer_dr.fencers.common.driver import FencerBaseDriver -import libvirt -from oslo_config import cfg -from oslo_log import log -import time - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -class LibvirtDriver(FencerBaseDriver): - - def __init__(self, nodes, fencer_conf): - super(LibvirtDriver, self).__init__(nodes, fencer_conf) - self.parser = YamlParser(self.fencer_conf['credentials_file']) - # initiate libvirt connection - conn_name = self.fencer_conf.get('name', None) - self.connection = libvirt.open(name=conn_name) - - def force_shutdown(self, node): - target = self.connection.lookupByName(name=node.get('domain-name')) - return target.destroy() - - def graceful_shutdown(self, node): - target = self.connection.lookupByName(name=node.get('domain-name')) - return target.shutdown() - - def status(self, node): - target = self.connection.lookupByName(name=node.get('domain-name')) - return target.isActive() - - def get_node_details(self, node): - """Loads the node's fencing information from ``credentials_file`` - :param node: a dict contains node ip or hostname - :return: a dict contains node fencing information - """ - node_details = self.parser.find_server_by_ip(node.get('ip')) or \ - self.parser.find_server_by_hostname(node.get('host')) - - return node_details - - def fence(self): - """Implements the fencing procedure for server fencing using ipmi - :return: a list of nodes and weather they're fenced or not! - """ - fenced_nodes = [] - for node in self.nodes: - LOG.debug("fencing node {0}".format(node)) - # load node details - node_details = self.get_node_details(node) - # loop on the node number of n times trying to fence it gently, - # if not force it! - for retry in range(0, self.fencer_conf['retries']): - if self.status(node=node_details): - try: - self.graceful_shutdown(node=node_details) - except Exception as e: - LOG.debug(e) - else: - node['status'] = True - break - time.sleep(self.fencer_conf['hold_period']) - LOG.info('wait for %d seconds before retrying to gracefully ' - 'shutdown' % self.fencer_conf['hold_period']) - - try: - self.force_shutdown(node=node_details) - except Exception as e: - LOG.error(e) - - if not self.status(node=node_details): - node['status'] = True - else: - node['status'] = False - fenced_nodes.append(node) - - return fenced_nodes - - def get_info(self): - return { - 'name': 'Libvirt Interface driver', - 'version': 1.1, - 'author': 'Hewlett-Packard Enterprise Company, L.P' - } - - diff --git a/freezer_dr/main.py b/freezer_dr/main.py deleted file mode 100644 index 278c8ca..0000000 --- a/freezer_dr/main.py +++ /dev/null @@ -1,57 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import print_function - -from freezer_dr.common import config -from freezer_dr.evacuators.common.manager import EvacuationManager -from freezer_dr.monitors.common.manager import MonitorManager -from freezer_dr.notifiers.common.manager import NotificationManager -from oslo_config import cfg -from oslo_log import log - - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -def main(): - config.configure() - config.setup_logging() - LOG.info('Starting Freezer DR ... ') - # initialize the notification driver as it will be used in many parts - notifier = NotificationManager() - # load and initialize the monitoring driver - monitor = MonitorManager(notifier=notifier.get_driver()) - # Do the monitoring procedure - # Monitor, analyse, nodes down ?, wait, double check ? evacuate .. - nodes = monitor.monitor() - - if nodes: - # @todo put node in maintenance mode :) Not working with virtual - # deployments - # Load Fence driver - # Shutdown the node - evac = EvacuationManager() - notify_nodes = evac.get_nodes_details(nodes) - notifier.notify(notify_nodes, 'original') - evacuated_nodes, failed_nodes = evac.evacuate(nodes) - LOG.debug("Successfully evacuated nodes {0}".format(evacuated_nodes)) - LOG.debug("Failed to evacuate nodes {0}".format(failed_nodes)) - evacuated_nodes = evac.get_nodes_details(evacuated_nodes) - notifier.notify(evacuated_nodes, 'success') - failed_nodes = evac.get_nodes_details(failed_nodes) - notifier.notify(failed_nodes, 'error') - else: - print("No nodes reported to be down") diff --git a/freezer_dr/monitors/__init__.py b/freezer_dr/monitors/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/monitors/common/__init__.py b/freezer_dr/monitors/common/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/freezer_dr/monitors/common/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/freezer_dr/monitors/common/driver.py b/freezer_dr/monitors/common/driver.py deleted file mode 100644 index 27bddc1..0000000 --- a/freezer_dr/monitors/common/driver.py +++ /dev/null @@ -1,101 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import abc - -from oslo_config import cfg - -CONF = cfg.CONF - - -class MonitorBaseDriver(object, metaclass=abc.ABCMeta): - """ - Abstract class that all monitoring plugins should implement to have a - unified interface and as many plugins as we want... - """ - _OPTS = [] - - def __init__(self, backend_name, notifier): - """ - Initializing the driver. Any monitoring system requires the following - parameters to call it's api. All these parameters can be passed from the - configuration file in /etc/freezer/dr.conf - :param backend_name: Name of section in the configuration file that - contains your driver initialization details; like username, password, - endpoint and so on. Variables in this section depends on your driver - - :param notifier: Notifier instance which can be used to notify the - admins in case of error or problem happened during the DR process. - You should only call notify method and send it your message to send - it to the admins - """ - CONF.register_opts(self._OPTS, group=backend_name) - self.conf = CONF.get(backend_name) - self.notifier = notifier - - @abc.abstractmethod - def get_data(self): - """ - Gathering metrics data. making the actual api call to - the monitoring system and get a list of nodes status. - """ - pass - - @abc.abstractmethod - def get_metrics(self): - """ - return list of metrics used to monitor compute nodes. it's Optional - not all drivers need to implement this method. - """ - raise NotImplementedError() - - @abc.abstractmethod - def analyze_nodes(self, nodes): - """ - Process nodes from get_data and return list of down nodes - :param nodes: dict of metrics of nodes { 'metric1': nodes, - 'metric2': nodes} - :return: a list of down nodes - """ - pass - - @abc.abstractmethod - def process_failed(self, nodes=[], wait=0): - """ - Double check the failed nodes again to make sure that nodes are down. - return a list of down nodes to be passed to the evacuation tool to - process failed hosts. - :param nodes: a list contains pre-checked nodes to re-check them again - :param wait: a configurable a mount of time to wait before doing this - check to give a chance for the host to recover if there was a minor - issue. - :return: a list of nodes to be evacuated, the list will be passed - directly to the evacuation tool to process them - """ - pass - - @abc.abstractmethod - def is_alive(self): - """ - Plugin should provide a way to make sure that the monitoring system is - a live or not. It's optional not all drivers need to implement it. - :return: True or False - """ - raise NotImplementedError() - - def get_info(self): - """ - Get Driver information .. - :return: dict of name, version, author, ... - """ diff --git a/freezer_dr/monitors/common/manager.py b/freezer_dr/monitors/common/manager.py deleted file mode 100644 index 84b3f57..0000000 --- a/freezer_dr/monitors/common/manager.py +++ /dev/null @@ -1,65 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from oslo_config import cfg -from oslo_log import log -from oslo_utils import importutils - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -class MonitorManager(object): - - def __init__(self, notifier): - monitor = CONF.get('monitoring') - backend_name = monitor['backend_name'] - self.driver = importutils.import_object( - monitor.driver, - backend_name=backend_name, - notifier=notifier - ) - driver_info = self.driver.get_info() - LOG.info('Initializing driver %s with version %s found in %s' % - (driver_info['name'], driver_info['version'], - monitor.get('driver'))) - - def monitor(self): - # Check if the monitoring system is a live - is_alive = self.driver.is_alive() - # if not a live will record that in logs and will try to communicate ! - if not is_alive: - LOG.error('Monitoring system is not a live or may be driver is ' - 'missing implementation for is_alive method') - - # getting data from the monitoring system - # may be in future we add a hock function to external data processors ! - # @todo add external data processors to analyze the monitoring systems - # data to separate monitoring from analysis - data = self.driver.get_data() - - # Asking the driver to analyze the data provided and provide list - # of failed nodes - nodes_down = self.driver.analyze_nodes(nodes=data) - if not nodes_down: - LOG.info('No nodes reported down') - return 0 # for the time being we will exit with no error ! - - LOG.info('Nodes Down are: %s will be double checked again after %s ' - 'seconds' % (str(nodes_down), CONF.wait)) - nodes_to_evacuate = self.driver.process_failed(nodes=nodes_down, - wait=CONF.wait) - return nodes_to_evacuate - - def get_driver_info(self): - return self.driver.get_info() diff --git a/freezer_dr/monitors/drivers/__init__.py b/freezer_dr/monitors/drivers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/monitors/drivers/default/__init__.py b/freezer_dr/monitors/drivers/default/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/monitors/drivers/default/driver.py b/freezer_dr/monitors/drivers/default/driver.py deleted file mode 100644 index a885a41..0000000 --- a/freezer_dr/monitors/drivers/default/driver.py +++ /dev/null @@ -1,158 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from freezer_dr.common.osclient import OSClient -from freezer_dr.monitors.common.driver import MonitorBaseDriver - -from http.client import HTTPConnection -from http.client import HTTPSConnection -from http.client import socket - -from oslo_config import cfg -from oslo_log import log -from time import sleep - -from urllib.parse import urlparse - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -class StandardDriver(MonitorBaseDriver): - _OPTS = [ - cfg.StrOpt('username', - help='username to be used to initialize the default ' - 'monitoring driver'), - cfg.StrOpt('password', - help='Password to be used for initializing the default ' - 'monitoring driver'), - cfg.StrOpt('endpoint', - help='Monitoring system API endpoint'), - cfg.DictOpt('kwargs', - default={}, - help='List of kwargs if you want to pass it to initialize' - ' the monitoring driver. should be provided in' - ' key:value format'), - ] - - def __init__(self, backend_name, notifier): - super(StandardDriver, self).__init__(backend_name=backend_name, - notifier=notifier) - self.endpoint = self.conf.endpoint - client = OSClient( - authurl=self.conf.endpoint, - username=self.conf.username, - password=self.conf.password, - **self.conf.kwargs - ) - LOG.info("OSClient:: username: %s, password: %s, endpoint: %s, kwargs:" - " %s" % (self.conf.username, '****', self.conf.endpoint, - self.conf.kwargs) - ) - self.client = client - - def get_data(self): - hypervisors = self.client.novahypervisors() - computes = self.client.novacomputes() - agents = self.client.neutronagents() - data = {'hypervisors': hypervisors, - 'computes': computes, - 'agents': agents} - return data - - def process_failed(self, nodes=None, wait=0): - if not wait: - wait = CONF.wait - if not nodes: - return None - sleep(wait) - # @todo do the api call again to get the nodes status again - data = self.get_data() - nodes_down = self.analyze_nodes(nodes=data) - # Thanks Eldar :) for sets - nodes_down_hosts = set([dnode['host'] for dnode in nodes_down]) - return [node for node in nodes if node['host'] in nodes_down_hosts] - - def get_metrics(self): - return ['nova-compute', 'hypervisor', 'neutron-ovs-agent'] - - def analyze_nodes(self, nodes): - # list all down nova compute - nova_down = self.is_nova_service_down(nodes.get('computes')) - # list all down hypervisors - hypervisor_down = self.is_hpyervisor_down(nodes.get('hypervisors')) - # list all down openvswitch agents - agents_down = self.is_neutron_agents_down(nodes.get('agents')) - - nodes_down = [] - for server in hypervisor_down: - ip = server.get('ip') - host = server.get('host') - if host in nova_down and host in agents_down: - node = {'ip': ip, 'host': host} - nodes_down.append(node) - - return nodes_down - - def is_alive(self): - url = urlparse(self.endpoint) - if url.scheme == 'https': - http_connector = HTTPSConnection - else: - http_connector = HTTPConnection - try: - connection = http_connector(host=url.netloc) - connection.request('HEAD', url=url.path) - response = connection.getresponse() - except socket.error: - return False - try: - if getattr(response, 'status') == 200: - return True - except AttributeError: - pass - return False - - def get_info(self): - return { - 'name': 'Freezer DR Native Driver', - 'version': 1.0, - 'author': 'Hewlett-Packard Development Company, L.P' - } - - def is_hpyervisor_down(self, hypervisors): - down_hosts = [] - for hypervisor in hypervisors: - if hypervisor.get('state') == 'down': - host = {} - host['host'] = hypervisor.get('service').get('host') - host['ip'] = hypervisor.get('host_ip') - down_hosts.append(host) - - return down_hosts - - def is_nova_service_down(self, computes): - down_hosts = [] - for node in computes: - if node.get('state') == 'down' and node.get('status') == 'enabled': - down_hosts.append(node.get('host')) - return down_hosts - - def is_neutron_agents_down(self, agents): - down_hosts = [] - for agent in agents: - if agent.get('admin_state_up') and not agent.get('alive'): - down_hosts.append(agent.get('host')) - - return down_hosts - diff --git a/freezer_dr/monitors/drivers/dummy/__init__.py b/freezer_dr/monitors/drivers/dummy/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/monitors/drivers/dummy/driver.py b/freezer_dr/monitors/drivers/dummy/driver.py deleted file mode 100644 index 1915863..0000000 --- a/freezer_dr/monitors/drivers/dummy/driver.py +++ /dev/null @@ -1,64 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_config import cfg - -from freezer_dr.monitors.common.driver import MonitorBaseDriver - -CONF = cfg.CONF - - -class DummyDriver(MonitorBaseDriver): - """A monitoring driver that returns a configured list of nodes as failed. - - This can be useful for testing without actually shutting down the nodes. - The nodes that should be reported as failing, can be configured in the - monitoring section of the freezer_dr configuration file as follows: - kwargs = nodes_down:hostname1;hostname2 - """ - _OPTS = [ - cfg.ListOpt('nodes_down', - default=[], - required=True, - help="fake list of failed compute nodes.") - ] - - def __init__(self, backend_name, notifier): - super(DummyDriver, self).__init__(backend_name=backend_name, - notifier=notifier) - - hostnames = self.conf.get('nodes_down', []) - self.nodes_down = [{'host': n} for n in hostnames] - - def get_data(self): - return self.nodes_down - - def get_metrics(self): - raise NotImplementedError() - - def process_failed(self, nodes=None, wait=0): - return nodes - - def analyze_nodes(self, nodes): - return nodes - - def is_alive(self): - return True - - def get_info(self): - return { - 'name': 'Freezer DR Dummy Driver', - 'version': 1.0, - 'author': 'Hewlett-Packard Enterprise Development, L.P' - } diff --git a/freezer_dr/monitors/drivers/monasca/__init__.py b/freezer_dr/monitors/drivers/monasca/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/monitors/drivers/monasca/driver.py b/freezer_dr/monitors/drivers/monasca/driver.py deleted file mode 100644 index 329a92c..0000000 --- a/freezer_dr/monitors/drivers/monasca/driver.py +++ /dev/null @@ -1,339 +0,0 @@ -# (c) Copyright 2016 Hewlett-Packard Development Enterprise, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import http.client -import time -import urllib.parse - -from monascaclient import client -from oslo_config import cfg -from oslo_log import log - -from freezer_dr.common import utils -from freezer_dr.monitors.common import driver - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -class MonascaDriver(driver.MonitorBaseDriver): - """Monasca monitoring driver to monitor compute nodes. It makes use of - Monasca to monitor the compute nodes. Metric information - needed. 'hostname' must be used in dimensions to filter the - values in alarms. You need to define alarms for all hosts with - the required metrics. - """ - - _OPTS = [ - cfg.StrOpt('keystone_url', - help="Keystone Url for authentication", - required=True), - cfg.StrOpt('username', - help="cloud user used to record monasca alerts and alarms", - required=True), - cfg.StrOpt('password', - help="Cloud user's password", - required=True), - cfg.StrOpt('project_name', - help='Project/Tenant name. Default is admin', - default='admin', - required=True), - cfg.BoolOpt('insecure', - help='Use insecure connection.', - default=False), - cfg.StrOpt('project_domain_id', - help="Project Domain Id. Default is default", - default='default'), - cfg.StrOpt('user_domain_id', - help="User Domain Id. Default is default", - default='default'), - cfg.StrOpt('cacert', - help='CA certificate. Default is None', - default=None), - cfg.StrOpt('monasca_url', - help='Monasca endpoint URL. This is required to create a ' - 'monasca client instance ' - ), - cfg.ListOpt('metrics', - help='Monasca Metrics that needs to be checked. Each metric' - ' should be defined in a seperate section in the' - ' configuration file.', - default=['host_alive_status'], - required=True - ), - cfg.StrOpt('aggregate', - choices=['any', 'all'], - default='all', - help="If more than one metric used and they reported " - "different states i.e.(a:failed, b:success) should we " - "evacuate the compute host if only one metric failed " - "(any) or only if all failed we evacuate (all). " - "Default is all") - ] - - def __init__(self, backend_name, notifier): - super(MonascaDriver, self).__init__(backend_name=backend_name, - notifier=notifier) - self.monasca_client = client.Client( - "2_0", - self.conf['monasca_url'], - auth_url=self.conf['keystone_url'], - username=self.conf['username'], - password=self.conf['password'], - project_name=self.conf['project_name'], - user_doamin_id=self.conf['user_domain_id'], - project_doamin_id=self.conf['project_domain_id'], - insecure=self.conf.get('insecure'), - cacert=self.conf.get('cacert', None) - ) - # Compute nodes might be disabled or set to maintenance mode so - # freezer-dr needs to process only enabled nodes ... - self.nodes = [node for node in self.get_compute_nodes() - if node['status'] == "enabled"] - # register metric options in their groups and load their values - self.__load_metrics() - - def _get_raw_data(self): - """ This function returns the raw data we got from Monasca before - processing and normalizing. You shouldn't call this function directly. - :return: dict contains: - { - hostname1: { - metric_name1: [{metric value 1}, {metric value 2}] - metric_name2: [{metric value 1}, {metric value 2}] - }, - hostname2: { - metric_name1: [{metric value 1}, {metric value 2}] - metric_name2: [{metric value 1}, {metric value 2}] - } - } - """ - data = {} - for node in self.nodes: - data[node['host']] = {} - for metric in self.conf.metrics: - data[node['host']][metric] = self.monasca_client.alarms.list( - **self._build_metrics( - metric=metric, - hostname=node['host'] - ) - ) - return data - - def get_data(self): - """This function returns monitoring data from Monasca. It calls - _get_raw_data to get raw data and then process these data returns - a normalized dict - :return: dict contains:: - - { - hostname1: { - metric_name1: ['Ok', 'ALARM', 'UNDETERMINED'] - metric_name2: ['OK', 'OK', 'OK'] - }, - hostname2: { - metric_name1: ['Ok', 'ALARM', 'OK'] - metric_name2: ['ALARM', 'UNDETERMINED', 'OK'] - } - } - """ - data = self._get_raw_data() - data2 = {} - for host, metric_results in data.items(): - data2[host] = {} - for metric_name, metric_values in metric_results.iteritems(): - data2[host][metric_name] = [] - for metric_value in metric_values: - data2[host][metric_name].append(metric_value.get('state')) - return data2 - - def process_failed(self, nodes=None, wait=1): - time.sleep(wait) - data = self.get_data() - nodes_down = self.analyze_nodes(nodes=data) - # Thanks Eldar :) for sets - nodes_down_hosts = set([dnode['host'] for dnode in nodes_down]) - return [node for node in nodes if node['host'] in nodes_down_hosts] - - def get_metrics(self): - """Lists all metrics - :return: List of Metrics - """ - return self.conf['metrics'] - - def _build_metrics(self, metric, hostname=None): - """Build the query to send to Monasca""" - metric = CONF[metric] - dimensions = {'hostname': hostname} - dimensions.update(metric.get('dimensions', {})) - - fields = { - 'metric_dimensions': dimensions, - 'metric_name': metric['metric_name'] - } - return fields - - def analyze_nodes(self, nodes): - """It will check if the nodes are in 'OK' state or not. If not they - will considered down. We have three states as follow: - 1. OK - 2. ALARM - 3. UNDEFINED - """ - # @todo(szaher) use list comprehension instead of loops - # list below is correct and should return the extact same value like - # the two nested for loops - # nodes_down = [ - # {"host": hostname} for hostname, metrics in nodes.iteritems() if - # [True for name, values in metrics.iteritems() if 'ALARM' in values] - # ] - nodes_data = [] - for node, metrics in nodes.iteritems(): - node_data = {node: []} - for metric_name, metric_data in metrics.iteritems(): - node_data[node].append( - self.__process_metric(node, metric_name, metric_data) - ) - nodes_data.append(node_data) - - aggregate = self.conf.get('aggregate', 'all') - aggregate += '({0})' - nodes_down = [] - for node_data in nodes_data: - node_info = {} - for node, data in node_data.iteritems(): - if not data: - LOG.warning('No data available for node: {0}'.format(node)) - continue - node_info[node] = eval(aggregate.format(data)) - if node_info: - nodes_down.append(node_info) - - if not nodes_down: - return [] - return [ - {'host': host.keys()[0]} for host in nodes_down - if True in host.values() - ] - - def __process_metric(self, node, metric_name, metric_data): - """Process metric values got from Monasca. - Handles UNDETERMINED states and changes it to required state(read - from config file). - If no metric data found,""" - metric_conf = CONF[metric_name] - # process UNDETERMINED State and change it to the required state - metric_data = [ - i if i in ['OK', 'ALARM'] else - metric_conf.get('undetermined', 'ALARM').upper() - for i in metric_data - ] - if not metric_data: - message = """ - No data found for this metric: {0}
- Data returned: {1}
- hostname: {2}
- Cause might be:
-
    -
  • Metric is not defined in Monasca
  • -
  • Alarm with this metric name is not set for this host
  • -
  • Check your Monasca configuration and Metric configuration - defined in freezer-dr.conf
  • -
- You can try this command to check:
- $ monasca alarm-list --metric-name {3} --metric-dimensions - hostname={2} - -

- Freezer-DR - """.format(metric_name, str(metric_data), node, - metric_conf['metric_name']) - self.notifier.notify(message) - LOG.warning("No data found for metric: {0} on host: {1}".format( - metric_name, node - )) - exit(1) - # build the decision - aggregate = metric_conf.get('aggregate') - aggregate += "(x=='ALARM' for x in metric_data)" - return eval(aggregate) - - def is_alive(self): - url = urllib.parse.urlparse(self.conf.monasca_url) - if url.scheme == 'https': - http_connector = http.client.HTTPSConnection - else: - http_connector = http.client.HTTPConnection - try: - connection = http_connector(host=url.netloc) - connection.request('HEAD', url=url.path) - response = connection.getresponse() - except http.client.socket.error: - return False - try: - if getattr(response, 'status') in [200, 401]: - return True - except AttributeError: - pass - return False - - def get_info(self): - return { - 'name': 'Monasca Driver', - 'version': 1.0, - 'author': 'Hewlett-Packard Development Enterprise, L.P' - } - - def get_compute_nodes(self): - """Get a list of available compute hosts.""" - client = utils.get_os_client() - return client.novacomputes() - - def __load_metrics(self): - """load custom sections created by user""" - for metric in self.conf.metrics: - CONF.register_opts(self.__metric_opts, group=metric) - - @property - def __metric_opts(self): - """List of options to be used in metric defined sections""" - return [ - cfg.StrOpt("metric_name", - help="Metric Name used to log monitoring information" - " in Monasca", - required=True), - cfg.DictOpt("dimensions", - default={}, - help="Dict that contains dimensions information. " - "component:nova-compute,service:compute", - ), - cfg.StrOpt("aggregate", - choices=["any", "all"], - help="How to consider the compute node is down. If you " - "metric reports many states, like checking " - "different services on the compute host, should we" - " consider if one component down all are down or" - " only if all components are down. Default is all." - " This means if all components fail, freezer-dr" - " will consider the host failed", - default='all' - ), - cfg.StrOpt("undetermined", - choices=['OK', 'ALARM'], - default='ALARM', - help="How to handle UNDETERMINED states. It can be " - "ignored, will be considered OK state or can be " - "considered ALARM. Default is ALARM") - - ] diff --git a/freezer_dr/notifiers/__init__.py b/freezer_dr/notifiers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/notifiers/common/__init__.py b/freezer_dr/notifiers/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/notifiers/common/driver.py b/freezer_dr/notifiers/common/driver.py deleted file mode 100644 index b8b17ec..0000000 --- a/freezer_dr/notifiers/common/driver.py +++ /dev/null @@ -1,57 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import abc - - -class NotifierBaseDriver(object, metaclass=abc.ABCMeta): - """ Used to notify admins/users at any stage that an error happened or - process completed or something went wrong ! - """ - - def __init__(self, url, username, password, templates_dir, notify_from, - admin_list=None, **kwargs): - """ Initialize the notification backend. - :param url: Notification system backend - :param username: Username - :param password: Password - :param templates_dir: Path to templates directory to load message - templates - :param kwargs: Key:Value arguments - """ - self.url = url - self.username = username - self.password = password - self.templates_dir = templates_dir - self.admin_list = admin_list - self.notify_from = notify_from - self.options = kwargs - - @abc.abstractmethod - def notify_status(self, node, status): - """ Custom notification method. Can be used if you want to send custom - notification about Tenant, Instance, or go deeper if you want - :param node: Compute Host, Tenant, Instance, ... - :param status: Error, Success, Info - :return: True, False - """ - pass - - @abc.abstractmethod - def notify(self, message): - """ This method will be used in different places to notify admins - about certain problem - :param message: String message name - :return: - """ - pass diff --git a/freezer_dr/notifiers/common/manager.py b/freezer_dr/notifiers/common/manager.py deleted file mode 100644 index 1781e01..0000000 --- a/freezer_dr/notifiers/common/manager.py +++ /dev/null @@ -1,54 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from oslo_config import cfg -from oslo_log import log -from oslo_utils import importutils - - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -class NotificationManager(object): - - def __init__(self): - notifier_conf = CONF.get('notifiers') - self.driver = importutils.import_object( - notifier_conf.get('driver'), - notifier_conf.get('endpoint'), - notifier_conf.get('username'), - notifier_conf.get('password'), - notifier_conf.get('templates-dir'), - notifier_conf.get('notify-from'), - notifier_conf.get('notify-list'), - **notifier_conf.get('options') - ) - - def notify(self, nodes, status): - """ - Send Notification to users added on tenants that has VMs running on the - affected host. - :param nodes: List of hosts that are affected, contains instances - running on those hosts, tenants, users added on those tenants. - :param status: success or error - :return: - """ - for node in nodes: - self.driver.notify_status(node, status) - - def get_driver(self): - return self.driver - - - diff --git a/freezer_dr/notifiers/drivers/__init__.py b/freezer_dr/notifiers/drivers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/notifiers/drivers/default/__init__.py b/freezer_dr/notifiers/drivers/default/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/notifiers/drivers/default/default_email.py b/freezer_dr/notifiers/drivers/default/default_email.py deleted file mode 100644 index 30854e0..0000000 --- a/freezer_dr/notifiers/drivers/default/default_email.py +++ /dev/null @@ -1,124 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from datetime import date -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -from freezer_dr.common.utils import load_jinja_templates -from freezer_dr.notifiers.common.driver import NotifierBaseDriver -from oslo_config import cfg -from oslo_log import log -import smtplib -import time - - -CONF = cfg.CONF -LOG = log.getLogger(__name__) - - -class StandardEmail(NotifierBaseDriver): - - def __init__(self, url, username, password, templates_dir, notify_from, - admin_list=None, **kwargs): - super(StandardEmail, self).__init__(url, username, password, - templates_dir, notify_from, - admin_list, **kwargs) - LOG.info('Initializing StandardEmail driver @ {0}'.format(url)) - server = smtplib.SMTP(url, kwargs.get('port')) - server.ehlo() - if kwargs.get('tls'): - LOG.info('TLS enabled !') - server.starttls() - if username and password: - server.login(username, password) - LOG.info('Logged in !') - self.server = server - - def notify_status(self, node, status): - _template = 'info.jinja' - if status == 'original': - _template = 'original.jinja' - if status == 'success': - _template = 'user_success.jinja' - elif status == 'error': - _template = 'error.jinja' - - for tenant in node.get('tenants'): - for user in tenant.get('users'): - if 'email' in user: - subject = '[' + status + '] Evacuation Status' - template_vars = { - 'name': user.get('name'), - 'tenant': tenant.get('id'), - 'instances': tenant.get('instances'), - 'evacuation_time': date.fromtimestamp(time.time()) - } - message = load_jinja_templates(self.templates_dir, - _template, template_vars) - self.send_email(self.notify_from, user.get('email'), - subject, html_msg=message) - # notify administrators - subject = 'Host Evacuation status' - _template = 'success.jinja' - template_vars = { - 'host': node.get('host'), - 'tenants': node.get('tenants'), - 'instances': node.get('instances'), - 'hypervisor': node.get('details'), - 'evacuation_time': date.fromtimestamp(time.time()) - } - message = load_jinja_templates(self.templates_dir, _template, - template_vars) - self.send_email(self.notify_from, self.notify_from, subject, - message, self.admin_list or None) - - def send_email(self, mail_from, mail_to, subject, html_msg, cc_list=None, - plain_msg=None): - LOG.info('Sending email ....') - message = MIMEMultipart() - message['Subject'] = subject - message['to'] = mail_to - if cc_list: - message['cc'] = ', '.join(cc_list) - message['from'] = mail_from or self.notify_from - msg = MIMEText(html_msg, 'html') - message.attach(msg) - if plain_msg: - plain_msg = MIMEText(plain_msg, 'plain') - message.attach(plain_msg) - - try: - self.server.sendmail(mail_from, mail_to, - message.as_string()) - LOG.info('Email sent successfully !') - except Exception as e: - LOG.error(e) - - def notify(self, message): - try: - self.send_email( - mail_from=self.notify_from, - mail_to=self.notify_from, - subject="[Freezer-DR] Problem Occurred", - html_msg=message, - cc_list=self.admin_list or [] - ) - return True - except Exception: - return False - - def __exit__(self, exc_type, exc_val, exc_tb): - self.server.quit() - - - diff --git a/freezer_dr/notifiers/drivers/slack/__init__.py b/freezer_dr/notifiers/drivers/slack/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/freezer_dr/notifiers/drivers/slack/slack.py b/freezer_dr/notifiers/drivers/slack/slack.py deleted file mode 100644 index d3d2f51..0000000 --- a/freezer_dr/notifiers/drivers/slack/slack.py +++ /dev/null @@ -1,147 +0,0 @@ -# -# 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 datetime import date -from freezer_dr.notifiers.common.driver import NotifierBaseDriver -import json -from oslo_log import log -import requests -import time -import urllib.parse - -LOG = log.getLogger(__name__) - -class SlackNotifier(NotifierBaseDriver): - - MAX_CACHE_SIZE = 100 - RESPONSE_OK = 'ok' - - _raw_data_url_caches = [] - - def __init__(self, url, username, password, templates_dir, notify_from, - admin_list=None, **kwargs): - super(SlackNotifier, self).__init__(url, username, password, - templates_dir, notify_from, - admin_list, **kwargs) - LOG.info('Initializing SlackNotifier driver @ {0}'.format(url)) - - self.slack_timeout = kwargs.get('slack_timeout', '') - self.slack_ca_certs = kwargs.get('slack_ca_certs', '') - self.slack_insecured = kwargs.get('slack_insecured', 'True') - self.slack_proxy = kwargs.get('slack_proxy', '') - - def _build_slack_message(self, node, status): - """Builds slack message body - """ - body = { - 'title': 'Host Evacuation status', - 'host': node.get('host'), - 'tenants': node.get('tenants'), - 'instances': node.get('instances'), - 'hypervisor': node.get('details'), - 'evacuation_time': date.fromtimestamp(time.time()), - 'status': status - } - slack_request = {} - slack_request['text'] = json.dumps(body, indent=3) - - return slack_request - - def _check_response(self, result): - if 'application/json' in result.headers.get('Content-Type'): - response = result.json() - if response.get(self.RESPONSE_OK): - return True - else: - LOG.error('Received an error message when trying to send to slack. error={}' - .format(response.get('error'))) - return False - elif self.RESPONSE_OK == result.text: - return True - else: - LOG.error('Received an error message when trying to send to slack. error={}' - .format(result.text)) - return False - - def _send_message(self, request_options): - try: - url = request_options.get('url') - result = requests.post(**request_options) - if result.status_code not in range(200, 300): - LOG.error('Received an HTTP code {} when trying to post on URL {}.' - .format(result.status_code, url)) - return False - - # Slack returns 200 ok even if the token is invalid. Response has valid error message - if self._check_response(result): - LOG.info('Notification successfully posted.') - return True - - LOG.error('Failed to send to slack on URL {}.'.format(url)) - return False - except Exception as err: - LOG.error('Error trying to send to slack on URL {}. Detail: {}' - .format(url, err)) - return False - - - - def notify_status(self, node, status): - """Notify the Host Evacuation status via slack - Posts on the given url - """ - - slack_message = self._build_slack_message(node, status) - address = self.url - address = address.replace('#', '%23') - - parsed_url = urllib.parse.urlsplit(address) - query_params = urllib.parse.parse_qs(parsed_url.query) - url = urllib.parse.urljoin(address, urllib.parse.urlparse(address).path) - - verify = self.slack_ca_certs or not self.slack_insecured - - proxy = self.slack_proxy - proxy_dict = None - if proxy is not None: - proxy_dict = {'https': proxy} - - data_format_list = ['json', 'data'] - if url in SlackNotifier._raw_data_url_caches: - data_format_list = ['data'] - - for data_format in data_format_list: - LOG.info('Trying to send message to {} as {}' - .format(url, data_format)) - request_options = { - 'url': url, - 'verify': verify, - 'params': query_params, - 'proxies': proxy_dict, - 'timeout': self.slack_timeout, - data_format: slack_message - } - if self._send_message(request_options): - if (data_format == 'data' and - url not in SlackNotifier._raw_data_url_caches and - len(SlackNotifier._raw_data_url_caches) < self.MAX_CACHE_SIZE): - SlackNotifier._raw_data_url_caches.append(url) - return True - - LOG.info('Failed to send message to {} as {}' - .format(url, data_format)) - return False - - def notify(self, message): - pass - diff --git a/releasenotes/notes/drop-py-2-7-7c6101f30ffd8c71.yaml b/releasenotes/notes/drop-py-2-7-7c6101f30ffd8c71.yaml deleted file mode 100644 index 3d568e9..0000000 --- a/releasenotes/notes/drop-py-2-7-7c6101f30ffd8c71.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - | - Python 2.7 support has been dropped. Last release of freezer-dr - to support py2.7 is OpenStack Train. The minimum version of Python now - supported by freezer-dr is Python 3.6. diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 7be9277..0000000 --- a/requirements.txt +++ /dev/null @@ -1,11 +0,0 @@ -pbr>=2.0.0 # Apache-2.0 -python-keystoneclient>=3.8.0 # Apache-2.0 -python-monascaclient>=1.1.0 # Apache-2.0 -python-neutronclient>=6.7.0 # Apache-2.0 -python-novaclient>=9.1.0 # Apache-2.0 -PyYAML>=3.12.0 # MIT -oslo.config>=5.2.0 # Apache-2.0 -oslo.utils>=3.33.0 # Apache-2.0 -oslo.log>=3.36.0 # Apache-2.0 -libvirt-python>=1.2.5 # LGPLv2+ -Jinja2>=2.10 # BSD License (3 clause) diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 3fac336..0000000 --- a/setup.cfg +++ /dev/null @@ -1,46 +0,0 @@ -[metadata] -name = freezer-dr -summary = OpenStack Disaster Recovery -description-file = - README.rst -author = Freezer Team -author-email = openstack-discuss@lists.openstack.org -home-page = https://docs.openstack.org/freezer/latest/ -classifier = - Environment :: OpenStack - Intended Audience :: Developers - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: Implementation :: CPython - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Development Status :: 5 - Production/Stable - Natural Language :: English - Operating System :: POSIX :: Linux - Topic :: System :: Recovery Tools - -keywords = - openstack - freezer - disaster - recovery - evacuation - high availability - dr - -[files] -packages = - freezer_dr - -[entry_points] -oslo.config.opts = - freezer-dr = freezer_dr.common.config:list_opts -console_scripts = - freezer-dr = freezer_dr.main:main diff --git a/setup.py b/setup.py deleted file mode 100644 index cd35c3c..0000000 --- a/setup.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import setuptools - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 3c93bdf..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -# hacking pins flake8 etc -hacking>=3.0.1,<3.1.0 # Apache-2.0 -coverage>=4.0 -mock>=2.0.0 -pylint==2.4.0 # GPLv2 -stestr>=2.0.0 # Apache-2.0 -testtools>=2.2.0 -sphinx!=1.6.6,!=1.6.7,!=2.1.0,>=1.6.2 # BSD -openstackdocstheme>=1.31.2 # Apache-2.0 -sphinxcontrib-apidoc>=0.2.0 diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index f920945..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'saad' diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py deleted file mode 100644 index f920945..0000000 --- a/tests/unit/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'saad' diff --git a/tests/unit/common/__init__.py b/tests/unit/common/__init__.py deleted file mode 100644 index f920945..0000000 --- a/tests/unit/common/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'saad' diff --git a/tests/unit/common/test_yaml_parser.py b/tests/unit/common/test_yaml_parser.py deleted file mode 100644 index 5c8a0a8..0000000 --- a/tests/unit/common/test_yaml_parser.py +++ /dev/null @@ -1,39 +0,0 @@ -# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import unittest -from mock import patch - -from freezer_dr.common import utils -from freezer_dr.common.osclient import OSClient - - -class TestUtils(unittest.TestCase): - - @patch('freezer_dr.common.utils.CONF') - def test_os_credentials(self, mock_CONF): - keystone_conf = dict({ - 'auth_url': '', - 'password': '', - 'project_name': '', - 'user_domain_id': '', - 'project_domain_id': '', - 'project_domain_id': '', - 'user_domain_name': '', - 'kwargs': '' - }) - mock_CONF = {'keystone_authtoken': keystone_conf} - cred = utils.get_os_client() - osclient_object = isinstance(cred, OSClient) - self.assertEqual(osclient_object, True, '') diff --git a/tests/unit/evacuattors/__init__.py b/tests/unit/evacuattors/__init__.py deleted file mode 100644 index f920945..0000000 --- a/tests/unit/evacuattors/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'saad' diff --git a/tests/unit/fencers/__init__.py b/tests/unit/fencers/__init__.py deleted file mode 100644 index f920945..0000000 --- a/tests/unit/fencers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'saad' diff --git a/tests/unit/monitors/__init__.py b/tests/unit/monitors/__init__.py deleted file mode 100644 index f920945..0000000 --- a/tests/unit/monitors/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'saad' diff --git a/tests/unit/notifiers/__init__.py b/tests/unit/notifiers/__init__.py deleted file mode 100644 index f920945..0000000 --- a/tests/unit/notifiers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'saad' diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 132f4e8..0000000 --- a/tox.ini +++ /dev/null @@ -1,66 +0,0 @@ -[tox] -minversion = 2.0 -envlist =py39,py38, pep8,pylint,docs -skipsdist = True - -[testenv] -basepython = python3 -usedevelop = True -deps = - -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} - -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -passenv = - http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY -setenv = - VIRTUAL_ENV={envdir} - OS_TEST_PATH = ./tests/unit -commands = - find . -type f -name "*.pyc" -delete - stestr run {posargs} - rm -f .coverage - rm -rf .testrepository - -whitelist_externals = - find - coverage - rm -python_files = test_*.py -norecursedirs = .tox .venv - -[testenv:venv] -commands = {posargs} - -[testenv:docs] -commands = - sphinx-build -W -b html doc/source doc/build/html - -[testenv:py39] -basepython = python3.9 - -[testenv:py38] -basepython = python3.8 - -[testenv:pep8] -commands = flake8 freezer_dr - -[testenv:pylint] -commands = pylint --rcfile .pylintrc freezer_dr - -[testenv:genconfig] -sitepackages = False -envdir = {toxworkdir}/venv -commands = - oslo-config-generator --config-file=config-generator/freezer-dr.conf - -[flake8] -# it's not a bug that we aren't using all of hacking -# H102 -> apache2 license exists -# H103 -> license is apache -# H201 -> no bare excepts -# H501 -> don't use locals() for str formatting -# H903 -> \n not \r\n -ignore = H -select = H102, H103, H201, H501, H903, H201, H306, H301, H233 -show-source = True -exclude = .venv,.tox,dist,doc,test,*egg,tests \ No newline at end of file