Change the gate to OpenStack infrastrucure

Change the gate to OpenStack infrastrcuture and update the README.md
to reflect the work on the stateless design proposal and branch.

BP: https://blueprints.launchpad.net/tricircle/+spec/new-design

Change-Id: I51accdf33d8d9e50774c16d7649975ca91c2f5ec
Signed-off-by: Chaoyi Huang <joehuang@huawei.com>
This commit is contained in:
Chaoyi Huang 2015-12-11 15:29:10 +08:00
parent 57f0ddbf91
commit bfc6a83048
13 changed files with 379 additions and 63 deletions

88
.gitignore vendored
View File

@ -1,45 +1,53 @@
*.DS_Store
*.egg*
*.log
*.mo
*.pyc
*.swo
*.swp
*.sqlite
*.iml
*~
.autogenerated
*.py[cod]
# C extensions
*.so
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
var
sdist
develop-eggs
.installed.cfg
lib
lib64
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.nova-venv
.tox
nosetests.xml
.testrepository
.venv
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
.ropeproject
.testrepository/
.tox
.idea
.venv
# Complexity
output/*.html
output/*/index.html
# Sphinx
doc/build
# pbr generates these
AUTHORS
Authors
build-stamp
build/*
CA/
ChangeLog
coverage.xml
cover/*
covhtml
dist/*
doc/source/api/*
doc/build/*
etc/nova/nova.conf.sample
instances
keeper
keys
local_settings.py
MANIFEST
nosetests.xml
nova/tests/cover/*
nova/vcsversion.py
tools/conf/nova.conf*
tools/lintstack.head.py
tools/pylint_exceptions
etc/nova/nova.conf.sample
# Editors
*~
.*.swp
.*sw?

7
.testr.conf Normal file
View File

@ -0,0 +1,7 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -1,6 +1,8 @@
# Tricircle
(For PoC source code, please switch to ["poc"](https://github.com/openstack/tricircle/tree/poc) tag, or ["stable/fortest"](https://github.com/openstack/tricircle/tree/stable/fortest) branch)
(Attention Please, Stateless Design Proposal is being worked on the ["experiment"](https://github.com/openstack/tricircle/tree/experiment) branch).
(The origningal PoC source code, please switch to ["poc"](https://github.com/openstack/tricircle/tree/poc) tag, or ["stable/fortest"](https://github.com/openstack/tricircle/tree/stable/fortest) branch)
Tricircle is a openstack project that aims to deal with OpenStack deployment across multiple sites. It provides users a single management view by having only one OpenStack instance on behalf of all the involved ones. It essentially serves as a communication bus between the central OpenStack instance and the other OpenStack instances that are called upon.

75
doc/source/conf.py Executable file
View File

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
sys.path.insert(0, os.path.abspath('../..'))
# -- General configuration ----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
# 'sphinx.ext.intersphinx',
'oslosphinx'
]
# autodoc generation is a bit aggressive and a nuisance when doing heavy
# text edit cycles.
# execute "export SPHINX_DEBUG=1" in your terminal to disable
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'tricircle'
copyright = u'2015, OpenStack Foundation'
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
add_module_names = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output --------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
# html_theme_path = ["."]
# html_theme = '_theme'
# html_static_path = ['static']
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
# [howto/manual]).
latex_documents = [
('index',
'%s.tex' % project,
u'%s Documentation' % project,
u'OpenStack Foundation', 'manual'),
]
# Example configuration for intersphinx: refer to the Python standard library.
# intersphinx_mapping = {'http://docs.python.org/': None}

21
doc/source/index.rst Normal file
View File

@ -0,0 +1,21 @@
.. tricircle documentation master file, created by
sphinx-quickstart on Wed Dec 2 17:00:36 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to tricircle's documentation!
========================================================
Contents:
.. toctree::
:maxdepth: 2
api_v1
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -1,7 +1,8 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
pbr<2.0,>=1.3
pbr>=1.6
Babel>=1.3
Paste
PasteDeploy>=1.5.0
@ -9,30 +10,37 @@ Routes!=2.0,!=2.1,>=1.12.3;python_version=='2.7'
Routes!=2.0,>=1.12.3;python_version!='2.7'
debtcollector>=0.3.0 # Apache-2.0
eventlet>=0.17.4
pecan>=0.9.0
pecan>=1.0.0
greenlet>=0.3.2
httplib2>=0.7.5
requests>=2.5.2
Jinja2>=2.6 # BSD License (3 clause)
keystonemiddleware>=2.0.0
netaddr>=0.7.12
requests>=2.8.1
Jinja2>=2.8 # BSD License (3 clause)
keystonemiddleware>=4.0.0
netaddr!=0.7.16,>=0.7.12
netifaces>=0.10.4
retrying!=1.3.0,>=1.2.3 # Apache-2.0
SQLAlchemy<1.1.0,>=0.9.7
SQLAlchemy<1.1.0,>=0.9.9
WebOb>=1.2.3
python-keystoneclient>=1.6.0
alembic>=0.7.2
python-cinderclient>=1.3.1
python-glanceclient>=0.18.0
python-keystoneclient!=1.8.0,>=1.6.0
python-neutronclient>=2.6.0
python-novaclient>=2.29.0,!=2.33.0
alembic>=0.8.0
six>=1.9.0
stevedore>=1.5.0 # Apache-2.0
oslo.concurrency>=2.1.0 # Apache-2.0
oslo.config>=1.11.0 # Apache-2.0
oslo.concurrency>=2.3.0 # Apache-2.0
oslo.config>=2.7.0 # Apache-2.0
oslo.context>=0.2.0 # Apache-2.0
oslo.db>=1.12.0 # Apache-2.0
oslo.db>=4.1.0 # Apache-2.0
oslo.i18n>=1.5.0 # Apache-2.0
oslo.log>=1.6.0 # Apache-2.0
oslo.messaging>=1.16.0 # Apache-2.0
oslo.middleware>=2.4.0 # Apache-2.0
oslo.log>=1.12.0 # Apache-2.0
oslo.messaging!=2.8.0,!=3.1.0,>2.6.1 # Apache-2.0
oslo.middleware>=3.0.0 # Apache-2.0
oslo.policy>=0.5.0 # Apache-2.0
oslo.rootwrap>=2.0.0 # Apache-2.0
oslo.serialization>=1.4.0 # Apache-2.0
oslo.service>=0.1.0 # Apache-2.0
oslo.utils>=1.9.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0
oslo.service>=1.0.0 # Apache-2.0
oslo.utils!=3.1.0,>=2.8.0 # Apache-2.0
oslo.versionedobjects>=0.13.0
sqlalchemy-migrate>=0.9.6

48
setup.cfg Normal file
View File

@ -0,0 +1,48 @@
[metadata]
name = tricircle
summary = Tricircle is an OpenStack project that aims to deal with OpenStack deployment across multiple sites.
description-file =
README.md
author = OpenStack
author-email = openstack-dev@lists.openstack.org
home-page = http://www.openstack.org/
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.3
Programming Language :: Python :: 3.4
[files]
packages =
tricircle
[build_sphinx]
source-dir = doc/source
build-dir = doc/build
all_files = 1
[upload_sphinx]
upload-dir = doc/build/html
[compile_catalog]
directory = tricircle/locale
domain = tricircle
[update_catalog]
domain = tricircle
output_dir = tricircle/locale
input_file = tricircle/locale/tricircle.pot
[extract_messages]
keywords = _ gettext ngettext l_ lazy_gettext
mapping_file = babel.cfg
output_file = tricircle/locale/tricircle.pot
[entry_points]

29
setup.py Normal file
View File

@ -0,0 +1,29 @@
# 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.
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
# In python < 2.7.4, a lazy loading of package `pbr` will break
# setuptools if some other modules registered functions in `atexit`.
# solution from: http://bugs.python.org/issue15881#msg170215
try:
import multiprocessing # noqa
except ImportError:
pass
setuptools.setup(
setup_requires=['pbr'],
pbr=True)

23
test-requirements.txt Normal file
View File

@ -0,0 +1,23 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking<0.11,>=0.10.2
cliff>=1.15.0 # Apache-2.0
coverage>=3.6
fixtures>=1.3.1
mock>=1.2
python-subunit>=0.0.18
requests-mock>=0.7.0 # Apache-2.0
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
testrepository>=0.0.18
testtools>=1.4.0
testresources>=0.2.4
testscenarios>=0.4
WebTest>=2.0
oslotest>=1.10.0 # Apache-2.0
os-testr>=0.4.1
tempest-lib>=0.11.0
ddt>=1.0.1
pylint==1.4.5 # GNU GPL v2

43
tox.ini Normal file
View File

@ -0,0 +1,43 @@
[tox]
minversion = 1.6
envlist = py34,py27,pypy,pep8
skipsdist = True
[testenv]
sitepackages = True
usedevelop = True
install_command =
pip install -U --force-reinstall {opts} {packages}
setenv =
VIRTUAL_ENV={envdir}
deps =
-egit+https://git.openstack.org/openstack/neutron@master#egg=neutron
-r{toxinidir}/test-requirements.txt
commands = python setup.py testr --slowest --testr-args='{posargs}'
whitelist_externals = rm
[testenv:common-constraints]
install_command = {toxinidir}/tools/tox_install.sh constrained -c{env:UPPER_CONTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
[testenv:pep8]
commands = flake8
[testenv:venv]
commands = {posargs}
[testenv:cover]
commands = python setup.py testr --coverage --testr-args='{posargs}'
[testenv:docs]
commands = python setup.py build_sphinx
[testenv:debug]
commands = oslo_debug_helper {posargs}
[flake8]
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
ignore = E123,E125
builtins = _
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build

View File

@ -20,12 +20,24 @@ import unittest
import pecan
import tricircle.api.controllers.root as root_controller
from tricircle.common import cascading_site_api
from tricircle.common import context
from tricircle.common import rpc
from tricircle.db import client
from tricircle.db import core
from tricircle.db import models
def fake_create_client(target):
return None
def fake_cast_message(self, context, method, payload):
return None
class ControllerTest(unittest.TestCase):
def setUp(self):
core.initialize()
@ -49,6 +61,9 @@ class SitesControllerTest(ControllerTest):
super(SitesControllerTest, self).setUp()
self.controller = root_controller.SitesController()
@patch.object(rpc, 'create_client', new=fake_create_client)
@patch.object(cascading_site_api.CascadingSiteNotifyAPI,
'_cast_message', new=fake_cast_message)
def test_post_top_site(self):
kw = {'name': 'TopSite', 'top': True}
site_id = self.controller.post(**kw)['site']['site_id']
@ -56,6 +71,9 @@ class SitesControllerTest(ControllerTest):
self.assertEqual(site['site_name'], 'TopSite')
self.assertEqual(site['az_id'], '')
@patch.object(rpc, 'create_client', new=fake_create_client)
@patch.object(cascading_site_api.CascadingSiteNotifyAPI,
'_cast_message', new=fake_cast_message)
@patch.object(client.Client, 'create_resources')
def test_post_bottom_site(self, mock_method):
kw = {'name': 'BottomSite'}
@ -66,11 +84,17 @@ class SitesControllerTest(ControllerTest):
mock_method.assert_called_once_with('aggregate', self.context,
'ag_BottomSite', 'az_BottomSite')
@patch.object(rpc, 'create_client', new=fake_create_client)
@patch.object(cascading_site_api.CascadingSiteNotifyAPI,
'_cast_message', new=fake_cast_message)
def test_post_site_name_missing(self):
kw = {'top': True}
self.controller.post(**kw)
pecan.abort.assert_called_once_with(400, 'Name of site required')
@patch.object(rpc, 'create_client', new=fake_create_client)
@patch.object(cascading_site_api.CascadingSiteNotifyAPI,
'_cast_message', new=fake_cast_message)
def test_post_conflict(self):
kw = {'name': 'TopSite', 'top': True}
self.controller.post(**kw)
@ -78,6 +102,9 @@ class SitesControllerTest(ControllerTest):
pecan.abort.assert_called_once_with(409,
'Site with name TopSite exists')
@patch.object(rpc, 'create_client', new=fake_create_client)
@patch.object(cascading_site_api.CascadingSiteNotifyAPI,
'_cast_message', new=fake_cast_message)
def test_post_not_admin(self):
self.context.is_admin = False
kw = {'name': 'TopSite', 'top': True}
@ -85,6 +112,9 @@ class SitesControllerTest(ControllerTest):
pecan.abort.assert_called_once_with(
400, 'Admin role required to create sites')
@patch.object(rpc, 'create_client', new=fake_create_client)
@patch.object(cascading_site_api.CascadingSiteNotifyAPI,
'_cast_message', new=fake_cast_message)
@patch.object(client.Client, 'create_resources')
def test_post_decide_top(self, mock_method):
# 'top' default to False
@ -100,6 +130,9 @@ class SitesControllerTest(ControllerTest):
'az_Site%d' % i) for i in xrange(2, 4)]
mock_method.assert_has_calls(calls)
@patch.object(rpc, 'create_client', new=fake_create_client)
@patch.object(cascading_site_api.CascadingSiteNotifyAPI,
'_cast_message', new=fake_cast_message)
@patch.object(models, 'create_site')
def test_post_create_site_exception(self, mock_method):
mock_method.side_effect = Exception
@ -121,6 +154,9 @@ class SitesControllerTest(ControllerTest):
sites = models.list_sites(self.context, site_filter)
self.assertEqual(len(sites), 0)
@patch.object(rpc, 'create_client', new=fake_create_client)
@patch.object(cascading_site_api.CascadingSiteNotifyAPI,
'_cast_message', new=fake_cast_message)
def test_get_one(self):
kw = {'name': 'TopSite', 'top': True}
site_id = self.controller.post(**kw)['site']['site_id']
@ -129,11 +165,17 @@ class SitesControllerTest(ControllerTest):
'site_name': 'TopSite',
'az_id': ''})
@patch.object(rpc, 'create_client', new=fake_create_client)
@patch.object(cascading_site_api.CascadingSiteNotifyAPI,
'_cast_message', new=fake_cast_message)
def test_get_one_not_found(self):
self.controller.get_one('fake_id')
pecan.abort.assert_called_once_with(404,
'Site with id fake_id not found')
@patch.object(rpc, 'create_client', new=fake_create_client)
@patch.object(cascading_site_api.CascadingSiteNotifyAPI,
'_cast_message', new=fake_cast_message)
@patch.object(client.Client, 'create_resources', new=mock.Mock)
def test_get_all(self):
kw1 = {'name': 'TopSite', 'top': True}

View File

@ -45,6 +45,11 @@ def fake_update_port(instance, context, port_id, port):
return FAKE_PORT
class FakePlugin(TricirclePlugin):
def __init__(self):
pass
class TricirclePluginTest(unittest.TestCase):
def setUp(self):
FAKE_PORT['status'] = neutron_const.PORT_STATUS_DOWN
@ -55,7 +60,7 @@ class TricirclePluginTest(unittest.TestCase):
@patch.object(db_base_plugin_v2.NeutronDbPluginV2,
'get_port', new=fake_get_port)
def test_update_port_status(self):
plugin = TricirclePlugin()
plugin = FakePlugin()
# this method requires a neutron context, but for test we just pass
# a tricircle context
port = plugin.update_port_status(context.Context(), FAKE_PORT_ID,
@ -69,7 +74,7 @@ class TricirclePluginTest(unittest.TestCase):
@patch.object(db_base_plugin_v2.NeutronDbPluginV2,
'get_port', new=fake_get_port)
def test_update_port_status_port_not_found(self):
plugin = TricirclePlugin()
plugin = FakePlugin()
port = plugin.update_port_status(context.Context(), 'no_such_port',
neutron_const.PORT_STATUS_ACTIVE)
self.assertEqual(FAKE_PORT['status'], neutron_const.PORT_STATUS_DOWN)

View File

@ -29,6 +29,11 @@ FAKE_PORT_ID = 'fake_port_uuid'
FAKE_CONTEXT = object()
class FakePlugin(plugin.TricirclePlugin):
def __init__(self):
pass
class RpcCallbacksTest(unittest.TestCase):
def setUp(self):
self.callbacks = rpc.RpcCallbacks()
@ -39,7 +44,7 @@ class RpcCallbacksTest(unittest.TestCase):
'get_plugin') as get_plugin_method:
with patch.object(plugin.TricirclePlugin,
'update_port_status') as update_method:
get_plugin_method.return_value = plugin.TricirclePlugin()
get_plugin_method.return_value = FakePlugin()
self.callbacks.update_port_up(FAKE_CONTEXT,
port_id=FAKE_PORT_ID)
update_method.assert_called_once_with(
@ -52,7 +57,7 @@ class RpcCallbacksTest(unittest.TestCase):
'get_plugin') as get_plugin_method:
with patch.object(plugin.TricirclePlugin,
'update_port_status') as update_method:
get_plugin_method.return_value = plugin.TricirclePlugin()
get_plugin_method.return_value = FakePlugin()
self.callbacks.update_port_down(FAKE_CONTEXT,
port_id=FAKE_PORT_ID)
update_method.assert_called_once_with(