Retire stackforge/warm

This commit is contained in:
Monty Taylor 2015-10-17 16:05:06 -04:00
parent 2a8fddd51a
commit 52656b254c
31 changed files with 7 additions and 1778 deletions

40
.gitignore vendored
View File

@ -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

View File

@ -1,4 +0,0 @@
[gerrit]
host=review.openstack.org
port=29418
project=stackforge/warm.git

View File

@ -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

View File

@ -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
View File

@ -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.

View File

@ -1,6 +0,0 @@
include AUTHORS
include ChangeLog
exclude .gitignore
exclude .gitreview
global-exclude *.pyc

64
README
View File

@ -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
View 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".

View File

@ -1,3 +0,0 @@
python-dev
libffi-dev
libssl-dev

View File

@ -1,3 +0,0 @@
python-devel
libffi-devel
openssl-devel

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -1,4 +0,0 @@
hacking>=0.8.0,<0.9
mock>=1.0
testrepository>=0.0.18
testtools>=0.9.32

View File

@ -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)

View File

@ -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()

View File

@ -1,4 +0,0 @@
#!/bin/bash
TOOLS=`dirname $0`
VENV=$TOOLS/../.venv
source $VENV/bin/activate && $@

30
tox.ini
View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -1,2 +0,0 @@
import six
six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))

View File

@ -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

View File

@ -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.

View File

@ -1,3 +0,0 @@
#cloud-config
packages:
- wordpress

View File

@ -1,8 +0,0 @@
from warm.openstack.common import test
class TestCase(test.BaseTestCase):
def test_noop(self):
self.assertTrue(True)

View File

@ -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()

View File

@ -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()