Retire stackforge/warm
This commit is contained in:
parent
2a8fddd51a
commit
52656b254c
40
.gitignore
vendored
40
.gitignore
vendored
@ -1,40 +0,0 @@
|
|||||||
*.py[cod]
|
|
||||||
*.log
|
|
||||||
*.pem
|
|
||||||
*.DS_Store
|
|
||||||
*.egg*
|
|
||||||
*.log
|
|
||||||
*.mo
|
|
||||||
*.pyc
|
|
||||||
*.swo
|
|
||||||
*.swp
|
|
||||||
*.sqlite
|
|
||||||
*~
|
|
||||||
.autogenerated
|
|
||||||
.coverage
|
|
||||||
.nova-venv
|
|
||||||
.project
|
|
||||||
.pydevproject
|
|
||||||
.ropeproject
|
|
||||||
.testrepository/
|
|
||||||
.tox
|
|
||||||
.idea
|
|
||||||
.venv
|
|
||||||
AUTHORS
|
|
||||||
Authors
|
|
||||||
build-stamp
|
|
||||||
build/*
|
|
||||||
CA/
|
|
||||||
ChangeLog
|
|
||||||
coverage.xml
|
|
||||||
cover/*
|
|
||||||
covhtml
|
|
||||||
dist/*
|
|
||||||
doc/source/api/*
|
|
||||||
doc/build/*
|
|
||||||
instances
|
|
||||||
keeper
|
|
||||||
keys
|
|
||||||
local_settings.py
|
|
||||||
MANIFEST
|
|
||||||
nosetests.xml
|
|
@ -1,4 +0,0 @@
|
|||||||
[gerrit]
|
|
||||||
host=review.openstack.org
|
|
||||||
port=29418
|
|
||||||
project=stackforge/warm.git
|
|
@ -1,4 +0,0 @@
|
|||||||
[DEFAULT]
|
|
||||||
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} ${PYTHON:-python} -m subunit.run discover -t ./ ./ $LISTOPT $IDOPTION
|
|
||||||
test_id_option=--load-list $IDFILE
|
|
||||||
test_list_option=--list
|
|
37
HACKING.rst
37
HACKING.rst
@ -1,37 +0,0 @@
|
|||||||
Warm Style Commandments
|
|
||||||
=======================
|
|
||||||
|
|
||||||
- Step 1: Read the OpenStack Style Commandments
|
|
||||||
http://docs.openstack.org/developer/hacking/
|
|
||||||
- Step 2: Read on
|
|
||||||
|
|
||||||
Creating Unit Tests
|
|
||||||
-------------------
|
|
||||||
For every new feature, unit tests should be created that both test and
|
|
||||||
(implicitly) document the usage of said feature. If submitting a patch for a
|
|
||||||
bug that had no unit test, a new passing unit test should be added. If a
|
|
||||||
submitted bug fix does have a unit test, be sure to add a new one that fails
|
|
||||||
without the patch and passes with the patch.
|
|
||||||
|
|
||||||
Running Tests
|
|
||||||
-------------
|
|
||||||
The testing system is based on a combination of tox and testr. The canonical
|
|
||||||
approach to running tests is to simply run the command ``tox``. This will
|
|
||||||
create virtual environments, populate them with dependencies and run all of
|
|
||||||
the tests that OpenStack CI systems run. Behind the scenes, tox is running
|
|
||||||
``testr run --parallel``, but is set up such that you can supply any additional
|
|
||||||
testr arguments that are needed to tox. For example, you can run:
|
|
||||||
``tox -- --analyze-isolation`` to cause tox to tell testr to add
|
|
||||||
--analyze-isolation to its argument list.
|
|
||||||
|
|
||||||
It is also possible to run the tests inside of a virtual environment
|
|
||||||
you have created, or it is possible that you have all of the dependencies
|
|
||||||
installed locally already. In this case, you can interact with the testr
|
|
||||||
command directly. Running ``testr run`` will run the entire test suite. ``testr
|
|
||||||
run --parallel`` will run it in parallel (this is the default incantation tox
|
|
||||||
uses.) More information about testr can be found at:
|
|
||||||
http://wiki.openstack.org/testr
|
|
||||||
|
|
||||||
Note
|
|
||||||
----
|
|
||||||
This document is largely inspired from nova/HACKING.rst
|
|
176
LICENSE
176
LICENSE
@ -1,176 +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.
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
include AUTHORS
|
|
||||||
include ChangeLog
|
|
||||||
exclude .gitignore
|
|
||||||
exclude .gitreview
|
|
||||||
|
|
||||||
global-exclude *.pyc
|
|
64
README
64
README
@ -1,64 +0,0 @@
|
|||||||
Warm - To setup simple OpenStack environments from template
|
|
||||||
===========================================================
|
|
||||||
|
|
||||||
Warm exposes APIs on Yaml files to be reused. I's good tool to setup
|
|
||||||
small environement on OpenStack.
|
|
||||||
|
|
||||||
Please report me any bug or feature. I will be happy to work on it.
|
|
||||||
|
|
||||||
Note: Warm mixup names and ids, It does not recreate resource
|
|
||||||
already exists with a same name/id.
|
|
||||||
|
|
||||||
|
|
||||||
How to use it
|
|
||||||
=============
|
|
||||||
|
|
||||||
- To install Warm use pip (don't forget to check for dependances).
|
|
||||||
$ pip install warm
|
|
||||||
|
|
||||||
- We are assuming your env OS_* are already configured.
|
|
||||||
$ export | grep OS_
|
|
||||||
declare -x OS_AUTH_URL="https://identity/v2.0"
|
|
||||||
declare -x OS_PASSWORD="*******"
|
|
||||||
declare -x OS_TENANT_ID="ea262aa012f244f8af2d1687977aaa81"
|
|
||||||
declare -x OS_TENANT_NAME="my-project"
|
|
||||||
declare -x OS_USERNAME="sferdjaoui"
|
|
||||||
|
|
||||||
- You are now ready to create your first template.
|
|
||||||
$ cat > my-tpl.yaml <<EOF
|
|
||||||
server:
|
|
||||||
- name: srv
|
|
||||||
flavor: m1.small
|
|
||||||
image: cirros-0.3.1-x86_64-uec
|
|
||||||
EOF
|
|
||||||
|
|
||||||
- You can now run warm.
|
|
||||||
$ warm my-tpl.yaml
|
|
||||||
|
|
||||||
To get more information about a template syntax, see config.yaml.sample or
|
|
||||||
you can check the repositoy https://github.com/sahid/warm-templates to find
|
|
||||||
more examples.
|
|
||||||
|
|
||||||
|
|
||||||
Build Prerequisites
|
|
||||||
===================
|
|
||||||
|
|
||||||
debian-based
|
|
||||||
------------
|
|
||||||
|
|
||||||
The list of debian package dependencies can be found in deps.deb.txt:
|
|
||||||
|
|
||||||
$ sudo apt-get install `cat deps.deb.txt`
|
|
||||||
|
|
||||||
rpm-based
|
|
||||||
---------
|
|
||||||
|
|
||||||
The list of RPM package dependencies can be found in deps.rpm.txt:
|
|
||||||
|
|
||||||
$ sudo yum install `cat deps.rpm.txt`
|
|
||||||
|
|
||||||
|
|
||||||
Roadmap
|
|
||||||
=======
|
|
||||||
Add floating-ip
|
|
||||||
pylint, pep8
|
|
7
README.rst
Normal file
7
README.rst
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
This project is no longer maintained.
|
||||||
|
|
||||||
|
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".
|
||||||
|
|
@ -1,3 +0,0 @@
|
|||||||
python-dev
|
|
||||||
libffi-dev
|
|
||||||
libssl-dev
|
|
@ -1,3 +0,0 @@
|
|||||||
python-devel
|
|
||||||
libffi-devel
|
|
||||||
openssl-devel
|
|
@ -1,8 +0,0 @@
|
|||||||
[DEFAULT]
|
|
||||||
|
|
||||||
# The list of modules to copy from openstack-common
|
|
||||||
module=install_venv_common
|
|
||||||
module=test
|
|
||||||
|
|
||||||
# The base module to hold the copy of openstack.common
|
|
||||||
base=warm
|
|
@ -1,8 +0,0 @@
|
|||||||
pbr>=0.6,<1.0
|
|
||||||
six>=1.5.2
|
|
||||||
Babel>=1.3
|
|
||||||
requests>=1.1
|
|
||||||
PyYAML>=3.1.0
|
|
||||||
python-openstackclient==0.2.2
|
|
||||||
python-neutronclient>=2.3.4,<3
|
|
||||||
netaddr
|
|
164
run_tests.sh
164
run_tests.sh
@ -1,164 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
function usage {
|
|
||||||
echo "Usage: $0 [OPTION]..."
|
|
||||||
echo "Run python-novaclient test suite"
|
|
||||||
echo ""
|
|
||||||
echo " -V, --virtual-env Always use virtualenv. Install automatically if not present"
|
|
||||||
echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment"
|
|
||||||
echo " -s, --no-site-packages Isolate the virtualenv from the global Python environment"
|
|
||||||
echo " -x, --stop Stop running tests after the first error or failure."
|
|
||||||
echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added."
|
|
||||||
echo " -p, --pep8 Just run pep8"
|
|
||||||
echo " -P, --no-pep8 Don't run pep8"
|
|
||||||
echo " -c, --coverage Generate coverage report"
|
|
||||||
echo " -h, --help Print this usage message"
|
|
||||||
echo " --hide-elapsed Don't print the elapsed time for each test along with slow test list"
|
|
||||||
echo ""
|
|
||||||
echo "Note: with no options specified, the script will try to run the tests in a virtual environment,"
|
|
||||||
echo " If no virtualenv is found, the script will ask if you would like to create one. If you "
|
|
||||||
echo " prefer to run tests NOT in a virtual environment, simply pass the -N option."
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
|
|
||||||
function process_option {
|
|
||||||
case "$1" in
|
|
||||||
-h|--help) usage;;
|
|
||||||
-V|--virtual-env) always_venv=1; never_venv=0;;
|
|
||||||
-N|--no-virtual-env) always_venv=0; never_venv=1;;
|
|
||||||
-s|--no-site-packages) no_site_packages=1;;
|
|
||||||
-f|--force) force=1;;
|
|
||||||
-p|--pep8) just_pep8=1;;
|
|
||||||
-P|--no-pep8) no_pep8=1;;
|
|
||||||
-c|--coverage) coverage=1;;
|
|
||||||
-*) testropts="$testropts $1";;
|
|
||||||
*) testrargs="$testrargs $1"
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
venv=.venv
|
|
||||||
with_venv=tools/with_venv.sh
|
|
||||||
always_venv=0
|
|
||||||
never_venv=0
|
|
||||||
force=0
|
|
||||||
no_site_packages=0
|
|
||||||
installvenvopts=
|
|
||||||
testrargs=
|
|
||||||
testropts=
|
|
||||||
wrapper=""
|
|
||||||
just_pep8=0
|
|
||||||
no_pep8=0
|
|
||||||
coverage=0
|
|
||||||
|
|
||||||
LANG=en_US.UTF-8
|
|
||||||
LANGUAGE=en_US:en
|
|
||||||
LC_ALL=C
|
|
||||||
|
|
||||||
for arg in "$@"; do
|
|
||||||
process_option $arg
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $no_site_packages -eq 1 ]; then
|
|
||||||
installvenvopts="--no-site-packages"
|
|
||||||
fi
|
|
||||||
|
|
||||||
function init_testr {
|
|
||||||
if [ ! -d .testrepository ]; then
|
|
||||||
${wrapper} testr init
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_tests {
|
|
||||||
# Cleanup *pyc
|
|
||||||
${wrapper} find . -type f -name "*.pyc" -delete
|
|
||||||
|
|
||||||
if [ $coverage -eq 1 ]; then
|
|
||||||
# Do not test test_coverage_ext when gathering coverage.
|
|
||||||
if [ "x$testrargs" = "x" ]; then
|
|
||||||
testrargs="^(?!.*test_coverage_ext).*$"
|
|
||||||
fi
|
|
||||||
export PYTHON="${wrapper} coverage run --source novaclient --parallel-mode"
|
|
||||||
fi
|
|
||||||
# Just run the test suites in current environment
|
|
||||||
set +e
|
|
||||||
TESTRTESTS="$TESTRTESTS $testrargs"
|
|
||||||
echo "Running \`${wrapper} $TESTRTESTS\`"
|
|
||||||
${wrapper} $TESTRTESTS
|
|
||||||
RESULT=$?
|
|
||||||
set -e
|
|
||||||
|
|
||||||
copy_subunit_log
|
|
||||||
|
|
||||||
return $RESULT
|
|
||||||
}
|
|
||||||
|
|
||||||
function copy_subunit_log {
|
|
||||||
LOGNAME=`cat .testrepository/next-stream`
|
|
||||||
LOGNAME=$(($LOGNAME - 1))
|
|
||||||
LOGNAME=".testrepository/${LOGNAME}"
|
|
||||||
cp $LOGNAME subunit.log
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_pep8 {
|
|
||||||
echo "Running flake8 ..."
|
|
||||||
${wrapper} flake8
|
|
||||||
}
|
|
||||||
|
|
||||||
TESTRTESTS="testr run --parallel $testropts"
|
|
||||||
|
|
||||||
if [ $never_venv -eq 0 ]
|
|
||||||
then
|
|
||||||
# Remove the virtual environment if --force used
|
|
||||||
if [ $force -eq 1 ]; then
|
|
||||||
echo "Cleaning virtualenv..."
|
|
||||||
rm -rf ${venv}
|
|
||||||
fi
|
|
||||||
if [ -e ${venv} ]; then
|
|
||||||
wrapper="${with_venv}"
|
|
||||||
else
|
|
||||||
if [ $always_venv -eq 1 ]; then
|
|
||||||
# Automatically install the virtualenv
|
|
||||||
python tools/install_venv.py $installvenvopts
|
|
||||||
wrapper="${with_venv}"
|
|
||||||
else
|
|
||||||
echo -e "No virtual environment found...create one? (Y/n) \c"
|
|
||||||
read use_ve
|
|
||||||
if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then
|
|
||||||
# Install the virtualenv and run the test suite in it
|
|
||||||
python tools/install_venv.py $installvenvopts
|
|
||||||
wrapper=${with_venv}
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Delete old coverage data from previous runs
|
|
||||||
if [ $coverage -eq 1 ]; then
|
|
||||||
${wrapper} coverage erase
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $just_pep8 -eq 1 ]; then
|
|
||||||
run_pep8
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
init_testr
|
|
||||||
run_tests
|
|
||||||
|
|
||||||
# NOTE(sirp): we only want to run pep8 when we're running the full-test suite,
|
|
||||||
# not when we're running tests individually. To handle this, we need to
|
|
||||||
# distinguish between options (noseopts), which begin with a '-', and
|
|
||||||
# arguments (testrargs).
|
|
||||||
if [ -z "$testrargs" ]; then
|
|
||||||
if [ $no_pep8 -eq 0 ]; then
|
|
||||||
run_pep8
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $coverage -eq 1 ]; then
|
|
||||||
echo "Generating coverage report in covhtml/"
|
|
||||||
${wrapper} coverage combine
|
|
||||||
${wrapper} coverage html --include='novaclient/*' --omit='novaclient/openstack/common/*' -d covhtml -i
|
|
||||||
fi
|
|
24
setup.cfg
24
setup.cfg
@ -1,24 +0,0 @@
|
|||||||
[metadata]
|
|
||||||
name = warm
|
|
||||||
summary = Deploy OpenStack resources from Yaml templates.
|
|
||||||
description-file =
|
|
||||||
README
|
|
||||||
author = Sahid Orentino Ferdjaoui
|
|
||||||
author-email = sahid.ferdjaoui@cloudwatt.com
|
|
||||||
home-page = https://wiki.openstack.org/wiki/Warm
|
|
||||||
classifier =
|
|
||||||
Environment :: OpenStack
|
|
||||||
License :: OSI Approved :: Apache Software License
|
|
||||||
Intended Audience :: Developers
|
|
||||||
Intended Audience :: System Administrators
|
|
||||||
Programming Language :: Python
|
|
||||||
Operating System :: MacOS :: MacOS X
|
|
||||||
Operating System :: POSIX :: Linux
|
|
||||||
|
|
||||||
[files]
|
|
||||||
packages =
|
|
||||||
warm
|
|
||||||
|
|
||||||
[entry_points]
|
|
||||||
console_scripts =
|
|
||||||
warm = warm:main
|
|
22
setup.py
22
setup.py
@ -1,22 +0,0 @@
|
|||||||
# Copyright 2013 Cloudwatt
|
|
||||||
#
|
|
||||||
# Author: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@cloudwatt.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.
|
|
||||||
#
|
|
||||||
|
|
||||||
import setuptools
|
|
||||||
|
|
||||||
setuptools.setup(
|
|
||||||
setup_requires=['pbr'],
|
|
||||||
pbr=True)
|
|
@ -1,103 +0,0 @@
|
|||||||
# A template use the YAML syntaxe.
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Authentification
|
|
||||||
# The program can read environement variables OS_*
|
|
||||||
###############################################################################
|
|
||||||
#username: demo
|
|
||||||
#password: ok
|
|
||||||
#project_name: demo
|
|
||||||
#auth_url: http://10.0.2.15:5000/v2.0
|
|
||||||
#region_name:
|
|
||||||
#path:
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Key
|
|
||||||
###############################################################################
|
|
||||||
#key:
|
|
||||||
#- name: demo
|
|
||||||
# path: .
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Volume
|
|
||||||
###############################################################################
|
|
||||||
#volume:
|
|
||||||
#- name: vol01
|
|
||||||
# size: 1
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Security Groups & Rules
|
|
||||||
###############################################################################
|
|
||||||
#securitygroup:
|
|
||||||
#- name: sec01
|
|
||||||
# description: my security group
|
|
||||||
# rules:
|
|
||||||
# - ip_protocol: tcp
|
|
||||||
# from_port: 22
|
|
||||||
# to_port: 22
|
|
||||||
# cidr: 0.0.0.0/23
|
|
||||||
#
|
|
||||||
#securitygrouprule:
|
|
||||||
#- group: sec01
|
|
||||||
# ip_protocol: tcp
|
|
||||||
# from_port: 22
|
|
||||||
# to_port: 22
|
|
||||||
# cidr: 0.0.0.0/23
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Server
|
|
||||||
###############################################################################
|
|
||||||
#server:
|
|
||||||
#- name: demo
|
|
||||||
# flavor: 1
|
|
||||||
# image: cirros-0.3.1-x86_64-uec
|
|
||||||
# volumes:
|
|
||||||
# - name: vol01
|
|
||||||
# device: /dev/sdh
|
|
||||||
# networks:
|
|
||||||
# - name: net01
|
|
||||||
# v4-fixed-ip: 10.123.2.25
|
|
||||||
# - name: net01
|
|
||||||
# v6-fixed-ip: dead:beef::25/64
|
|
||||||
# securitygroups: [demo, ]
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Network & SubNet
|
|
||||||
###############################################################################
|
|
||||||
#network:
|
|
||||||
#- name: net01
|
|
||||||
# subnets:
|
|
||||||
# - cidr: 10.123.2.0/24
|
|
||||||
# ip_version: 4
|
|
||||||
# host_routes:
|
|
||||||
# - destination: 0.0.0.0/0
|
|
||||||
# nexthop: 10.123.2.1
|
|
||||||
# - destination: 10.0.0.0/24
|
|
||||||
# nexthop: 10.123.2.2
|
|
||||||
#
|
|
||||||
#subnet:
|
|
||||||
#- network: net01
|
|
||||||
# name: sub01
|
|
||||||
# cidr: 10.123.2.0/24
|
|
||||||
# ip_version: 4
|
|
||||||
# host_routes:
|
|
||||||
# - destination: 10.0.0.0/24
|
|
||||||
# nexthop: 10.123.2.2
|
|
||||||
#- network: net01
|
|
||||||
# name: sub02
|
|
||||||
# cidr: dead:beef::/64
|
|
||||||
# ip_version: 6
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Router
|
|
||||||
###############################################################################
|
|
||||||
#router:
|
|
||||||
#- name: router01
|
|
||||||
# interfaces:
|
|
||||||
# - name: interface01
|
|
||||||
# subnet: sub01
|
|
||||||
# gateways:
|
|
||||||
# - name: gate01
|
|
||||||
# network: net01
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
hacking>=0.8.0,<0.9
|
|
||||||
mock>=1.0
|
|
||||||
testrepository>=0.0.18
|
|
||||||
testtools>=0.9.32
|
|
@ -1,74 +0,0 @@
|
|||||||
# Copyright 2010 United States Government as represented by the
|
|
||||||
# Administrator of the National Aeronautics and Space Administration.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Copyright 2010 OpenStack Foundation
|
|
||||||
# Copyright 2013 IBM Corp.
|
|
||||||
# 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 ConfigParser
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import install_venv_common as install_venv # flake8: noqa
|
|
||||||
|
|
||||||
|
|
||||||
def print_help(project, venv, root):
|
|
||||||
help = """
|
|
||||||
%(project)s development environment setup is complete.
|
|
||||||
|
|
||||||
%(project)s development uses virtualenv to track and manage Python
|
|
||||||
dependencies while in development and testing.
|
|
||||||
|
|
||||||
To activate the %(project)s virtualenv for the extent of your current
|
|
||||||
shell session you can run:
|
|
||||||
|
|
||||||
$ source %(venv)s/bin/activate
|
|
||||||
|
|
||||||
Or, if you prefer, you can run commands in the virtualenv on a case by
|
|
||||||
case basis by running:
|
|
||||||
|
|
||||||
$ %(root)s/tools/with_venv.sh <your command>
|
|
||||||
"""
|
|
||||||
print help % dict(project=project, venv=venv, root=root)
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv):
|
|
||||||
root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
|
||||||
|
|
||||||
if os.environ.get('tools_path'):
|
|
||||||
root = os.environ['tools_path']
|
|
||||||
venv = os.path.join(root, '.venv')
|
|
||||||
if os.environ.get('venv'):
|
|
||||||
venv = os.environ['venv']
|
|
||||||
|
|
||||||
pip_requires = os.path.join(root, 'requirements.txt')
|
|
||||||
test_requires = os.path.join(root, 'test-requirements.txt')
|
|
||||||
py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
|
|
||||||
setup_cfg = ConfigParser.ConfigParser()
|
|
||||||
setup_cfg.read('setup.cfg')
|
|
||||||
project = setup_cfg.get('metadata', 'name')
|
|
||||||
|
|
||||||
install = install_venv.InstallVenv(
|
|
||||||
root, venv, pip_requires, test_requires, py_version, project)
|
|
||||||
options = install.parse_args(argv)
|
|
||||||
install.check_python_version()
|
|
||||||
install.check_dependencies()
|
|
||||||
install.create_virtualenv(no_site_packages=options.no_site_packages)
|
|
||||||
install.install_dependencies()
|
|
||||||
print_help(project, venv, root)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main(sys.argv)
|
|
@ -1,172 +0,0 @@
|
|||||||
# Copyright 2013 OpenStack Foundation
|
|
||||||
# Copyright 2013 IBM Corp.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""Provides methods needed by installation script for OpenStack development
|
|
||||||
virtual environments.
|
|
||||||
|
|
||||||
Since this script is used to bootstrap a virtualenv from the system's Python
|
|
||||||
environment, it should be kept strictly compatible with Python 2.6.
|
|
||||||
|
|
||||||
Synced in from openstack-common
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import optparse
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
class InstallVenv(object):
|
|
||||||
|
|
||||||
def __init__(self, root, venv, requirements,
|
|
||||||
test_requirements, py_version,
|
|
||||||
project):
|
|
||||||
self.root = root
|
|
||||||
self.venv = venv
|
|
||||||
self.requirements = requirements
|
|
||||||
self.test_requirements = test_requirements
|
|
||||||
self.py_version = py_version
|
|
||||||
self.project = project
|
|
||||||
|
|
||||||
def die(self, message, *args):
|
|
||||||
print(message % args, file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def check_python_version(self):
|
|
||||||
if sys.version_info < (2, 6):
|
|
||||||
self.die("Need Python Version >= 2.6")
|
|
||||||
|
|
||||||
def run_command_with_code(self, cmd, redirect_output=True,
|
|
||||||
check_exit_code=True):
|
|
||||||
"""Runs a command in an out-of-process shell.
|
|
||||||
|
|
||||||
Returns the output of that command. Working directory is self.root.
|
|
||||||
"""
|
|
||||||
if redirect_output:
|
|
||||||
stdout = subprocess.PIPE
|
|
||||||
else:
|
|
||||||
stdout = None
|
|
||||||
|
|
||||||
proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout)
|
|
||||||
output = proc.communicate()[0]
|
|
||||||
if check_exit_code and proc.returncode != 0:
|
|
||||||
self.die('Command "%s" failed.\n%s', ' '.join(cmd), output)
|
|
||||||
return (output, proc.returncode)
|
|
||||||
|
|
||||||
def run_command(self, cmd, redirect_output=True, check_exit_code=True):
|
|
||||||
return self.run_command_with_code(cmd, redirect_output,
|
|
||||||
check_exit_code)[0]
|
|
||||||
|
|
||||||
def get_distro(self):
|
|
||||||
if (os.path.exists('/etc/fedora-release') or
|
|
||||||
os.path.exists('/etc/redhat-release')):
|
|
||||||
return Fedora(
|
|
||||||
self.root, self.venv, self.requirements,
|
|
||||||
self.test_requirements, self.py_version, self.project)
|
|
||||||
else:
|
|
||||||
return Distro(
|
|
||||||
self.root, self.venv, self.requirements,
|
|
||||||
self.test_requirements, self.py_version, self.project)
|
|
||||||
|
|
||||||
def check_dependencies(self):
|
|
||||||
self.get_distro().install_virtualenv()
|
|
||||||
|
|
||||||
def create_virtualenv(self, no_site_packages=True):
|
|
||||||
"""Creates the virtual environment and installs PIP.
|
|
||||||
|
|
||||||
Creates the virtual environment and installs PIP only into the
|
|
||||||
virtual environment.
|
|
||||||
"""
|
|
||||||
if not os.path.isdir(self.venv):
|
|
||||||
print('Creating venv...', end=' ')
|
|
||||||
if no_site_packages:
|
|
||||||
self.run_command(['virtualenv', '-q', '--no-site-packages',
|
|
||||||
self.venv])
|
|
||||||
else:
|
|
||||||
self.run_command(['virtualenv', '-q', self.venv])
|
|
||||||
print('done.')
|
|
||||||
else:
|
|
||||||
print("venv already exists...")
|
|
||||||
pass
|
|
||||||
|
|
||||||
def pip_install(self, *args):
|
|
||||||
self.run_command(['tools/with_venv.sh',
|
|
||||||
'pip', 'install', '--upgrade'] + list(args),
|
|
||||||
redirect_output=False)
|
|
||||||
|
|
||||||
def install_dependencies(self):
|
|
||||||
print('Installing dependencies with pip (this can take a while)...')
|
|
||||||
|
|
||||||
# First things first, make sure our venv has the latest pip and
|
|
||||||
# setuptools and pbr
|
|
||||||
self.pip_install('pip>=1.4')
|
|
||||||
self.pip_install('setuptools')
|
|
||||||
self.pip_install('pbr')
|
|
||||||
|
|
||||||
self.pip_install('-r', self.requirements, '-r', self.test_requirements)
|
|
||||||
|
|
||||||
def parse_args(self, argv):
|
|
||||||
"""Parses command-line arguments."""
|
|
||||||
parser = optparse.OptionParser()
|
|
||||||
parser.add_option('-n', '--no-site-packages',
|
|
||||||
action='store_true',
|
|
||||||
help="Do not inherit packages from global Python "
|
|
||||||
"install")
|
|
||||||
return parser.parse_args(argv[1:])[0]
|
|
||||||
|
|
||||||
|
|
||||||
class Distro(InstallVenv):
|
|
||||||
|
|
||||||
def check_cmd(self, cmd):
|
|
||||||
return bool(self.run_command(['which', cmd],
|
|
||||||
check_exit_code=False).strip())
|
|
||||||
|
|
||||||
def install_virtualenv(self):
|
|
||||||
if self.check_cmd('virtualenv'):
|
|
||||||
return
|
|
||||||
|
|
||||||
if self.check_cmd('easy_install'):
|
|
||||||
print('Installing virtualenv via easy_install...', end=' ')
|
|
||||||
if self.run_command(['easy_install', 'virtualenv']):
|
|
||||||
print('Succeeded')
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
print('Failed')
|
|
||||||
|
|
||||||
self.die('ERROR: virtualenv not found.\n\n%s development'
|
|
||||||
' requires virtualenv, please install it using your'
|
|
||||||
' favorite package management tool' % self.project)
|
|
||||||
|
|
||||||
|
|
||||||
class Fedora(Distro):
|
|
||||||
"""This covers all Fedora-based distributions.
|
|
||||||
|
|
||||||
Includes: Fedora, RHEL, CentOS, Scientific Linux
|
|
||||||
"""
|
|
||||||
|
|
||||||
def check_pkg(self, pkg):
|
|
||||||
return self.run_command_with_code(['rpm', '-q', pkg],
|
|
||||||
check_exit_code=False)[1] == 0
|
|
||||||
|
|
||||||
def install_virtualenv(self):
|
|
||||||
if self.check_cmd('virtualenv'):
|
|
||||||
return
|
|
||||||
|
|
||||||
if not self.check_pkg('python-virtualenv'):
|
|
||||||
self.die("Please install 'python-virtualenv'.")
|
|
||||||
|
|
||||||
super(Fedora, self).install_virtualenv()
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
TOOLS=`dirname $0`
|
|
||||||
VENV=$TOOLS/../.venv
|
|
||||||
source $VENV/bin/activate && $@
|
|
30
tox.ini
30
tox.ini
@ -1,30 +0,0 @@
|
|||||||
[tox]
|
|
||||||
envlist = py26,py27,py33,pypy,pep8
|
|
||||||
minversion = 1.6
|
|
||||||
skipsdist = True
|
|
||||||
|
|
||||||
[testenv]
|
|
||||||
usedevelop = True
|
|
||||||
install_command = pip install -U {opts} {packages}
|
|
||||||
setenv = VIRTUAL_ENV={envdir}
|
|
||||||
|
|
||||||
deps = -r{toxinidir}/requirements.txt
|
|
||||||
-r{toxinidir}/test-requirements.txt
|
|
||||||
commands = python setup.py testr --testr-args='{posargs}'
|
|
||||||
|
|
||||||
[testenv:pep8]
|
|
||||||
commands = flake8
|
|
||||||
|
|
||||||
[testenv:venv]
|
|
||||||
commands = {posargs}
|
|
||||||
|
|
||||||
[testenv:cover]
|
|
||||||
commands = python setup.py testr --coverage --testr-args='{posargs}'
|
|
||||||
|
|
||||||
[tox:jenkins]
|
|
||||||
downloadcache = ~/cache/pip
|
|
||||||
|
|
||||||
[flake8]
|
|
||||||
ignore = E12,F841,F811,F821,H302,H404
|
|
||||||
show-source = True
|
|
||||||
exclude=.venv,.git,.tox,dist,*openstack/common*,*lib/python*,*egg,build
|
|
152
warm/__init__.py
152
warm/__init__.py
@ -1,152 +0,0 @@
|
|||||||
# Copyright 2013 Cloudwatt
|
|
||||||
#
|
|
||||||
# Author: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@cloudwatt.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.
|
|
||||||
|
|
||||||
"""The main script of the project."""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import optparse
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
from neutronclient.neutron import client as neutron
|
|
||||||
from openstackclient.common import clientmanager
|
|
||||||
|
|
||||||
from warm import components
|
|
||||||
from warm import version
|
|
||||||
|
|
||||||
DEFAULT_LOGFILE = "/dev/null"
|
|
||||||
DEFAULT_LOGLEVEL = logging.DEBUG
|
|
||||||
DEFAULT_COMPUTE_API_VERSION = '2'
|
|
||||||
DEFAULT_IDENTITY_API_VERSION = '2.0'
|
|
||||||
DEFAULT_IMAGE_API_VERSION = '2'
|
|
||||||
DEFAULT_OBJECT_API_VERSION = '1'
|
|
||||||
DEFAULT_VOLUME_API_VERSION = '1'
|
|
||||||
DEFAULT_DOMAIN = 'default'
|
|
||||||
DEFAULT_KEY_NAME = 'warmkey'
|
|
||||||
|
|
||||||
OS_USERNAME = os.getenv("OS_USERNAME")
|
|
||||||
OS_PASSWORD = os.getenv("OS_PASSWORD")
|
|
||||||
OS_TENANT_NAME = os.getenv("OS_TENANT_NAME")
|
|
||||||
OS_AUTH_URL = os.getenv("OS_AUTH_URL")
|
|
||||||
|
|
||||||
USAGE = "usage: %prog <template> [options]"
|
|
||||||
|
|
||||||
|
|
||||||
class Agent(object):
|
|
||||||
def __init__(self, **options):
|
|
||||||
self.options = options
|
|
||||||
|
|
||||||
self.api_version = {
|
|
||||||
'compute': self.options.get(
|
|
||||||
"compute_api_version", DEFAULT_COMPUTE_API_VERSION),
|
|
||||||
'identity': self.options.get(
|
|
||||||
"identity_api_version", DEFAULT_IDENTITY_API_VERSION),
|
|
||||||
'image': self.options.get(
|
|
||||||
"image_api_version", DEFAULT_IMAGE_API_VERSION),
|
|
||||||
'object-store': self.options.get(
|
|
||||||
"object_api_version", DEFAULT_OBJECT_API_VERSION),
|
|
||||||
'volume': self.options.get(
|
|
||||||
"volume_api_version", DEFAULT_VOLUME_API_VERSION)}
|
|
||||||
|
|
||||||
self.client = clientmanager.ClientManager(
|
|
||||||
token=self.options.get("token"),
|
|
||||||
url=self.options.get("url"),
|
|
||||||
auth_url=self.options.get("auth_url", OS_AUTH_URL),
|
|
||||||
project_name=self.options.get("project_name", OS_TENANT_NAME),
|
|
||||||
project_id=self.options.get("project_id"),
|
|
||||||
username=self.options.get("username", OS_USERNAME),
|
|
||||||
password=self.options.get("password", OS_PASSWORD),
|
|
||||||
region_name=self.options.get("region_name"),
|
|
||||||
api_version=self.api_version)
|
|
||||||
|
|
||||||
self.clientneutron = neutron.Client(
|
|
||||||
token=self.options.get("token"),
|
|
||||||
username=self.options.get("username", OS_USERNAME),
|
|
||||||
password=self.options.get("password", OS_PASSWORD),
|
|
||||||
tenant_name=self.options.get("project_name", OS_TENANT_NAME),
|
|
||||||
auth_url=self.options.get("auth_url", OS_AUTH_URL),
|
|
||||||
region_name=self.options.get("region_name"),
|
|
||||||
insecure=self.options.get("insecure", True),
|
|
||||||
api_version=self.options.get("api_version", "2.0"))
|
|
||||||
|
|
||||||
def _InitKeypairs(self):
|
|
||||||
logging.info("Initializing keypairs...")
|
|
||||||
self.key_name = self.options.get("key_name", DEFAULT_KEY_NAME)
|
|
||||||
try:
|
|
||||||
self.client.compute.keypairs.delete(self.key_name)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
key = self.client.compute.keypairs.create(self.key_name)
|
|
||||||
f = open("%s.pem" % self.key_name, 'w')
|
|
||||||
f.write(key.private_key)
|
|
||||||
f.close
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = optparse.OptionParser(usage=USAGE)
|
|
||||||
parser.add_option("-V", "--verbose",
|
|
||||||
dest="verbose",
|
|
||||||
action="store_true",
|
|
||||||
help="Be more verbose.",
|
|
||||||
default=False)
|
|
||||||
parser.add_option("-v", "--version",
|
|
||||||
dest="version",
|
|
||||||
action="store_true",
|
|
||||||
help="Print the current version used.",
|
|
||||||
default=False)
|
|
||||||
(options, args) = parser.parse_args()
|
|
||||||
|
|
||||||
verbose = getattr(options, "verbose")
|
|
||||||
out = DEFAULT_LOGFILE
|
|
||||||
if verbose:
|
|
||||||
out = "/dev/stdout"
|
|
||||||
logging.basicConfig(filename=out, level=DEFAULT_LOGLEVEL)
|
|
||||||
|
|
||||||
if getattr(options, "version"):
|
|
||||||
print(version.__version__)
|
|
||||||
exit()
|
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
parser.print_help()
|
|
||||||
exit()
|
|
||||||
|
|
||||||
stream = file(sys.argv[1])
|
|
||||||
config = yaml.load(stream)
|
|
||||||
|
|
||||||
agent = Agent(**config)
|
|
||||||
|
|
||||||
for key, cls in CLASS_MAPPING:
|
|
||||||
if key in config:
|
|
||||||
logging.debug("Some %s configurations found, "
|
|
||||||
"work in progress..." % key)
|
|
||||||
for cfg in config[key]:
|
|
||||||
getattr(components, cls)(agent)(**cfg)
|
|
||||||
|
|
||||||
|
|
||||||
CLASS_MAPPING = [
|
|
||||||
("key", "Key"),
|
|
||||||
("volume", "Volume"),
|
|
||||||
("network", "Network"),
|
|
||||||
("subnet", "SubNet"),
|
|
||||||
("router", "Router"),
|
|
||||||
("securitygroup", "SecurityGroup"),
|
|
||||||
("securitygrouprule", "SecurityGroupRule"),
|
|
||||||
("server", "Server"),
|
|
||||||
]
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,470 +0,0 @@
|
|||||||
# Copyright 2013 Cloudwatt
|
|
||||||
#
|
|
||||||
# Author: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@cloudwatt.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.
|
|
||||||
|
|
||||||
"""Tests."""
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from netaddr import AddrFormatError
|
|
||||||
from netaddr import IPAddress
|
|
||||||
from neutronclient.common import exceptions as neutron_exc
|
|
||||||
from neutronclient.neutron import v2_0 as neutronV20
|
|
||||||
from novaclient import exceptions as nova_exc
|
|
||||||
from openstackclient.common import exceptions
|
|
||||||
from openstackclient.common import utils
|
|
||||||
|
|
||||||
import warm.utils
|
|
||||||
|
|
||||||
|
|
||||||
class Base(object):
|
|
||||||
"""Base class for a component."""
|
|
||||||
def __init__(self, agent, ref=None):
|
|
||||||
self._agent = agent
|
|
||||||
self._ref = ref
|
|
||||||
|
|
||||||
def find(self, id_or_name, ref_only=False):
|
|
||||||
service = None
|
|
||||||
ref = None
|
|
||||||
if isinstance(self, Key):
|
|
||||||
service = self._agent.client.compute.keypairs
|
|
||||||
if isinstance(self, Image):
|
|
||||||
service = self._agent.client.compute.images
|
|
||||||
elif isinstance(self, Server):
|
|
||||||
service = self._agent.client.compute.servers
|
|
||||||
elif isinstance(self, Flavor):
|
|
||||||
service = self._agent.client.compute.flavors
|
|
||||||
elif isinstance(self, Volume):
|
|
||||||
service = self._agent.client.volume.volumes
|
|
||||||
elif isinstance(self, SecurityGroup):
|
|
||||||
service = self._agent.client.compute.security_groups
|
|
||||||
elif isinstance(self, Network):
|
|
||||||
service = self._agent.client.compute.networks
|
|
||||||
elif isinstance(self, SubNet):
|
|
||||||
sid = neutronV20.find_resourceid_by_name_or_id(
|
|
||||||
self._agent.clientneutron, "subnet", id_or_name)
|
|
||||||
ref = self._agent.clientneutron.show_subnet(sid)
|
|
||||||
elif isinstance(self, Router):
|
|
||||||
rid = neutronV20.find_resourceid_by_name_or_id(
|
|
||||||
self._agent.clientneutron, "router", id_or_name)
|
|
||||||
ref = self._agent.clientneutron.show_router(rid)
|
|
||||||
|
|
||||||
if service:
|
|
||||||
ref = utils.find_resource(service, id_or_name)
|
|
||||||
if ref_only:
|
|
||||||
return ref
|
|
||||||
self._ref = ref
|
|
||||||
return self
|
|
||||||
|
|
||||||
def wait_for_ready(self, field="status", success=("available", "active")):
|
|
||||||
if isinstance(self, Image):
|
|
||||||
service = self._agent.client.compute.images
|
|
||||||
elif isinstance(self, Server):
|
|
||||||
service = self._agent.client.compute.servers
|
|
||||||
elif isinstance(self, Flavor):
|
|
||||||
service = self._agent.client.compute.flavors
|
|
||||||
elif isinstance(self, Volume):
|
|
||||||
service = self._agent.client.volume.volumes
|
|
||||||
|
|
||||||
utils.wait_for_status(service.get,
|
|
||||||
self.id,
|
|
||||||
sleep_time=1,
|
|
||||||
success_status=success,
|
|
||||||
status_field=field)
|
|
||||||
|
|
||||||
def delete(self):
|
|
||||||
if not self._ref:
|
|
||||||
raise Exception("This component is not initialize yet.")
|
|
||||||
return self._Delete()
|
|
||||||
|
|
||||||
def _Execute(self, options):
|
|
||||||
raise NotImplemented("This method needs to be implemented.")
|
|
||||||
|
|
||||||
def _Delete(self):
|
|
||||||
return self._ref.delete()
|
|
||||||
|
|
||||||
def _PostExecute(self, options):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _Id(self):
|
|
||||||
return self._ref.id
|
|
||||||
|
|
||||||
def _Name(self):
|
|
||||||
return self._ref.name
|
|
||||||
|
|
||||||
def __call__(self, **options):
|
|
||||||
try:
|
|
||||||
if options.get("name"):
|
|
||||||
self._ref = self.find(options.get("name"), ref_only=True)
|
|
||||||
except (exceptions.CommandError, neutron_exc.NeutronClientException):
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
if not self._ref:
|
|
||||||
self._ref = self._Execute(options)
|
|
||||||
self._PostExecute(options)
|
|
||||||
return self
|
|
||||||
|
|
||||||
@property
|
|
||||||
def id(self):
|
|
||||||
if not self._ref:
|
|
||||||
raise Exception("This component is not initialize yet.")
|
|
||||||
return self._Id()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
if not self._ref:
|
|
||||||
raise Exception("This component is not initialize yet.")
|
|
||||||
return self._Name()
|
|
||||||
|
|
||||||
|
|
||||||
class Key(Base):
|
|
||||||
"""Handles keypairs operations."""
|
|
||||||
def _Execute(self, options):
|
|
||||||
whitelist = dict(
|
|
||||||
name=options["name"],
|
|
||||||
path=options.get("path", "."))
|
|
||||||
try:
|
|
||||||
key = self.find(whitelist["name"])
|
|
||||||
except exceptions.CommandError:
|
|
||||||
key = self._agent.client.compute.keypairs.create(whitelist["name"])
|
|
||||||
f = open("%(path)s/%(name)s.pem" % whitelist, 'w')
|
|
||||||
f.write(key.private_key)
|
|
||||||
f.close
|
|
||||||
return key
|
|
||||||
|
|
||||||
|
|
||||||
class Image(Base):
|
|
||||||
"""Handles image operations."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Flavor(Base):
|
|
||||||
"""Handles flavor operations."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Volume(Base):
|
|
||||||
"""Handles volume operations."""
|
|
||||||
def _Execute(self, options):
|
|
||||||
whitelist = dict(
|
|
||||||
size=options["size"],
|
|
||||||
display_name=options.get("name", ""))
|
|
||||||
return self._agent.client.volume.volumes.create(**whitelist)
|
|
||||||
|
|
||||||
def _Name(self):
|
|
||||||
return self._ref.display_name
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroup(Base):
|
|
||||||
def _Execute(self, options):
|
|
||||||
"""Handles security groups operations."""
|
|
||||||
whitelist = dict(
|
|
||||||
name=options["name"],
|
|
||||||
description=options.get("description", "<empty>"))
|
|
||||||
return self._agent.client.compute.security_groups.create(**whitelist)
|
|
||||||
|
|
||||||
def _PostExecute(self, options):
|
|
||||||
if "rules" in options:
|
|
||||||
for rule_opt in options["rules"]:
|
|
||||||
self.Rule(**rule_opt)
|
|
||||||
|
|
||||||
def Rule(self, **options):
|
|
||||||
options["group"] = self.id
|
|
||||||
SecurityGroupRule(self._agent)(**options)
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupRule(Base):
|
|
||||||
def _Execute(self, options):
|
|
||||||
parent = SecurityGroup(self._agent).find(options["group"])
|
|
||||||
group_id = None
|
|
||||||
if "secgroup" in options:
|
|
||||||
group = SecurityGroup(self._agent).find(options["secgroup"])
|
|
||||||
if group:
|
|
||||||
group_id = group.id
|
|
||||||
whitelist = dict(
|
|
||||||
parent_group_id=parent.id,
|
|
||||||
ip_protocol=options.get("ip_protocol"),
|
|
||||||
from_port=options.get("from_port"),
|
|
||||||
to_port=options.get("to_port"),
|
|
||||||
cidr=options.get("cidr"),
|
|
||||||
group_id=group_id)
|
|
||||||
try:
|
|
||||||
return self._agent.client.compute.security_group_rules.create(
|
|
||||||
**whitelist)
|
|
||||||
except (nova_exc.BadRequest, nova_exc.OverLimit):
|
|
||||||
# BUG(sahid): How to find a rule?,
|
|
||||||
# if the rule already exists, exception OverLimit...
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Server(Base):
|
|
||||||
"""Handle server (instance) operations."""
|
|
||||||
def _Execute(self, options):
|
|
||||||
image = Image(self._agent).find(options.get("image"))
|
|
||||||
flavor = Flavor(self._agent).find(options.get("flavor"))
|
|
||||||
|
|
||||||
secgrps = []
|
|
||||||
for name in options.get("securitygroups", []):
|
|
||||||
secgrp = SecurityGroup(self._agent).find(name)
|
|
||||||
secgrps.append(secgrp.id)
|
|
||||||
|
|
||||||
networks = []
|
|
||||||
for obj in options.get("networks", []):
|
|
||||||
net = Network(self._agent).find(obj["name"])
|
|
||||||
ipv4_addr = None
|
|
||||||
ipv6_addr = None
|
|
||||||
if obj.get("fixed_ip"):
|
|
||||||
# Note(ethuleau): keep 'fixed_ip' attribute for compatibility
|
|
||||||
try:
|
|
||||||
ip_addr = IPAddress(obj.get("fixed_ip"))
|
|
||||||
except AddrFormatError:
|
|
||||||
raise Exception("Invalid IP address: %s",
|
|
||||||
obj.get("fixed_ip"))
|
|
||||||
if ip_addr.version == 4:
|
|
||||||
ipv4_addr = str(ip_addr)
|
|
||||||
else:
|
|
||||||
ipv6_addr = str(ip_addr)
|
|
||||||
if obj.get("v4-fixed-ip"):
|
|
||||||
ipv4_addr = obj.get("v4-fixed-ip")
|
|
||||||
if obj.get("v6-fixed-ip"):
|
|
||||||
ipv6_addr = obj.get("v6-fixed-ip")
|
|
||||||
# Note(ethuleau): keep 'port' attribute for compatibility
|
|
||||||
port_id = obj.get("port")
|
|
||||||
if obj.get("port-id"):
|
|
||||||
port_id = obj.get("port-id")
|
|
||||||
networks.append({
|
|
||||||
"net-id": net.id,
|
|
||||||
"v4-fixed-ip": ipv4_addr,
|
|
||||||
"v6-fixed-ip": ipv6_addr,
|
|
||||||
"port-id": port_id})
|
|
||||||
|
|
||||||
userdata = None
|
|
||||||
if "userdata" in options:
|
|
||||||
tmpfile = "/tmp/%s" % uuid.uuid1()
|
|
||||||
content = warm.utils.multipart_content(*options["userdata"])
|
|
||||||
with open(tmpfile, "w+") as output:
|
|
||||||
output.write(content)
|
|
||||||
userdata = file(tmpfile)
|
|
||||||
|
|
||||||
whitelist = dict(
|
|
||||||
name=options.get("name"),
|
|
||||||
image=image.id,
|
|
||||||
flavor=flavor.id,
|
|
||||||
security_groups=secgrps,
|
|
||||||
nics=networks,
|
|
||||||
userdata=userdata,
|
|
||||||
availability_zone=options.get("availability_zone"),
|
|
||||||
key_name=options.get("key"),
|
|
||||||
min_count=options.get("min_count"),
|
|
||||||
max_count=options.get("max_count"))
|
|
||||||
return self._agent.client.compute.servers.create(**whitelist)
|
|
||||||
|
|
||||||
def _PostExecute(self, options):
|
|
||||||
if "volumes" in options:
|
|
||||||
self.wait_for_ready()
|
|
||||||
for volume_opt in options["volumes"]:
|
|
||||||
self.Mount(**volume_opt)
|
|
||||||
|
|
||||||
def Mount(self, **options):
|
|
||||||
volume = Volume(self._agent).find(options["name"])
|
|
||||||
volume.wait_for_ready()
|
|
||||||
whitelist = dict(
|
|
||||||
server_id=self.id,
|
|
||||||
volume_id=volume.id,
|
|
||||||
device=options["device"])
|
|
||||||
self._agent.client.compute.volumes.create_server_volume(**whitelist)
|
|
||||||
|
|
||||||
|
|
||||||
class Network(Base):
|
|
||||||
def _Execute(self, options):
|
|
||||||
whitelist = dict(
|
|
||||||
name=options["name"],
|
|
||||||
admin_state_up=options.get("admin_state_up", True))
|
|
||||||
body = {"network": whitelist}
|
|
||||||
#TODO(sahid): Needs to use client.
|
|
||||||
return self._agent.clientneutron.create_network(body)
|
|
||||||
|
|
||||||
def _PostExecute(self, options):
|
|
||||||
if "subnets" in options:
|
|
||||||
for cfg in options["subnets"]:
|
|
||||||
self.AttachSubNet(cfg)
|
|
||||||
|
|
||||||
def AttachSubNet(self, options):
|
|
||||||
options["network"] = self.id
|
|
||||||
SubNet(self._agent)(**options)
|
|
||||||
|
|
||||||
def _Id(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._ref["network"]["id"]
|
|
||||||
return self._ref.id
|
|
||||||
|
|
||||||
def _Name(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._ref["network"]["name"]
|
|
||||||
return self._ref.name
|
|
||||||
|
|
||||||
def _Delete(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._agent.clientneutron.delete_network(self.id)
|
|
||||||
return self.delete()
|
|
||||||
|
|
||||||
|
|
||||||
class SubNet(Base):
|
|
||||||
def _Execute(self, options):
|
|
||||||
host_routes = []
|
|
||||||
for obj in options.get("host_routes", []):
|
|
||||||
host_routes.append({
|
|
||||||
"destination": obj.get("destination"),
|
|
||||||
"nexthop": obj.get("nexthop"),
|
|
||||||
})
|
|
||||||
|
|
||||||
network = Network(self._agent).find(options["network"])
|
|
||||||
whitelist = dict(
|
|
||||||
network_id=network.id,
|
|
||||||
name=options.get("name"),
|
|
||||||
cidr=options.get("cidr"),
|
|
||||||
ip_version=options.get("ip_version"),
|
|
||||||
dns_nameservers=options.get("dns_nameservers", []),
|
|
||||||
enable_dhcp=options.get("enable_dhcp", True),
|
|
||||||
host_routes=host_routes)
|
|
||||||
|
|
||||||
if options.get("gateway_ip"):
|
|
||||||
whitelist["gateway_ip"] = options.get("gateway_ip")
|
|
||||||
body = {"subnet": whitelist}
|
|
||||||
#TODO(sahid): Needs to use client.
|
|
||||||
return self._agent.clientneutron.create_subnet(body)
|
|
||||||
|
|
||||||
def _Id(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._ref["subnet"]["id"]
|
|
||||||
return self._ref.id
|
|
||||||
|
|
||||||
def _Name(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._ref["subnet"]["name"]
|
|
||||||
return self._ref.name
|
|
||||||
|
|
||||||
def _Delete(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._agent.clientneutron.delete_subnet(self.id)
|
|
||||||
self._ref.delete()
|
|
||||||
|
|
||||||
|
|
||||||
class Router(Base):
|
|
||||||
def _Execute(self, options):
|
|
||||||
whitelist = dict(
|
|
||||||
name=options["name"],
|
|
||||||
admin_state_up=options.get("admin_state_up", True))
|
|
||||||
return self._agent.clientneutron.create_router({"router": whitelist})
|
|
||||||
|
|
||||||
def _PostExecute(self, options):
|
|
||||||
if "gateways" in options:
|
|
||||||
for gateway_opt in options["gateways"]:
|
|
||||||
self.AttachGateway(gateway_opt)
|
|
||||||
if "interfaces" in options:
|
|
||||||
for interface_opt in options["interfaces"]:
|
|
||||||
self.AttachInterface(interface_opt)
|
|
||||||
|
|
||||||
def AttachInterface(self, options):
|
|
||||||
options["router"] = self.id
|
|
||||||
RouterInterface(self._agent)(**options)
|
|
||||||
|
|
||||||
def AttachGateway(self, options):
|
|
||||||
options["router"] = self.id
|
|
||||||
RouterGateway(self._agent)(**options)
|
|
||||||
|
|
||||||
def _Id(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._ref["router"]["id"]
|
|
||||||
return self._ref.id
|
|
||||||
|
|
||||||
def _Name(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._ref["router"]["name"]
|
|
||||||
return self._ref.name
|
|
||||||
|
|
||||||
def _Delete(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
items = self._agent.clientneutron.list_ports().items()
|
|
||||||
for name, interfaces in items:
|
|
||||||
for interface in interfaces:
|
|
||||||
if interface["device_id"] == self.id:
|
|
||||||
RouterInterface(self._agent, interface).delete()
|
|
||||||
return self._agent.clientneutron.delete_router(self.id)
|
|
||||||
|
|
||||||
self._ref.delete()
|
|
||||||
|
|
||||||
|
|
||||||
class RouterInterface(Base):
|
|
||||||
def _Execute(self, options):
|
|
||||||
router = Router(self._agent).find(options["router"])
|
|
||||||
subnet = SubNet(self._agent).find(options["subnet"])
|
|
||||||
whitelist = dict(
|
|
||||||
name=options.get("name"),
|
|
||||||
subnet_id=subnet.id)
|
|
||||||
try:
|
|
||||||
return self._agent.clientneutron.add_interface_router(
|
|
||||||
router.id, whitelist)
|
|
||||||
except neutron_exc.NeutronClientException:
|
|
||||||
pass # BUG(sahid): Needs to know how to get an interface.
|
|
||||||
|
|
||||||
def _Id(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._ref["id"]
|
|
||||||
return self._ref.id
|
|
||||||
|
|
||||||
def _Name(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._ref["name"]
|
|
||||||
return self._ref.name
|
|
||||||
|
|
||||||
def _Delete(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._agent.clientneutron.remove_interface_router(
|
|
||||||
self._ref["device_id"],
|
|
||||||
{"subnet_id": self._ref["fixed_ips"][0]['subnet_id']})
|
|
||||||
self._ref.delete()
|
|
||||||
|
|
||||||
|
|
||||||
class RouterGateway(Base):
|
|
||||||
def _Execute(self, options):
|
|
||||||
router = Router(self._agent).find(options["router"])
|
|
||||||
network = Network(self._agent).find(options["network"])
|
|
||||||
whitelist = dict(
|
|
||||||
name=options.get("name"),
|
|
||||||
network_id=network.id)
|
|
||||||
|
|
||||||
try:
|
|
||||||
return self._agent.clientneutron.add_gateway_router(
|
|
||||||
router.id, whitelist)
|
|
||||||
except neutron_exc.NeutronClientException:
|
|
||||||
pass # BUG(sahid): Needs to know how to get an interface.
|
|
||||||
|
|
||||||
def _Id(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._ref["id"]
|
|
||||||
return self._ref.id
|
|
||||||
|
|
||||||
def _Name(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._ref["name"]
|
|
||||||
return self._ref.name
|
|
||||||
|
|
||||||
def _Delete(self):
|
|
||||||
if isinstance(self._ref, dict):
|
|
||||||
return self._agent.clientneutron.remove_gateway_router(
|
|
||||||
self._ref["device_id"],
|
|
||||||
{"network_id": self._ref["fixed_ips"][0]['subnet_id']})
|
|
||||||
self._ref.delete()
|
|
@ -1,2 +0,0 @@
|
|||||||
import six
|
|
||||||
six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))
|
|
@ -1,99 +0,0 @@
|
|||||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
##############################################################################
|
|
||||||
##
|
|
||||||
## DO NOT MODIFY THIS FILE
|
|
||||||
##
|
|
||||||
## This file is being graduated to the warmtest library. Please make all
|
|
||||||
## changes there, and only backport critical fixes here. - dhellmann
|
|
||||||
##
|
|
||||||
##############################################################################
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
"""Common utilities used in testing"""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import fixtures
|
|
||||||
import testtools
|
|
||||||
|
|
||||||
_TRUE_VALUES = ('True', 'true', '1', 'yes')
|
|
||||||
_LOG_FORMAT = "%(levelname)8s [%(name)s] %(message)s"
|
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(testtools.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(BaseTestCase, self).setUp()
|
|
||||||
self._set_timeout()
|
|
||||||
self._fake_output()
|
|
||||||
self._fake_logs()
|
|
||||||
self.useFixture(fixtures.NestedTempfile())
|
|
||||||
self.useFixture(fixtures.TempHomeDir())
|
|
||||||
self.tempdirs = []
|
|
||||||
|
|
||||||
def _set_timeout(self):
|
|
||||||
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
|
|
||||||
try:
|
|
||||||
test_timeout = int(test_timeout)
|
|
||||||
except ValueError:
|
|
||||||
# If timeout value is invalid do not set a timeout.
|
|
||||||
test_timeout = 0
|
|
||||||
if test_timeout > 0:
|
|
||||||
self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
|
|
||||||
|
|
||||||
def _fake_output(self):
|
|
||||||
if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES:
|
|
||||||
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
|
|
||||||
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
|
|
||||||
if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES:
|
|
||||||
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
|
|
||||||
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
|
|
||||||
|
|
||||||
def _fake_logs(self):
|
|
||||||
if os.environ.get('OS_DEBUG') in _TRUE_VALUES:
|
|
||||||
level = logging.DEBUG
|
|
||||||
else:
|
|
||||||
level = logging.INFO
|
|
||||||
capture_logs = os.environ.get('OS_LOG_CAPTURE') in _TRUE_VALUES
|
|
||||||
if capture_logs:
|
|
||||||
self.useFixture(
|
|
||||||
fixtures.FakeLogger(
|
|
||||||
format=_LOG_FORMAT,
|
|
||||||
level=level,
|
|
||||||
nuke_handlers=capture_logs,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logging.basicConfig(format=_LOG_FORMAT, level=level)
|
|
||||||
|
|
||||||
def create_tempfiles(self, files, ext='.conf'):
|
|
||||||
tempfiles = []
|
|
||||||
for (basename, contents) in files:
|
|
||||||
if not os.path.isabs(basename):
|
|
||||||
(fd, path) = tempfile.mkstemp(prefix=basename, suffix=ext)
|
|
||||||
else:
|
|
||||||
path = basename + ext
|
|
||||||
fd = os.open(path, os.O_CREAT | os.O_WRONLY)
|
|
||||||
tempfiles.append(path)
|
|
||||||
try:
|
|
||||||
os.write(fd, contents)
|
|
||||||
finally:
|
|
||||||
os.close(fd)
|
|
||||||
return tempfiles
|
|
@ -1,15 +0,0 @@
|
|||||||
# Copyright 2013 Cloudwatt
|
|
||||||
#
|
|
||||||
# Author: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@cloudwatt.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.
|
|
@ -1,3 +0,0 @@
|
|||||||
#cloud-config
|
|
||||||
packages:
|
|
||||||
- wordpress
|
|
@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
from warm.openstack.common import test
|
|
||||||
|
|
||||||
|
|
||||||
class TestCase(test.BaseTestCase):
|
|
||||||
|
|
||||||
def test_noop(self):
|
|
||||||
self.assertTrue(True)
|
|
@ -1,60 +0,0 @@
|
|||||||
# Copyright 2013 Cloudwatt
|
|
||||||
#
|
|
||||||
# Author: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@cloudwatt.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.
|
|
||||||
|
|
||||||
"""Some utilities script to be used with warm."""
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from email.mime import multipart
|
|
||||||
from email.mime import text
|
|
||||||
|
|
||||||
|
|
||||||
MULTIPART_MAPPINGS = {
|
|
||||||
'#include': 'text/x-include-url',
|
|
||||||
'#!': 'text/x-shellscript',
|
|
||||||
'#cloud-config': 'text/cloud-config',
|
|
||||||
'#upstart-job': 'text/upstart-job',
|
|
||||||
'#part-handler': 'text/part-handler',
|
|
||||||
'#cloud-boothook': 'text/cloud-boothook'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_type(fname, deftype="text/plain"):
|
|
||||||
rtype = deftype
|
|
||||||
with open(fname, "rb") as f:
|
|
||||||
line = f.readline()
|
|
||||||
for s, mtype in MULTIPART_MAPPINGS.items():
|
|
||||||
if line.startswith(s):
|
|
||||||
rtype = mtype
|
|
||||||
break
|
|
||||||
return rtype
|
|
||||||
|
|
||||||
|
|
||||||
def multipart_content(*files):
|
|
||||||
"""Returns a mutlipart content.
|
|
||||||
Note:
|
|
||||||
This script was clearly inspired by write-mime-multipart.
|
|
||||||
"""
|
|
||||||
outer = multipart.MIMEMultipart()
|
|
||||||
for fname in files:
|
|
||||||
mtype = get_type(fname)
|
|
||||||
maintype, subtype = mtype.split('/', 1)
|
|
||||||
with open(fname) as f:
|
|
||||||
msg = text.MIMEText(f.read(), _subtype=subtype)
|
|
||||||
msg.add_header('Content-Disposition', 'attachment',
|
|
||||||
filename=os.path.basename(fname))
|
|
||||||
outer.attach(msg)
|
|
||||||
return outer.as_string()
|
|
@ -1,19 +0,0 @@
|
|||||||
# Copyright 2013 Cloudwatt
|
|
||||||
#
|
|
||||||
# Author: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@cloudwatt.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.
|
|
||||||
|
|
||||||
import pbr.version
|
|
||||||
|
|
||||||
__version__ = pbr.version.VersionInfo('warm').version_string()
|
|
Loading…
Reference in New Issue
Block a user