Merge in docs from openstack-ci.
Change-Id: I49f71f8118e45f28d4b777ddc9588b8e30151d79
This commit is contained in:
parent
215f3afbe2
commit
90531483b0
216
doc/conf.py
Normal file
216
doc/conf.py
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# OpenStack CI documentation build configuration file, created by
|
||||||
|
# sphinx-quickstart on Mon Jul 18 13:42:23 2011.
|
||||||
|
#
|
||||||
|
# This file is execfile()d with the current directory set to its containing dir.
|
||||||
|
#
|
||||||
|
# Note that not all possible configuration values are present in this
|
||||||
|
# autogenerated file.
|
||||||
|
#
|
||||||
|
# All configuration values have a default; values that are commented out
|
||||||
|
# serve to show the default.
|
||||||
|
|
||||||
|
import sys, os, datetime
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
#needs_sphinx = '1.0'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
|
extensions = []
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The suffix of source filenames.
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The encoding of source files.
|
||||||
|
#source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = u'OpenStack CI'
|
||||||
|
copyright = u'2011, Monty Taylor, James Blair and Andrew Hutchings'
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
# The short X.Y version.
|
||||||
|
version = "%d.%02d" % (datetime.datetime.now().year, datetime.datetime.now().month)
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
release = "%d.%02d.%02d" % (datetime.datetime.now().year, datetime.datetime.now().month, datetime.datetime.now().day)
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#language = None
|
||||||
|
|
||||||
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
|
# non-false value, then it is used:
|
||||||
|
#today = ''
|
||||||
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
|
#today_fmt = '%B %d, %Y'
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
exclude_patterns = []
|
||||||
|
|
||||||
|
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||||
|
#default_role = None
|
||||||
|
|
||||||
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
|
#add_function_parentheses = True
|
||||||
|
|
||||||
|
# If true, the current module name will be prepended to all description
|
||||||
|
# unit titles (such as .. function::).
|
||||||
|
#add_module_names = True
|
||||||
|
|
||||||
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
|
# output. They are ignored by default.
|
||||||
|
#show_authors = False
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
|
# A list of ignored prefixes for module index sorting.
|
||||||
|
#modindex_common_prefix = []
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output ---------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
html_theme = 'default'
|
||||||
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
#html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
|
#html_theme_path = []
|
||||||
|
|
||||||
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
|
# "<project> v<release> documentation".
|
||||||
|
#html_title = None
|
||||||
|
|
||||||
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
|
#html_short_title = None
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
|
# of the sidebar.
|
||||||
|
#html_logo = None
|
||||||
|
|
||||||
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
|
# pixels large.
|
||||||
|
#html_favicon = None
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
|
# using the given strftime format.
|
||||||
|
#html_last_updated_fmt = '%b %d, %Y'
|
||||||
|
|
||||||
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
|
# typographically correct entities.
|
||||||
|
#html_use_smartypants = True
|
||||||
|
|
||||||
|
# Custom sidebar templates, maps document names to template names.
|
||||||
|
#html_sidebars = {}
|
||||||
|
|
||||||
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
|
# template names.
|
||||||
|
#html_additional_pages = {}
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#html_domain_indices = True
|
||||||
|
|
||||||
|
# If false, no index is generated.
|
||||||
|
#html_use_index = True
|
||||||
|
|
||||||
|
# If true, the index is split into individual pages for each letter.
|
||||||
|
#html_split_index = False
|
||||||
|
|
||||||
|
# If true, links to the reST sources are added to the pages.
|
||||||
|
#html_show_sourcelink = True
|
||||||
|
|
||||||
|
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_sphinx = True
|
||||||
|
|
||||||
|
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_copyright = True
|
||||||
|
|
||||||
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
|
# base URL from which the finished HTML is served.
|
||||||
|
#html_use_opensearch = ''
|
||||||
|
|
||||||
|
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
|
#html_file_suffix = None
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'OpenStackCIdoc'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for LaTeX output --------------------------------------------------
|
||||||
|
|
||||||
|
# The paper size ('letter' or 'a4').
|
||||||
|
#latex_paper_size = 'letter'
|
||||||
|
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#latex_font_size = '10pt'
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||||
|
latex_documents = [
|
||||||
|
('index', 'OpenStackCI.tex', u'OpenStack CI Documentation',
|
||||||
|
u'Monty Taylor and James Blair', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
|
# the title page.
|
||||||
|
#latex_logo = None
|
||||||
|
|
||||||
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
|
# not chapters.
|
||||||
|
#latex_use_parts = False
|
||||||
|
|
||||||
|
# If true, show page references after internal links.
|
||||||
|
#latex_show_pagerefs = False
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
#latex_show_urls = False
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#latex_preamble = ''
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#latex_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for manual page output --------------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
('index', 'openstackci', u'OpenStack CI Documentation',
|
||||||
|
[u'Monty Taylor, James Blair and Andrew Hutchings'], 1)
|
||||||
|
]
|
979
doc/gerrit.rst
Normal file
979
doc/gerrit.rst
Normal file
@ -0,0 +1,979 @@
|
|||||||
|
:title: Gerrit Installation
|
||||||
|
|
||||||
|
Gerrit
|
||||||
|
######
|
||||||
|
|
||||||
|
Objective
|
||||||
|
*********
|
||||||
|
|
||||||
|
A workflow where developers submit changes to gerrit, changes are
|
||||||
|
peer-reviewed and automatically tested by Jenkins before being
|
||||||
|
committed to the main repo. The public repo is on github.
|
||||||
|
|
||||||
|
References
|
||||||
|
**********
|
||||||
|
|
||||||
|
* http://gerrit.googlecode.com/svn/documentation/2.2.1/install.html
|
||||||
|
* http://feeding.cloud.geek.nz/2011/04/code-reviews-with-gerrit-and-gitorious.html
|
||||||
|
* http://feeding.cloud.geek.nz/2011/05/integrating-launchpad-and-gerrit-code.html
|
||||||
|
* http://www.infoq.com/articles/Gerrit-jenkins-hudson
|
||||||
|
* https://wiki.jenkins-ci.org/display/JENKINS/Gerrit+Trigger
|
||||||
|
* https://wiki.mahara.org/index.php/Developer_Area/Developer_Tools
|
||||||
|
|
||||||
|
Known Issues
|
||||||
|
************
|
||||||
|
|
||||||
|
* Don't use innodb until at least gerrit 2.2.2 because of:
|
||||||
|
http://code.google.com/p/gerrit/issues/detail?id=518
|
||||||
|
|
||||||
|
Installation
|
||||||
|
************
|
||||||
|
|
||||||
|
Host Installation
|
||||||
|
=================
|
||||||
|
|
||||||
|
Prepare Host
|
||||||
|
------------
|
||||||
|
This sets the host up with the standard OpenStack system
|
||||||
|
administration configuration. Skip this if you're not setting up a
|
||||||
|
host for use by the OpenStack project.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo apt-get install puppet git openjdk-6-jre-headless mysql-server
|
||||||
|
git clone git://github.com/openstack/openstack-ci-puppet.git
|
||||||
|
cd openstack-ci-puppet/
|
||||||
|
sudo puppet apply --modulepath=modules manifests/site.pp
|
||||||
|
|
||||||
|
Install MySQL
|
||||||
|
-------------
|
||||||
|
You should setup MySQL as follows, changing 'secret' to a suitable password:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
mysql -u root -p
|
||||||
|
|
||||||
|
.. code-block:: mysql
|
||||||
|
|
||||||
|
CREATE USER 'gerrit2'@'localhost' IDENTIFIED BY 'secret';
|
||||||
|
CREATE DATABASE reviewdb;
|
||||||
|
ALTER DATABASE reviewdb charset=latin1;
|
||||||
|
GRANT ALL ON reviewdb.* TO 'gerrit2'@'localhost';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
|
||||||
|
Then create the gerrit2 system user as follows:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo useradd -mr gerrit2
|
||||||
|
sudo chsh gerrit2 -s /bin/bash
|
||||||
|
sudo su - gerrit2
|
||||||
|
|
||||||
|
With Gerrit 2.2.2 onwards edit /etc/mysql/my.cnf with the following:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[mysqld]
|
||||||
|
default-storage-engine=INNODB
|
||||||
|
|
||||||
|
Install Gerrit
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Note that Openstack's gerrit installation currently uses a custom .war of gerrit
|
||||||
|
2.2.2. The following instruction is for the generic gerrit binaries:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
wget http://gerrit.googlecode.com/files/gerrit-2.2.1.war
|
||||||
|
mv gerrit-2.2.1.war gerrit.war
|
||||||
|
java -jar gerrit.war init -d review_site
|
||||||
|
|
||||||
|
The .war file will bring up an interactive tool to change the settings, these
|
||||||
|
should be set as follows. Note that the password configured earlier for MySQL
|
||||||
|
should be provided when prompted::
|
||||||
|
|
||||||
|
*** Gerrit Code Review 2.2.1
|
||||||
|
***
|
||||||
|
|
||||||
|
Create '/home/gerrit2/review_site' [Y/n]?
|
||||||
|
|
||||||
|
*** Git Repositories
|
||||||
|
***
|
||||||
|
|
||||||
|
Location of Git repositories [git]:
|
||||||
|
|
||||||
|
*** SQL Database
|
||||||
|
***
|
||||||
|
|
||||||
|
Database server type [H2/?]: ?
|
||||||
|
Supported options are:
|
||||||
|
h2
|
||||||
|
postgresql
|
||||||
|
mysql
|
||||||
|
jdbc
|
||||||
|
Database server type [H2/?]: mysql
|
||||||
|
|
||||||
|
Gerrit Code Review is not shipped with MySQL Connector/J 5.1.10
|
||||||
|
** This library is required for your configuration. **
|
||||||
|
Download and install it now [Y/n]?
|
||||||
|
Downloading http://repo2.maven.org/maven2/mysql/mysql-connector-java/5.1.10/mysql-connector-java-5.1.10.jar ... OK
|
||||||
|
Checksum mysql-connector-java-5.1.10.jar OK
|
||||||
|
Server hostname [localhost]:
|
||||||
|
Server port [(MYSQL default)]:
|
||||||
|
Database name [reviewdb]:
|
||||||
|
Database username [gerrit2]:
|
||||||
|
gerrit2's password :
|
||||||
|
confirm password :
|
||||||
|
|
||||||
|
*** User Authentication
|
||||||
|
***
|
||||||
|
|
||||||
|
Authentication method [OPENID/?]:
|
||||||
|
|
||||||
|
*** Email Delivery
|
||||||
|
***
|
||||||
|
|
||||||
|
SMTP server hostname [localhost]:
|
||||||
|
SMTP server port [(default)]:
|
||||||
|
SMTP encryption [NONE/?]:
|
||||||
|
SMTP username :
|
||||||
|
|
||||||
|
*** Container Process
|
||||||
|
***
|
||||||
|
|
||||||
|
Run as [gerrit2]:
|
||||||
|
Java runtime [/usr/lib/jvm/java-6-openjdk/jre]:
|
||||||
|
Copy gerrit.war to /home/gerrit2/review_site/bin/gerrit.war [Y/n]?
|
||||||
|
Copying gerrit.war to /home/gerrit2/review_site/bin/gerrit.war
|
||||||
|
|
||||||
|
*** SSH Daemon
|
||||||
|
***
|
||||||
|
|
||||||
|
Listen on address [*]:
|
||||||
|
Listen on port [29418]:
|
||||||
|
|
||||||
|
Gerrit Code Review is not shipped with Bouncy Castle Crypto v144
|
||||||
|
If available, Gerrit can take advantage of features
|
||||||
|
in the library, but will also function without it.
|
||||||
|
Download and install it now [Y/n]?
|
||||||
|
Downloading http://www.bouncycastle.org/download/bcprov-jdk16-144.jar ... OK
|
||||||
|
Checksum bcprov-jdk16-144.jar OK
|
||||||
|
Generating SSH host key ... rsa... dsa... done
|
||||||
|
|
||||||
|
*** HTTP Daemon
|
||||||
|
***
|
||||||
|
|
||||||
|
Behind reverse proxy [y/N]? y
|
||||||
|
Proxy uses SSL (https://) [y/N]? y
|
||||||
|
Subdirectory on proxy server [/]:
|
||||||
|
Listen on address [*]:
|
||||||
|
Listen on port [8081]:
|
||||||
|
Canonical URL [https://review.openstack.org/]:
|
||||||
|
|
||||||
|
Initialized /home/gerrit2/review_site
|
||||||
|
Executing /home/gerrit2/review_site/bin/gerrit.sh start
|
||||||
|
Starting Gerrit Code Review: OK
|
||||||
|
Waiting for server to start ... OK
|
||||||
|
Opening browser ...
|
||||||
|
Please open a browser and go to https://review.openstack.org/#admin,projects
|
||||||
|
|
||||||
|
Configure Gerrit
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The file /home/gerrit2/review_site/etc/gerrit.config will be setup automatically
|
||||||
|
by puppet.
|
||||||
|
|
||||||
|
Set Gerrit to start on boot:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
ln -snf /home/gerrit2/review_site/bin/gerrit.sh /etc/init.d/gerrit
|
||||||
|
update-rc.d gerrit defaults 90 10
|
||||||
|
|
||||||
|
Then create the file ``/etc/default/gerritcodereview`` with the following
|
||||||
|
contents:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
GERRIT_SITE=/home/gerrit2/review_site
|
||||||
|
|
||||||
|
Add "Approved" review type to gerrit:
|
||||||
|
|
||||||
|
.. code-block:: mysql
|
||||||
|
|
||||||
|
mysql -u root -p
|
||||||
|
use reviewdb;
|
||||||
|
insert into approval_categories values ('Approved', 'A', 2, 'MaxNoBlock', 'N', 'APRV');
|
||||||
|
insert into approval_category_values values ('No score', 'APRV', 0);
|
||||||
|
insert into approval_category_values values ('Approved', 'APRV', 1);
|
||||||
|
update approval_category_values set name = "Looks good to me (core reviewer)" where name="Looks good to me, approved";
|
||||||
|
|
||||||
|
Expand "Verified" review type to -2/+2:
|
||||||
|
|
||||||
|
.. code-block:: mysql
|
||||||
|
|
||||||
|
mysql -u root -p
|
||||||
|
use reviewdb;
|
||||||
|
update approval_category_values set value=2
|
||||||
|
where value=1 and category_id='VRIF';
|
||||||
|
update approval_category_values set value=-2
|
||||||
|
where value=-1 and category_id='VRIF';
|
||||||
|
insert into approval_category_values values
|
||||||
|
("Doesn't seem to work","VRIF",-1),
|
||||||
|
("Works for me","VRIF","1");
|
||||||
|
|
||||||
|
Reword the default messages that use the word Submit, as they imply that
|
||||||
|
we're not happy with people for submitting the patch in the first place:
|
||||||
|
|
||||||
|
.. code-block:: mysql
|
||||||
|
|
||||||
|
mysql -u root -p
|
||||||
|
use reviewdb;
|
||||||
|
update approval_category_values set name="Do not merge"
|
||||||
|
where category_id='CRVW' and value=-2;
|
||||||
|
update approval_category_values
|
||||||
|
set name="I would prefer that you didn't merge this"
|
||||||
|
where category_id='CRVW' and value=-1;
|
||||||
|
|
||||||
|
OpenStack currently uses a hybrid approach for CLA enforcement. We
|
||||||
|
use Gerrit's built in CLA system to ensure that contributors have
|
||||||
|
signed the CLA, but contributors don't actually use Gerrit to sign it.
|
||||||
|
Instead, developers use an external service (Echosign) to agree to the
|
||||||
|
CLA, and then request membership in a Launchpad group called
|
||||||
|
"openstack-cla". The moderators of that group (core members of any
|
||||||
|
OpenStack project) approve membership requests after verifying that
|
||||||
|
new contributors have signed the CLA at Echosign. The openstack-cla
|
||||||
|
group is kept synchronized with Gerrit. Gerrit is then configured
|
||||||
|
with a "dummy" CLA (which users are not expected to see), and the
|
||||||
|
administrator indicates to Gerrit that the entire openstack-cla group
|
||||||
|
has agreed to the CLA. This lets Gerrit enforce that the CLA has been
|
||||||
|
signed while the actual facility to sign it in Gerrit is disabled via
|
||||||
|
a source patch.
|
||||||
|
|
||||||
|
This configuration is not recommended for new projects and is merely
|
||||||
|
an artifact of legal requirements placed on the OpenStack project.
|
||||||
|
Here are the SQL commands to set it up:
|
||||||
|
|
||||||
|
.. code-block:: mysql
|
||||||
|
|
||||||
|
insert into contributor_agreement_id values (NULL);
|
||||||
|
insert into contributor_agreements values ('Y', 'N', 'N', 'CLA (Echosign)',
|
||||||
|
'OpenStack CLA via Echosign', 'static/echosign-cla.html', 1);
|
||||||
|
|
||||||
|
insert into account_group_agreements values (
|
||||||
|
now(), 'V', 1, now(), NULL,
|
||||||
|
(select group_id from account_group_names where name='openstack-cla'),
|
||||||
|
1);
|
||||||
|
|
||||||
|
|
||||||
|
Install Apache
|
||||||
|
--------------
|
||||||
|
::
|
||||||
|
|
||||||
|
apt-get install apache2
|
||||||
|
|
||||||
|
Create: /etc/apache2/sites-available/gerrit:
|
||||||
|
|
||||||
|
.. code-block:: apacheconf
|
||||||
|
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerAdmin webmaster@localhost
|
||||||
|
|
||||||
|
ErrorLog ${APACHE_LOG_DIR}/gerrit-error.log
|
||||||
|
|
||||||
|
LogLevel warn
|
||||||
|
|
||||||
|
CustomLog ${APACHE_LOG_DIR}/gerrit-access.log combined
|
||||||
|
|
||||||
|
Redirect / https://review-dev.openstack.org/
|
||||||
|
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
|
<IfModule mod_ssl.c>
|
||||||
|
<VirtualHost _default_:443>
|
||||||
|
ServerAdmin webmaster@localhost
|
||||||
|
|
||||||
|
ErrorLog ${APACHE_LOG_DIR}/gerrit-ssl-error.log
|
||||||
|
|
||||||
|
LogLevel warn
|
||||||
|
|
||||||
|
CustomLog ${APACHE_LOG_DIR}/gerrit-ssl-access.log combined
|
||||||
|
|
||||||
|
SSLEngine on
|
||||||
|
|
||||||
|
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||||
|
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
|
||||||
|
#SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt
|
||||||
|
|
||||||
|
<FilesMatch "\.(cgi|shtml|phtml|php)$">
|
||||||
|
SSLOptions +StdEnvVars
|
||||||
|
</FilesMatch>
|
||||||
|
<Directory /usr/lib/cgi-bin>
|
||||||
|
SSLOptions +StdEnvVars
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
BrowserMatch "MSIE [2-6]" \
|
||||||
|
nokeepalive ssl-unclean-shutdown \
|
||||||
|
downgrade-1.0 force-response-1.0
|
||||||
|
# MSIE 7 and newer should be able to use keepalive
|
||||||
|
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
|
||||||
|
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteCond %{HTTP_HOST} !review-dev.openstack.org
|
||||||
|
RewriteRule ^.*$ https://review-dev.openstack.org/
|
||||||
|
|
||||||
|
ProxyPassReverse / http://localhost:8081/
|
||||||
|
<Location />
|
||||||
|
Order allow,deny
|
||||||
|
Allow from all
|
||||||
|
ProxyPass http://localhost:8081/ retry=0
|
||||||
|
</Location>
|
||||||
|
|
||||||
|
|
||||||
|
</VirtualHost>
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
Run the following commands:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
a2enmod ssl proxy proxy_http rewrite
|
||||||
|
a2ensite gerrit
|
||||||
|
a2dissite default
|
||||||
|
|
||||||
|
Install Exim
|
||||||
|
------------
|
||||||
|
::
|
||||||
|
|
||||||
|
apt-get install exim4
|
||||||
|
dpkg-reconfigure exim4-config
|
||||||
|
|
||||||
|
Choose "internet site", otherwise select defaults
|
||||||
|
|
||||||
|
edit: /etc/default/exim4 ::
|
||||||
|
|
||||||
|
QUEUEINTERVAL='5m'
|
||||||
|
|
||||||
|
GitHub Setup
|
||||||
|
============
|
||||||
|
|
||||||
|
Generate an SSH key for Gerrit for use on GitHub
|
||||||
|
------------------------------------------------
|
||||||
|
::
|
||||||
|
|
||||||
|
sudo su - gerrit2
|
||||||
|
gerrit2@gerrit:~$ ssh-keygen
|
||||||
|
Generating public/private rsa key pair.
|
||||||
|
Enter file in which to save the key (/home/gerrit2/.ssh/id_rsa):
|
||||||
|
Created directory '/home/gerrit2/.ssh'.
|
||||||
|
Enter passphrase (empty for no passphrase):
|
||||||
|
Enter same passphrase again:
|
||||||
|
|
||||||
|
GitHub Configuration
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
#. create openstack-gerrit user on github
|
||||||
|
#. add gerrit2 ssh public key to openstack-gerrit user
|
||||||
|
#. create gerrit team in openstack org on github with push/pull access
|
||||||
|
#. add openstack-gerrit to gerrit team in openstack org
|
||||||
|
#. add public master repo to gerrit team in openstack org
|
||||||
|
#. save github host key in known_hosts
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
gerrit2@gerrit:~$ ssh git@github.com
|
||||||
|
The authenticity of host 'github.com (207.97.227.239)' can't be established.
|
||||||
|
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
|
||||||
|
Are you sure you want to continue connecting (yes/no)? yes
|
||||||
|
Warning: Permanently added 'github.com,207.97.227.239' (RSA) to the list of known hosts.
|
||||||
|
PTY allocation request failed on channel 0
|
||||||
|
|
||||||
|
You will also need to create the file ``github.secure.config`` in the gerrit2 user's home directory. The contents of this are as follows:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[github]
|
||||||
|
username = guthub-user
|
||||||
|
api_token = hexstring
|
||||||
|
|
||||||
|
The username should be the github username for gerrit to use when communicating
|
||||||
|
with github. The api_token can be found in github's account setting for the
|
||||||
|
account.
|
||||||
|
|
||||||
|
Gerrit Replication to GitHub
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
The file ``review_site/etc/replication.config`` is needed with the following
|
||||||
|
contents:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[remote "github"]
|
||||||
|
url = git@github.com:${name}.git
|
||||||
|
|
||||||
|
Jenkins / Gerrit Integration
|
||||||
|
============================
|
||||||
|
|
||||||
|
Create a Jenkins User in Gerrit
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
With the jenkins public key, as a gerrit admin user::
|
||||||
|
|
||||||
|
cat jenkins.pub | ssh -p29418 review.openstack.org gerrit create-account --ssh-key - --full-name Jenkins jenkins
|
||||||
|
|
||||||
|
Create "CI Systems" group in gerrit, make jenkins a member
|
||||||
|
|
||||||
|
Create a Gerrit Git Prep Job in Jenkins
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
When gating trunk with Jenkins, we want to test changes as they will
|
||||||
|
appear once merged by Gerrit, but the gerrit trigger plugin will, by
|
||||||
|
default, test them as submitted. If HEAD moves on while the change is
|
||||||
|
under review, it may end up getting merged with HEAD, and we want to
|
||||||
|
test the result.
|
||||||
|
|
||||||
|
To do that, make sure the "Hudson Template Project plugin" is
|
||||||
|
installed, then set up a new job called "Gerrit Git Prep", and add a
|
||||||
|
shell command build step (no other configuration)::
|
||||||
|
|
||||||
|
#!/bin/sh -x
|
||||||
|
git checkout $GERRIT_BRANCH
|
||||||
|
git reset --hard remotes/origin/$GERRIT_BRANCH
|
||||||
|
git merge FETCH_HEAD
|
||||||
|
CODE=$?
|
||||||
|
if [ ${CODE} -ne 0 ]; then
|
||||||
|
git reset --hard remotes/origin/$GERRIT_BRANCH
|
||||||
|
exit ${CODE}
|
||||||
|
fi
|
||||||
|
|
||||||
|
Later, we will configure Jenkins jobs that we want to behave this way
|
||||||
|
to use this build step.
|
||||||
|
|
||||||
|
Auto Review Expiry
|
||||||
|
==================
|
||||||
|
|
||||||
|
Puppet automatically installs a daily cron job called ``expire_old_reviews.py``
|
||||||
|
onto the gerrit servers. This script follows two rules:
|
||||||
|
|
||||||
|
#. If the review hasn't been touched in 2 weeks, mark as abandoned.
|
||||||
|
#. If there is a negative review and it hasn't been touched in 1 week, mark as
|
||||||
|
abandoned.
|
||||||
|
|
||||||
|
If your review gets touched by either of these rules it is possible to
|
||||||
|
unabandon a review on the gerrit web interface.
|
||||||
|
|
||||||
|
Launchpad Sync
|
||||||
|
==============
|
||||||
|
|
||||||
|
The launchpad user sync process consists of two scripts which are in
|
||||||
|
openstack/openstack-ci on github: sync_launchpad_gerrit.py and
|
||||||
|
insert_gerrit.py.
|
||||||
|
|
||||||
|
Both scripts should be run as gerrit2 on review.openstack.org
|
||||||
|
|
||||||
|
sync_launchpad_users.py runs and creates a python pickle file, users.pickle,
|
||||||
|
with all of the user and group information. This is a long process. (12
|
||||||
|
minutes)
|
||||||
|
|
||||||
|
insert_gerrit.py reads the pickle file and applies it to the MySQL database.
|
||||||
|
The gerrit caches must then be flushed.
|
||||||
|
|
||||||
|
Depends
|
||||||
|
-------
|
||||||
|
::
|
||||||
|
|
||||||
|
apt-get install python-mysqldb python-openid python-launchpadlib
|
||||||
|
|
||||||
|
Keys
|
||||||
|
----
|
||||||
|
|
||||||
|
The key for the launchpad sync user is in ~/.ssh/launchpad_rsa. Connecting
|
||||||
|
to Launchpad requires oauth authentication - so the first time
|
||||||
|
sync_launchpad_gerrit.py is run, it will display a URL. Open this URL in a
|
||||||
|
browser and log in to launchpad as the hudson-openstack user. Subsequent
|
||||||
|
runs will run with cached credentials.
|
||||||
|
|
||||||
|
Running
|
||||||
|
-------
|
||||||
|
::
|
||||||
|
|
||||||
|
cd openstack-ci
|
||||||
|
git pull
|
||||||
|
python sync_launchpad_gerrit.py
|
||||||
|
python insert_gerrit.py
|
||||||
|
ssh -i /home/gerrit2/.ssh/launchpadsync_rsa -p29418 review.openstack.org gerrit flush-caches
|
||||||
|
|
||||||
|
Gerrit IRC Bot
|
||||||
|
==============
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
Ensure there is an up-to-date checkout of openstack-ci in ~gerrit2.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
apt-get install python-irclib python-daemon
|
||||||
|
cp ~gerrit2/openstack-ci/gerritbot.init /etc/init.d
|
||||||
|
chmod a+x /etc/init.d/gerritbot
|
||||||
|
update-rc.d gerritbot defaults
|
||||||
|
su - gerrit2
|
||||||
|
ssh-keygen -f /home/gerrit2/.ssh/gerritbot_rsa
|
||||||
|
|
||||||
|
As a Gerrit admin, create a user for gerritbot::
|
||||||
|
|
||||||
|
cat ~gerrit2/.ssh/gerritbot_rsa | ssh -p29418 gerrit.openstack.org gerrit create-account --ssh-key - --full-name GerritBot gerritbot
|
||||||
|
|
||||||
|
Configure gerritbot, including which events should be announced in the
|
||||||
|
gerritbot.config file:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[ircbot]
|
||||||
|
nick=NICNAME
|
||||||
|
pass=PASSWORD
|
||||||
|
server=irc.freenode.net
|
||||||
|
channel=openstack-dev
|
||||||
|
port=6667
|
||||||
|
|
||||||
|
[gerrit]
|
||||||
|
user=gerritbot
|
||||||
|
key=/home/gerrit2/.ssh/gerritbot_rsa
|
||||||
|
host=review.openstack.org
|
||||||
|
port=29418
|
||||||
|
events=patchset-created, change-merged, x-vrif-minus-1, x-crvw-minus-2
|
||||||
|
|
||||||
|
Register an account with NickServ on FreeNode, and put the account and
|
||||||
|
password in the config file.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
sudo /etc/init.d/gerritbot start
|
||||||
|
|
||||||
|
Launchpad Bug Integration
|
||||||
|
=========================
|
||||||
|
|
||||||
|
In addition to the hyperlinks provided by the regex in gerrit.config,
|
||||||
|
we use a Gerrit hook to update Launchpad bugs when changes referencing
|
||||||
|
them are applied.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
Ensure an up-to-date checkout of openstack-ci is in ~gerrit2.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
apt-get install python-pyme
|
||||||
|
cp ~gerrit2/gerrit-hooks/change-merged ~gerrit2/review_site/hooks/
|
||||||
|
|
||||||
|
Create a GPG and register it with Launchpad::
|
||||||
|
|
||||||
|
gerrit2@gerrit:~$ gpg --gen-key
|
||||||
|
gpg (GnuPG) 1.4.11; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||||
|
This is free software: you are free to change and redistribute it.
|
||||||
|
There is NO WARRANTY, to the extent permitted by law.
|
||||||
|
|
||||||
|
Please select what kind of key you want:
|
||||||
|
(1) RSA and RSA (default)
|
||||||
|
(2) DSA and Elgamal
|
||||||
|
(3) DSA (sign only)
|
||||||
|
(4) RSA (sign only)
|
||||||
|
Your selection?
|
||||||
|
RSA keys may be between 1024 and 4096 bits long.
|
||||||
|
What keysize do you want? (2048)
|
||||||
|
Requested keysize is 2048 bits
|
||||||
|
Please specify how long the key should be valid.
|
||||||
|
0 = key does not expire
|
||||||
|
<n> = key expires in n days
|
||||||
|
<n>w = key expires in n weeks
|
||||||
|
<n>m = key expires in n months
|
||||||
|
<n>y = key expires in n years
|
||||||
|
Key is valid for? (0)
|
||||||
|
Key does not expire at all
|
||||||
|
Is this correct? (y/N) y
|
||||||
|
|
||||||
|
You need a user ID to identify your key; the software constructs the user ID
|
||||||
|
from the Real Name, Comment and Email Address in this form:
|
||||||
|
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
|
||||||
|
|
||||||
|
Real name: Openstack Gerrit
|
||||||
|
Email address: review@openstack.org
|
||||||
|
Comment:
|
||||||
|
You selected this USER-ID:
|
||||||
|
"Openstack Gerrit <review@openstack.org>"
|
||||||
|
|
||||||
|
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
|
||||||
|
You need a Passphrase to protect your secret key.
|
||||||
|
|
||||||
|
gpg: gpg-agent is not available in this session
|
||||||
|
You don't want a passphrase - this is probably a *bad* idea!
|
||||||
|
I will do it anyway. You can change your passphrase at any time,
|
||||||
|
using this program with the option "--edit-key".
|
||||||
|
|
||||||
|
We need to generate a lot of random bytes. It is a good idea to perform
|
||||||
|
some other action (type on the keyboard, move the mouse, utilize the
|
||||||
|
disks) during the prime generation; this gives the random number
|
||||||
|
generator a better chance to gain enough entropy.
|
||||||
|
|
||||||
|
gpg: /home/gerrit2/.gnupg/trustdb.gpg: trustdb created
|
||||||
|
gpg: key 382ACA7F marked as ultimately trusted
|
||||||
|
public and secret key created and signed.
|
||||||
|
|
||||||
|
gpg: checking the trustdb
|
||||||
|
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
|
||||||
|
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
|
||||||
|
pub 2048R/382ACA7F 2011-07-26
|
||||||
|
Key fingerprint = 21EF 7F30 C281 F61F 44CD EC48 7424 9762 382A CA7F
|
||||||
|
uid Openstack Gerrit <review@openstack.org>
|
||||||
|
sub 2048R/95F6FA4A 2011-07-26
|
||||||
|
|
||||||
|
gerrit2@gerrit:~$ gpg --send-keys --keyserver keyserver.ubuntu.com 382ACA7F
|
||||||
|
gpg: sending key 382ACA7F to hkp server keyserver.ubuntu.com
|
||||||
|
|
||||||
|
Log into the Launchpad account and add the GPG key to the account.
|
||||||
|
|
||||||
|
Adding New Projects
|
||||||
|
*******************
|
||||||
|
|
||||||
|
Creating a Project in Gerrit
|
||||||
|
============================
|
||||||
|
|
||||||
|
Using ssh key of a gerrit admin (you)::
|
||||||
|
|
||||||
|
ssh -p 29418 review.openstack.org gerrit create-project --name openstack/PROJECT
|
||||||
|
|
||||||
|
If the project is an API project (eg, image-api), we want it to share
|
||||||
|
some extra permissions that are common to all API projects (eg, the
|
||||||
|
OpenStack documentation coordinators can approve changes, see
|
||||||
|
:ref:`acl`). Run the following command to reparent the project if it
|
||||||
|
is an API project::
|
||||||
|
|
||||||
|
ssh -p 29418 gerrit.openstack.org gerrit set-project-parent --parent API-Projects openstack/PROJECT
|
||||||
|
|
||||||
|
Add yourself to the "Project Bootstrappers" group in Gerrit which will
|
||||||
|
give you permissions to push to the repo bypassing code review.
|
||||||
|
|
||||||
|
Do the initial push of the project with::
|
||||||
|
|
||||||
|
git push ssh://USERNAME@review.openstack.org:29418/openstack/PROJECT.git HEAD:refs/heads/master
|
||||||
|
git push --tags ssh://USERNAME@review.openstack.org:29418/openstack/PROJECT.git
|
||||||
|
|
||||||
|
Remove yourself from the "Project Bootstrappers" group, and then set
|
||||||
|
the access controls as specified in :ref:`acl`.
|
||||||
|
|
||||||
|
Have Jenkins Monitor a Gerrit Project
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
In jenkins, under source code management:
|
||||||
|
|
||||||
|
* select git
|
||||||
|
|
||||||
|
* url: ssh://jenkins@review.openstack.org:29418/openstack/project.git
|
||||||
|
* click "advanced"
|
||||||
|
|
||||||
|
* refspec: $GERRIT_REFSPEC
|
||||||
|
* branches: origin/$GERRIT_BRANCH
|
||||||
|
* click "advanced"
|
||||||
|
|
||||||
|
* choosing stragety: gerrit trigger
|
||||||
|
|
||||||
|
* select gerrit event under build triggers:
|
||||||
|
|
||||||
|
* Trigger on Comment Added
|
||||||
|
|
||||||
|
* Approval Category: APRV
|
||||||
|
* Approval Value: 1
|
||||||
|
|
||||||
|
* plain openstack/project
|
||||||
|
* path **
|
||||||
|
|
||||||
|
* Select "Add build step" under "Build"
|
||||||
|
|
||||||
|
* select "Use builders from another project"
|
||||||
|
* Template Project: "Gerrit Git Prep"
|
||||||
|
* make sure this build step is the first in the sequence
|
||||||
|
|
||||||
|
Create a Project in GitHub
|
||||||
|
==========================
|
||||||
|
|
||||||
|
As a github openstack admin:
|
||||||
|
|
||||||
|
* Visit https://github.com/organizations/openstack
|
||||||
|
* Click New Repository
|
||||||
|
* Visit the gerrit team admin page
|
||||||
|
* Add the new repository to the gerrit team
|
||||||
|
|
||||||
|
Pull requests can not be disabled for a project in Github, so instead
|
||||||
|
we have a script that runs from cron to close any open pull requests
|
||||||
|
with instructions to use Gerrit.
|
||||||
|
|
||||||
|
* Edit openstack/openstack-ci-puppet:manifests/site.pp
|
||||||
|
|
||||||
|
and add the project to the list of github projects in the gerrit class
|
||||||
|
for the gerrit.openstack.org node.
|
||||||
|
|
||||||
|
Migrating a Project from bzr
|
||||||
|
============================
|
||||||
|
|
||||||
|
Add the bzr PPA and install bzr-fastimport:
|
||||||
|
|
||||||
|
add-apt-repository ppa:bzr/ppa
|
||||||
|
apt-get update
|
||||||
|
apt-get install bzr-fastimport
|
||||||
|
|
||||||
|
Doing this from the bzr PPA is important to ensure at least version 0.10 of
|
||||||
|
bzr-fastimport.
|
||||||
|
|
||||||
|
Clone the git-bzr-ng from termie:
|
||||||
|
|
||||||
|
git clone https://github.com/termie/git-bzr-ng.git
|
||||||
|
|
||||||
|
In git-bzr-ng, you'll find a script, git-bzr. Put it somewhere in your path.
|
||||||
|
Then, to get a git repo which contains the migrated bzr branch, run:
|
||||||
|
|
||||||
|
git bzr clone lp:${BRANCHNAME} ${LOCATION}
|
||||||
|
|
||||||
|
So, for instance, to do glance, you would do:
|
||||||
|
|
||||||
|
git bzr clone lp:glance glance
|
||||||
|
|
||||||
|
And you will then have a git repo of glance in the glance dir. This git repo
|
||||||
|
is now suitable for uploading in to gerrit to become the new master repo.
|
||||||
|
|
||||||
|
Project Config
|
||||||
|
==============
|
||||||
|
|
||||||
|
There are a few options which need to be enabled on the project in the Admin
|
||||||
|
interface.
|
||||||
|
|
||||||
|
* Merge Strategy should be set to "Merge If Necessary"
|
||||||
|
* "Automatically resolve conflicts" should be enabled
|
||||||
|
* "Require Change-Id in commit message" should be enabled
|
||||||
|
* "Require a valid contributor agreement to upload" should be enabled
|
||||||
|
|
||||||
|
Optionally, if the PTL agrees to it:
|
||||||
|
|
||||||
|
* "Require the first line of the commit to be 50 characters or less" should
|
||||||
|
be enabled.
|
||||||
|
|
||||||
|
.. _acl:
|
||||||
|
|
||||||
|
Access Controls
|
||||||
|
***************
|
||||||
|
|
||||||
|
High level goals:
|
||||||
|
|
||||||
|
#. Anonymous users can read all projects.
|
||||||
|
#. All registered users can perform informational code review (+/-1)
|
||||||
|
on any project.
|
||||||
|
#. Jenkins can perform verification (blocking or approving: +/-1).
|
||||||
|
#. All registered users can create changes.
|
||||||
|
#. The OpenStack Release Manager and Jenkins can tag releases (push
|
||||||
|
annotated tags).
|
||||||
|
#. Members of $PROJECT-core group can perform full code review
|
||||||
|
(blocking or approving: +/- 2), and submit changes to be merged.
|
||||||
|
#. Members of openstack-release (Release Manager and PTLs), and
|
||||||
|
$PROJECT-drivers (PTL and release minded people) exclusively can
|
||||||
|
perform full code review (blocking or approving: +/- 2), and submit
|
||||||
|
changes to be merged on milestone-proposed branches.
|
||||||
|
#. Full code review (+/- 2) of API projects should be available to the
|
||||||
|
-core group of the corresponding implementation project as well as to
|
||||||
|
the OpenStack Documentation Coordinators.
|
||||||
|
#. Full code review of stable branches should be available to the
|
||||||
|
-core group of the project as well as the openstack-stable-maint
|
||||||
|
group.
|
||||||
|
|
||||||
|
To manage API project permissions collectively across projects, API
|
||||||
|
projects are reparented to the "API-Projects" meta-project instead of
|
||||||
|
"All-Projects". This causes them to inherit permissions from the
|
||||||
|
API-Projects project (which, in turn, inherits from All-Projects).
|
||||||
|
|
||||||
|
These permissions try to achieve the high level goals::
|
||||||
|
|
||||||
|
All Projects (metaproject):
|
||||||
|
refs/*
|
||||||
|
read: anonymous
|
||||||
|
push annotated tag: release managers, ci tools, project bootstrappers
|
||||||
|
forge author identity: registered users
|
||||||
|
forge committer identity: project bootstrappers
|
||||||
|
push (w/ force push): project bootstrappers
|
||||||
|
create reference: project bootstrappers, release managers
|
||||||
|
push merge commit: project bootstrappers
|
||||||
|
|
||||||
|
refs/for/refs/*
|
||||||
|
push: registered users
|
||||||
|
|
||||||
|
refs/heads/*
|
||||||
|
label code review:
|
||||||
|
-1/+1: registered users
|
||||||
|
-2/+2: project bootstrappers
|
||||||
|
label verified:
|
||||||
|
-2/+2: ci tools
|
||||||
|
-2/+2: project bootstrappers
|
||||||
|
-1/+1: external tools
|
||||||
|
label approved 0/+1: project bootstrappers
|
||||||
|
submit: ci tools
|
||||||
|
submit: project bootstrappers
|
||||||
|
|
||||||
|
refs/heads/milestone-proposed
|
||||||
|
label code review (exclusive):
|
||||||
|
-2/+2 openstack-release
|
||||||
|
-1/+1 registered users
|
||||||
|
label approved (exclusive): 0/+1: openstack-release
|
||||||
|
owner: openstack-release
|
||||||
|
|
||||||
|
refs/heads/stable/*
|
||||||
|
label code review (exclusive):
|
||||||
|
-2/+2 opestack-stable-maint
|
||||||
|
-1/+1 registered users
|
||||||
|
label approved (exclusive): 0/+1: opestack-stable-maint
|
||||||
|
|
||||||
|
refs/meta/config
|
||||||
|
read: project owners
|
||||||
|
|
||||||
|
API Projects (metaproject):
|
||||||
|
refs/*
|
||||||
|
owner: Administrators
|
||||||
|
|
||||||
|
refs/heads/*
|
||||||
|
label code review -2/+2: openstack-doc-core
|
||||||
|
label approved 0/+1: openstack-doc-core
|
||||||
|
|
||||||
|
project foo:
|
||||||
|
refs/*
|
||||||
|
owner: Administrators
|
||||||
|
|
||||||
|
refs/heads/*
|
||||||
|
label code review -2/+2: foo-core
|
||||||
|
label approved 0/+1: foo-core
|
||||||
|
|
||||||
|
refs/heads/milestone-proposed
|
||||||
|
label code review -2/+2: foo-drivers
|
||||||
|
label approved 0/+1: foo-drivers
|
||||||
|
|
||||||
|
Renaming a Project
|
||||||
|
******************
|
||||||
|
|
||||||
|
Renaming a project is not automated and is disruptive to developers,
|
||||||
|
so it should be avoided. Allow for an hour of downtime for the
|
||||||
|
project in question, and about 10 minutes of downtime for all of
|
||||||
|
Gerrit. All Gerrit changes, merged and open, will carry over, so
|
||||||
|
in-progress changes do not need to be merged before the move.
|
||||||
|
|
||||||
|
To rename a project:
|
||||||
|
|
||||||
|
#. Make it inacessible by editing the Access pane. Add a "read" ACL
|
||||||
|
for "Administrators", and mark it "exclusive". Be sure to save
|
||||||
|
changes.
|
||||||
|
|
||||||
|
#. Update the database::
|
||||||
|
|
||||||
|
update account_project_watches
|
||||||
|
set project_name = "openstack/OLD"
|
||||||
|
where project_name = "openstack/NEW";
|
||||||
|
|
||||||
|
update changes
|
||||||
|
set dest_project_name = "openstack/OLD"
|
||||||
|
where dest_project_name = "openstack/NEW";
|
||||||
|
|
||||||
|
#. Wait for Jenkins to be idle (or take it offline)
|
||||||
|
|
||||||
|
#. Stop Gerrit and move the Git repository::
|
||||||
|
|
||||||
|
/etc/init.d/gerrit stop
|
||||||
|
cd /home/gerrit2/review_site/git/openstack/
|
||||||
|
mv OLD.git/ NEW.git
|
||||||
|
/etc/init.d/gerrit start
|
||||||
|
|
||||||
|
#. (Bring Jenkins online if need be)
|
||||||
|
|
||||||
|
#. Rename the project in GitHub
|
||||||
|
|
||||||
|
#. Update Jenkins jobs te reference the new name. Rename the jobs
|
||||||
|
themselves as appropriate
|
||||||
|
|
||||||
|
#. Remove the read access ACL you set in the first step from project
|
||||||
|
|
||||||
|
#. Submit a change that updates .gitreview with the new location of the
|
||||||
|
project
|
||||||
|
|
||||||
|
Developers will either need to re-clone a new copy of the repository,
|
||||||
|
or manually update their remotes.
|
||||||
|
|
||||||
|
Deleting a User from Gerrit
|
||||||
|
***************************
|
||||||
|
|
||||||
|
This isn't normally necessary, but if you find that you need to
|
||||||
|
completely delete an account from Gerrit, here's how:
|
||||||
|
|
||||||
|
.. code-block:: mysql
|
||||||
|
|
||||||
|
delete from account_agreements where account_id=NNNN;
|
||||||
|
delete from account_diff_preferences where id=NNNN;
|
||||||
|
delete from account_external_ids where account_id=NNNN;
|
||||||
|
delete from account_group_members where account_id=NNNN;
|
||||||
|
delete from account_group_members_audit where account_id=NNNN;
|
||||||
|
delete from account_patch_reviews where account_id=NNNN;
|
||||||
|
delete from account_project_watches where account_id=NNNN;
|
||||||
|
delete from account_ssh_keys where account_id=NNNN;
|
||||||
|
delete from accounts where account_id=NNNN;
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
ssh review.openstack.org -p29418 gerrit flush-caches --all
|
||||||
|
|
||||||
|
Adding A New Project On The Command Line
|
||||||
|
****************************************
|
||||||
|
|
||||||
|
All of the steps involved in adding a new project to Gerrit can be
|
||||||
|
accomplished via the commandline, with the exception of creating a new repo
|
||||||
|
on github and adding the jenkins jobs.
|
||||||
|
|
||||||
|
First of all, add the .gitreview file to the repo that will be added. Then,
|
||||||
|
assuming an ssh config alias of `review` for the gerrit instance, as a person
|
||||||
|
in the Project Bootstrappers group::
|
||||||
|
|
||||||
|
ssh review gerrit create-project --name openstack/$PROJECT
|
||||||
|
git review -s
|
||||||
|
git push gerrit HEAD:refs/heads/master
|
||||||
|
git push --tags gerrit
|
||||||
|
|
||||||
|
At this point, the branch contents will be in gerrit, and the project config
|
||||||
|
settings and ACLs need to be set. These are maintained in a special branch
|
||||||
|
inside of git in gerrit. Check out the branch from git::
|
||||||
|
|
||||||
|
git fetch gerrit +refs/meta/*:refs/remotes/gerrit-meta/*
|
||||||
|
git checkout -b config remotes/gerrit-meta/config
|
||||||
|
|
||||||
|
There will be two interesting files, `groups` and `project.config`. `groups`
|
||||||
|
contains UUIDs and names of groups that will be referenced in
|
||||||
|
`project.config`. There is a helper script in the openstack-ci repo called
|
||||||
|
`get_group_uuid.py` which will fetch the UUID for a given group. For
|
||||||
|
$PROJECT-core and $PROJECT-drivers::
|
||||||
|
|
||||||
|
openstack-ci/gerrit/get_group_uuid.py $GROUP_NAME
|
||||||
|
|
||||||
|
And make entries in `groups` for each one of them. Next, edit
|
||||||
|
`project.config` to look like::
|
||||||
|
|
||||||
|
[access "refs/*"]
|
||||||
|
owner = group Administrators
|
||||||
|
[receive]
|
||||||
|
requireChangeId = true
|
||||||
|
requireContributorAgreement = true
|
||||||
|
[submit]
|
||||||
|
mergeContent = true
|
||||||
|
[access "refs/heads/*"]
|
||||||
|
label-Code-Review = -2..+2 group $PROJECT-core
|
||||||
|
label-Approved = +0..+1 group $PROJECT-core
|
||||||
|
[access "refs/heads/milestone-proposed"]
|
||||||
|
label-Code-Review = -2..+2 group $PROJECT-drivers
|
||||||
|
label-Approved = +0..+1 group $PROJECT-drivers
|
||||||
|
|
||||||
|
Replace $PROJECT with the name of the project.
|
||||||
|
|
||||||
|
Finally, commit the changes and push the config back up to Gerrit::
|
||||||
|
|
||||||
|
git commit -m "Initial project config"
|
||||||
|
git push gerrit HEAD:refs/meta/config
|
47
doc/index.rst
Normal file
47
doc/index.rst
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
.. OpenStack CI documentation master file, created by
|
||||||
|
sphinx-quickstart on Mon Jul 18 13:42:23 2011.
|
||||||
|
You can adapt this file completely to your liking, but it should at least
|
||||||
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
OpenStack Continuous Integration
|
||||||
|
================================
|
||||||
|
|
||||||
|
This documentation covers the installation and maintenance of the
|
||||||
|
Continuous Integration (CI) infrastructure used by OpenStack. It
|
||||||
|
may be of interest to people who may want to help develop this
|
||||||
|
infrastructure or integrate their tools into it. Some instructions
|
||||||
|
may be useful to other projects that want to set up similar CI
|
||||||
|
systems.
|
||||||
|
|
||||||
|
OpenStack developers or users do not need to read this documentation.
|
||||||
|
Instead, see http://wiki.openstack.org/ to learn how contribute to or
|
||||||
|
use OpenStack.
|
||||||
|
|
||||||
|
Howtos:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
third_party
|
||||||
|
stackforge
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
systems
|
||||||
|
jenkins
|
||||||
|
gerrit
|
||||||
|
puppet
|
||||||
|
puppet_modules
|
||||||
|
jenkins_jobs
|
||||||
|
meetbot
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
340
doc/jenkins.rst
Normal file
340
doc/jenkins.rst
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
:title: Jenkins Configuration
|
||||||
|
|
||||||
|
Jenkins
|
||||||
|
#######
|
||||||
|
|
||||||
|
Overview
|
||||||
|
********
|
||||||
|
|
||||||
|
Jenkins is a Continuous Integration system and the central control
|
||||||
|
system for the orchestration of both pre-merge testing and post-merge
|
||||||
|
actions such as packaging and publishing of documentation.
|
||||||
|
|
||||||
|
The overall design that Jenkins is a key part of implementing is that
|
||||||
|
all code should be reviewed and tested before being merged in to trunk,
|
||||||
|
and that as many tasks around review, testing, merging and release that
|
||||||
|
can be automated should be.
|
||||||
|
|
||||||
|
Jenkis is essentially a job queing system, and everything that is done
|
||||||
|
through Jenkins can be thought of as having a few discreet components:
|
||||||
|
|
||||||
|
* Triggers - What causes a job to be run
|
||||||
|
* Location - Where do we run a job
|
||||||
|
* Steps - What actions are taken when the job runs
|
||||||
|
* Results - What is the outcome of the job
|
||||||
|
|
||||||
|
The OpenStack Jenkins can be found at http://jenkins.openstack.org
|
||||||
|
|
||||||
|
OpenStack uses :doc:`gerrit` to manage code reviews, which in turns calls
|
||||||
|
Jenkins to test those reviews.
|
||||||
|
|
||||||
|
Authorization
|
||||||
|
*************
|
||||||
|
|
||||||
|
Jenkins is set up to use OpenID in a Single Sign On mode with Launchpad.
|
||||||
|
This means that all of the user and group information is managed via
|
||||||
|
Launchpad users and teams. In the Jenkins Security Matrix, a Launchpad team
|
||||||
|
name can be specified and any members of that team will be granted those
|
||||||
|
permissions. However, because of the way the information is processed, a
|
||||||
|
user will need to re-log in upon changing either team membership on
|
||||||
|
Launchpad, or changing that team's authorization in Jenkins for the new
|
||||||
|
privileges to take effect.
|
||||||
|
|
||||||
|
Integration Testing
|
||||||
|
*******************
|
||||||
|
|
||||||
|
TODO: How others can get involved in testing and integrating with
|
||||||
|
OpenStack Jenkins.
|
||||||
|
|
||||||
|
Rackspace Bare-Metal Testing Cluster
|
||||||
|
====================================
|
||||||
|
|
||||||
|
The CI team mantains a cluster of machines supplied by Rackspace to
|
||||||
|
perform bare-metal deployment and testing of OpenStack as a whole.
|
||||||
|
This installation is intended as a reference implementation of just
|
||||||
|
one of many possible testing platforms, all of which can be integrated
|
||||||
|
with the OpenStack Jenkins system. This is a cluster of several
|
||||||
|
physical machines meaning the test environment has access to all of
|
||||||
|
the native processor features, and real-world networking, including
|
||||||
|
tagged VLANs.
|
||||||
|
|
||||||
|
Each time the trunk repo is updated, a Jenkins job will deploy an
|
||||||
|
OpenStack cluster using devstack and then run the openstack-test-rax
|
||||||
|
test suite against the cluster.
|
||||||
|
|
||||||
|
Deployment and Testing Process
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
The cluster deployment is divided into two phases: base operating
|
||||||
|
system installation, and OpenStack installation. Because the
|
||||||
|
operating system install takes considerable time (15 to 30 minutes),
|
||||||
|
has external network resource dependencies (the distribution mirror),
|
||||||
|
and has no bearing on the outcome of the OpenStack tests themselves,
|
||||||
|
the process used here effectively snapshots the machines immediately
|
||||||
|
after the base OS install and before OpenStack is installed. LVM
|
||||||
|
snapshots and kexec are used to immediately return the cluster to a
|
||||||
|
newly installed state without incurring the additional time it would
|
||||||
|
take to install from scratch. The Jenkins testing job invokes the
|
||||||
|
process starting at :ref:`rax_openstack_install`.
|
||||||
|
|
||||||
|
Installation Server Configuration
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The CI team runs the Ubuntu Orchestra server (based on cobbler) on our
|
||||||
|
Jenkins slave node to manage the OS installation on the test machines.
|
||||||
|
The configuration for the Orchestra server is kept in the CI team's
|
||||||
|
puppet modules. If you want to set up your own system, Orchestra is
|
||||||
|
not required, any system capable of performing the following steps is
|
||||||
|
suitable. However, if you want to stand up a test system as quickly
|
||||||
|
and simply as possible, you may find it easiest to base your system on
|
||||||
|
the one the CI team uses. You may use the puppet modules yourself, or
|
||||||
|
follow the instructions below.
|
||||||
|
|
||||||
|
The CI team's Orchestra configuration module is at:
|
||||||
|
|
||||||
|
https://github.com/openstack/openstack-ci-puppet/tree/master/modules/orchestra
|
||||||
|
|
||||||
|
Install Orchestra
|
||||||
|
"""""""""""""""""
|
||||||
|
|
||||||
|
Install Ubuntu 11.10 (Oneiric) and Orchestra::
|
||||||
|
|
||||||
|
sudo apt-get install ubuntu-orchestra-server ipmitool
|
||||||
|
|
||||||
|
The install process will prompt you to enter a password for Cobbler.
|
||||||
|
Have one ready and keep it in a safe place. The procedure here will
|
||||||
|
not use it, but if you later want to use the Cobbler web interface,
|
||||||
|
you will need it.
|
||||||
|
|
||||||
|
Configure Orchestra
|
||||||
|
"""""""""""""""""""
|
||||||
|
|
||||||
|
Install the following files on the Orchestra server so that it deploys
|
||||||
|
machines with our LVM/kexec test framework.
|
||||||
|
|
||||||
|
We update the dnsmasq.conf cobbler template to add
|
||||||
|
"dhcp-ignore=tag:!known", and some site-specific network
|
||||||
|
configuration::
|
||||||
|
|
||||||
|
wget https://raw.github.com/openstack/openstack-ci-puppet/master/modules/orchestra/files/dnsmasq.template \
|
||||||
|
-O /etc/cobbler/dnsmasq.template
|
||||||
|
|
||||||
|
Our servers need a kernel module blacklisted in order to boot
|
||||||
|
correctly. If you don't need to blacklist any modules, you should
|
||||||
|
either create an empty file here, or remove the reference to this file
|
||||||
|
from the preseed file later::
|
||||||
|
|
||||||
|
wget https://raw.github.com/openstack/openstack-ci-puppet/master/modules/orchestra/files/openstack_module_blacklist \
|
||||||
|
-O /var/lib/cobbler/snippets/openstack_module_blacklist
|
||||||
|
|
||||||
|
This cobbler snippet uses cloud-init to set up the LVM/kexec
|
||||||
|
environment and configures TCP syslogging to the installation
|
||||||
|
server/Jenkins slave::
|
||||||
|
|
||||||
|
wget https://raw.github.com/openstack/openstack-ci-puppet/master/modules/orchestra/files/openstack_cloud_init \
|
||||||
|
-O /var/lib/cobbler/snippets/openstack_cloud_init
|
||||||
|
|
||||||
|
This snippet holds the mysql root password that will be configured at
|
||||||
|
install time. It's currently a static string, but you could
|
||||||
|
dynamically write this file, or simply replace it with something more
|
||||||
|
secure::
|
||||||
|
|
||||||
|
wget https://raw.github.com/openstack/openstack-ci-puppet/master/modules/orchestra/files/openstack_mysql_password \
|
||||||
|
-O /var/lib/cobbler/snippets/openstack_mysql_password
|
||||||
|
|
||||||
|
This preseed file manages the OS install on the test nodes. It
|
||||||
|
includes the snippets installed above::
|
||||||
|
|
||||||
|
wget https://raw.github.com/openstack/openstack-ci-puppet/master/modules/orchestra/files/openstack-test.preseed \
|
||||||
|
-O /var/lib/cobbler/kickstarts/openstack-test.preseed
|
||||||
|
|
||||||
|
The following sudoers configuration is needed to allow Jenkins to
|
||||||
|
control cobbler, remove syslog files from the test hosts before
|
||||||
|
starting new tests, and restart rsyslog::
|
||||||
|
|
||||||
|
wget https://raw.github.com/openstack/openstack-ci-puppet/master/modules/orchestra/files/orchestra-jenkins-sudoers -O /etc/sudoers.d/orchestra-jenkins
|
||||||
|
|
||||||
|
Replace the Orchestra rsyslog config file with a simpler one that logs
|
||||||
|
all information from remote hosts in one file per host::
|
||||||
|
|
||||||
|
wget https://raw.github.com/openstack/openstack-ci-puppet/master/modules/orchestra/files/99-orchestra.conf -O /etc/rsyslog.d/99-orchestra.conf
|
||||||
|
|
||||||
|
Make sure the syslog directories exist and restart rsyslog::
|
||||||
|
|
||||||
|
mkdir -p /var/log/orchestra/rsyslog/
|
||||||
|
chown -R syslog.syslog /var/log/orchestra/
|
||||||
|
restart rsyslog
|
||||||
|
|
||||||
|
Add an "OpenStack Test" system profile to cobbler that uses the
|
||||||
|
preseed file above::
|
||||||
|
|
||||||
|
cobbler profile add \
|
||||||
|
--name=natty-x86_64-ostest \
|
||||||
|
--parent=natty-x86_64 \
|
||||||
|
--kickstart=/var/lib/cobbler/kickstarts/openstack-test.preseed \
|
||||||
|
--kopts="priority=critical locale=en_US"
|
||||||
|
|
||||||
|
Add each of your systems to cobbler with a command similar to this
|
||||||
|
(you may need different kernel options)::
|
||||||
|
|
||||||
|
cobbler system add \
|
||||||
|
--name=baremetal1 \
|
||||||
|
--hostname=baremetal1 \
|
||||||
|
--profile=natty-x86_64-ostest \
|
||||||
|
--mac=00:11:22:33:44:55 \
|
||||||
|
--power-type=ipmitool \
|
||||||
|
--power-user=IPMI_USERNAME \
|
||||||
|
--power-pass=IPMI_PASS \
|
||||||
|
--power-address=IPMI_IP_ADDR \
|
||||||
|
--ip-address=SYSTEM_IP_ADDRESS \
|
||||||
|
--subnet=SYSTEM_SUBNET \
|
||||||
|
--kopts="netcfg/choose_interface=auto netcfg/dhcp_timeout=60 auto=true priority=critical"
|
||||||
|
|
||||||
|
When complete, have cobbler write out its configuration files::
|
||||||
|
|
||||||
|
cobbler sync
|
||||||
|
|
||||||
|
Set Up Jenkins Jobs
|
||||||
|
"""""""""""""""""""
|
||||||
|
|
||||||
|
We have Jenkins jobs to handle all of the tasks after the initial
|
||||||
|
Orchestra configuration so that we can easily run them at any time.
|
||||||
|
This includes the OS installation on the test nodes, even though we
|
||||||
|
don't run that often because the state is preserved in an LVM
|
||||||
|
snapshot, we may want to change the configuration used and make a new
|
||||||
|
snapshot. In that case we just need to trigger the Jenkins job again.
|
||||||
|
|
||||||
|
The Jenkins job that kicks off the operating system installation calls
|
||||||
|
the "baremetal-os-install.sh" script from the openstack-ci repo:
|
||||||
|
|
||||||
|
https://github.com/openstack/openstack-ci/blob/master/slave_scripts/baremetal-os-install.sh
|
||||||
|
|
||||||
|
That script instructs cobbler to install the OS on each of the test
|
||||||
|
nodes.
|
||||||
|
|
||||||
|
To speed up the devstack installation and avoid excessive traffic to
|
||||||
|
the pypi server, we build a PIP package cache on the installation
|
||||||
|
server. That is also an infrequent task that we configure as a
|
||||||
|
jenkins job. That calls:
|
||||||
|
|
||||||
|
https://github.com/openstack/openstack-ci/blob/master/slave_scripts/update-pip-cache.sh
|
||||||
|
|
||||||
|
That builds a PIP package cache that the test script later copies to
|
||||||
|
the test servers for use by devstack.
|
||||||
|
|
||||||
|
Run those two jobs, and once complete, the test nodes are ready to go.
|
||||||
|
|
||||||
|
This is the end of the operating system installation, and the system
|
||||||
|
is currently in the pristine state that will be used by the test
|
||||||
|
procedure (which is stored in the LVM volume "orig_root").
|
||||||
|
|
||||||
|
.. _rax_openstack_install:
|
||||||
|
|
||||||
|
OpenStack Installation
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
When the deployment and integration test job runs, it does the
|
||||||
|
following, each time starting from the pristine state arrived at the
|
||||||
|
end of the previous section.
|
||||||
|
|
||||||
|
Reset the Test Nodes
|
||||||
|
""""""""""""""""""""
|
||||||
|
|
||||||
|
The Jenkins deployment and test job first runs the deployment script:
|
||||||
|
|
||||||
|
https://github.com/openstack/openstack-ci/blob/master/slave_scripts/baremetal-deploy.sh
|
||||||
|
|
||||||
|
Which invokes the following script on each host to reset it to the
|
||||||
|
pristine state:
|
||||||
|
|
||||||
|
https://github.com/openstack/openstack-ci/blob/master/slave_scripts/lvm-kexec-reset.sh
|
||||||
|
|
||||||
|
Because kexec is in use, resetting the environment and rebooting into
|
||||||
|
the pristine state takes only about 3 seconds.
|
||||||
|
|
||||||
|
The deployment script then removes the syslog files from the previous
|
||||||
|
run and restarts rsyslog to re-open them. Once the first test host
|
||||||
|
finishes booting and brings up its network, OpenStack installation
|
||||||
|
starts.
|
||||||
|
|
||||||
|
Run devstack on the Test Nodes
|
||||||
|
""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
Devstack's build_bm_multi script is run, which invokes devstack on
|
||||||
|
each of the test nodes. First on the "head" node which runs all of
|
||||||
|
the OpenStack services for the remaining "compute" nodes.
|
||||||
|
|
||||||
|
Run Test Suite
|
||||||
|
""""""""""""""
|
||||||
|
|
||||||
|
Once devstack is complete, the test suite is run. All logs from the
|
||||||
|
test nodes should be sent via syslog to the Jenkins slave, and at the
|
||||||
|
end of the test, the logs are archived with the Job for developers to
|
||||||
|
inspect in case of problems.
|
||||||
|
|
||||||
|
Cluster Configuration
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Here are the configuration parameters of the CI team's test cluster.
|
||||||
|
The cluster is currently divided into three mini-clusters so that
|
||||||
|
independent Jenkins jobs can run in parallel on the different
|
||||||
|
clusters.
|
||||||
|
|
||||||
|
VLANs
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
+----+--------------------------------+
|
||||||
|
|VLAN| Description |
|
||||||
|
+====+================================+
|
||||||
|
|90 | Native VLAN |
|
||||||
|
+----+--------------------------------+
|
||||||
|
|91 | Internal cluster communication |
|
||||||
|
| | network: 192.168.91.0/24 |
|
||||||
|
+----+--------------------------------+
|
||||||
|
|92 | Public Internet (fake) |
|
||||||
|
| | network: 192.168.92.0/24 |
|
||||||
|
+----+--------------------------------+
|
||||||
|
|
||||||
|
Servers
|
||||||
|
~~~~~~~
|
||||||
|
The servers are located on the Rackspace network, only accessible via
|
||||||
|
VPN.
|
||||||
|
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
| Server | Primary IP | Management IP |
|
||||||
|
+===========+==============+===============+
|
||||||
|
|deploy-rax | 10.14.247.36 | 10.14.247.46 |
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
|baremetal1 | 10.14.247.37 | 10.14.247.47 |
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
|baremetal2 | 10.14.247.38 | 10.14.247.48 |
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
|baremetal3 | 10.14.247.39 | 10.14.247.49 |
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
|baremetal4 | 10.14.247.40 | 10.14.247.50 |
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
|baremetal5 | 10.14.247.41 | 10.14.247.51 |
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
|baremetal6 | 10.14.247.42 | 10.14.247.52 |
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
|baremetal7 | 10.14.247.43 | 10.14.247.53 |
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
|baremetal8 | 10.14.247.44 | 10.14.247.54 |
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
|baremetal9 | 10.14.247.45 | 10.14.247.55 |
|
||||||
|
+-----------+--------------+---------------+
|
||||||
|
|
||||||
|
deploy-rax
|
||||||
|
The deployment server and Jenkins slave. It deploys the servers
|
||||||
|
using Orchestra and Devstack, and runs the test framework. It
|
||||||
|
should not run any OpenStack components, but we can install
|
||||||
|
libraries or anything else needed to run tests.
|
||||||
|
|
||||||
|
baremetal1, baremetal4, baremetal7
|
||||||
|
Configured as "head" nodes to run nova, mysql, and glance. Each one
|
||||||
|
is the head node of a three node cluster including the two compute
|
||||||
|
nodes following it
|
||||||
|
|
||||||
|
baremetal2-3, baremtal5-6, baremetal8-9
|
||||||
|
Configured as compute nodes for each of the three mini-clusters.
|
||||||
|
|
133
doc/jenkins_jobs.rst
Normal file
133
doc/jenkins_jobs.rst
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
Jenkins Job Builder
|
||||||
|
===================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
In order to make the process of managing hundreds of Jenkins Jobs easier a
|
||||||
|
Python based utility was designed to take YAML based configurations and convert
|
||||||
|
those into jobs that are injected into Jenkins.
|
||||||
|
|
||||||
|
Adding a project
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The YAML scripts to make this work are stored in the ``openstack-ci-puppet``
|
||||||
|
repository in the ``modules/jenkins_jobs/files/projects/site/project.yaml``
|
||||||
|
directory. Where ``site`` is either `openstack` or `stackforge` and ``project``
|
||||||
|
is the name of the project the YAML file is for.
|
||||||
|
|
||||||
|
Once the YAML file is added the puppet module needs to be told that the project
|
||||||
|
is there. For example:
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
class { "jenkins_jobs":
|
||||||
|
site => "stackforge",
|
||||||
|
projects => ['reddwarf', 'ceilometer']
|
||||||
|
}
|
||||||
|
|
||||||
|
In this example the YAML files for `reddwarf` and `ceilometer` in the
|
||||||
|
`stackforge` projects directory will be executed.
|
||||||
|
|
||||||
|
YAML Format
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The bare minimum YAML needs to look like this:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
---
|
||||||
|
modules:
|
||||||
|
- properties
|
||||||
|
- scm
|
||||||
|
- assignednode
|
||||||
|
- trigger_none
|
||||||
|
- builders
|
||||||
|
- publisher_none
|
||||||
|
|
||||||
|
main:
|
||||||
|
name: 'job-name'
|
||||||
|
site: 'stackforge'
|
||||||
|
project: 'project'
|
||||||
|
authenticatedBuild: 'false'
|
||||||
|
disabled: 'false'
|
||||||
|
|
||||||
|
This example starts with ``---``, this signifies the start of a job, there can
|
||||||
|
be multiple jobs per project file.
|
||||||
|
The ``modules`` entry is an array of modules that should be loaded for this job.
|
||||||
|
Modules are located in the ``modules/jenkins_jobs/files/modules/`` directory
|
||||||
|
and are python scripts to generate the required XML. Each module has a comment
|
||||||
|
near the top showing the required YAML to support that module. The follow
|
||||||
|
modules are required to generate a correct XML that Jenkins will support:
|
||||||
|
|
||||||
|
* properties (supplies the <properties> XML data)
|
||||||
|
* scm (supplies the <scm> XML data, required even is scm is not used
|
||||||
|
* trigger_* (a trigger module is required)
|
||||||
|
* builders
|
||||||
|
* publisher_* (a publisher module is required)
|
||||||
|
|
||||||
|
Each module also requires a ``main`` section which has the main data for the
|
||||||
|
modules, inside this there is:
|
||||||
|
|
||||||
|
* name - the name of the job
|
||||||
|
* site - openstack or stackforge
|
||||||
|
* project - the name of the project
|
||||||
|
* authenticatedBuild - whether or not you need to be authenticated to hit the
|
||||||
|
build button
|
||||||
|
* disabled - whether or not this job should be disabled
|
||||||
|
|
||||||
|
Testing for Job Changes
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
The Jenkins Jobs builder maintains a special YAML file in
|
||||||
|
``~/.jenkins_jobs_cache.yml``. This contains an MD5 of every generated XML that
|
||||||
|
it builds. If it finds the XML is different then it will proceed to send this
|
||||||
|
to Jenkins, otherwise it is skipped. If a job is accidentally deleted then this
|
||||||
|
file should be modified or removed.
|
||||||
|
|
||||||
|
Sending a Job to Jenkins
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The Jenkins Jobs builder talks to Jenkins using the Jenkins API. This means
|
||||||
|
that it can create and modify jobs directly without the need to restart or
|
||||||
|
reload the Jenkins server. It also means that Jenkins will verify the XML and
|
||||||
|
cause the Jenkins Jobs builder to fail if there is a problem.
|
||||||
|
|
||||||
|
For this to work a configuration file is needed. This needs to be stored in
|
||||||
|
``/root/secret-files/jenkins_jobs.ini`` and puppet will automatically put it in
|
||||||
|
the right place. The format for this file is as follows:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
[jenkins]
|
||||||
|
user=username
|
||||||
|
password=password
|
||||||
|
url=jenkins_url
|
||||||
|
|
||||||
|
The password can be obtained by logging into the Jenkins user, clicking on your
|
||||||
|
username in the top-right, clicking on `Configure` and then `Show API Token`.
|
||||||
|
This API Token is your password for the API.
|
||||||
|
|
||||||
|
Adding a Module
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Modules need to contain a class with the same name as the filename. The basic
|
||||||
|
layout is:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import xml.etree.ElementTree as XML
|
||||||
|
|
||||||
|
class my_module(object):
|
||||||
|
def __init__(self, data):
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
def gen_xml(self, xml_parent):
|
||||||
|
|
||||||
|
The ``__init__`` function will be provided with ``data`` which is a Python
|
||||||
|
dictionary representing the YAML data for the job.
|
||||||
|
|
||||||
|
The ``gen_xml`` function will be provided with ``xml_parent`` which is an
|
||||||
|
XML ElementTree object to be modified.
|
89
doc/meetbot.rst
Normal file
89
doc/meetbot.rst
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
Meetbot
|
||||||
|
==============
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
The OpenStack CI team run a slightly modified
|
||||||
|
`Meetbot <http://wiki.debian.org/MeetBot>`_ to log IRC channel activity and
|
||||||
|
meeting minutes. Meetbot is a plugin for
|
||||||
|
`Supybot <http://sourceforge.net/projects/supybot/>`_ which adds meeting
|
||||||
|
support features to the Supybot IRC bot.
|
||||||
|
|
||||||
|
Supybot
|
||||||
|
-------
|
||||||
|
|
||||||
|
In order to run Meetbot you will need to get Supybot. You can find the latest
|
||||||
|
release `here <http://sourceforge.net/projects/supybot/files/>`_. Once you have
|
||||||
|
extracted the release you will want to read the ``INSTALL`` and
|
||||||
|
``doc/GETTING_STARTED`` files. Those two files should have enough information to
|
||||||
|
get you going, but there are other goodies in ``doc/``.
|
||||||
|
|
||||||
|
Once you have Supybot installed you will need to configure a bot. The
|
||||||
|
``supybot-wizard`` command can get you started with a basic config, or you can
|
||||||
|
have Puppet do the heavy lifting. The OpenStack CI Meetbot Puppet module creates
|
||||||
|
a configuration and documentation for that module is at
|
||||||
|
:ref:`Meetbot_Puppet_Module`.
|
||||||
|
|
||||||
|
One important config setting is ``supybot.reply.whenAddressedBy.chars``, which
|
||||||
|
sets the prefix character for this bot. This should be set to something other
|
||||||
|
than ``#`` as ``#`` will conflict with Meetbot (you can leave the setting blank
|
||||||
|
if you don't want a prefix character).
|
||||||
|
|
||||||
|
Meetbot
|
||||||
|
-------
|
||||||
|
|
||||||
|
The OpenStack CI Meetbot fork can be found at
|
||||||
|
https://github.com/openstack-ci/meetbot. Manual installation of the Meetbot
|
||||||
|
plugin is straightforward and documented in that repository's README.
|
||||||
|
OpenStack CI installs and configures Meetbot through Puppet. Documentation for
|
||||||
|
the Puppet module that does that can be found at :ref:`Meetbot_Puppet_Module`.
|
||||||
|
|
||||||
|
Voting
|
||||||
|
^^^^^^
|
||||||
|
|
||||||
|
The OpenStack CI Meetbot fork adds simple voting features. After a meeting has
|
||||||
|
been started a meeting chair can begin a voting block with the ``#startvote``
|
||||||
|
command. The command takes two arguments, a question posed to voters (ending
|
||||||
|
with a ``?``), and the valid voting options. If the second argument is missing
|
||||||
|
the default options are "Yes" and "No". For example:
|
||||||
|
|
||||||
|
``#startvote Should we vote now? Yes, No, Maybe``
|
||||||
|
|
||||||
|
Meeting participants vote using the ``#vote`` command. This command takes a
|
||||||
|
single argument, which should be one of the options listed for voting by the
|
||||||
|
``#startvote`` command. For example:
|
||||||
|
|
||||||
|
``#vote Yes``
|
||||||
|
|
||||||
|
Note that you can vote multiple times, but only your last vote will count.
|
||||||
|
|
||||||
|
One can check the current vote tallies useing the ``#showvote`` command, which
|
||||||
|
takes no arguments. This will list the number of votes and voters for each item
|
||||||
|
that has votes.
|
||||||
|
|
||||||
|
When the meeting chair(s) are ready to stop the voting process they can issue
|
||||||
|
the ``#endvote`` command, which takes no arguments. Doing so will report the
|
||||||
|
voting results and log these results in the meeting minutes.
|
||||||
|
|
||||||
|
A somewhat contrived voting example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
foo | #startvote Should we vote now? Yes, No, Maybe
|
||||||
|
meetbot | Begin voting on: Should we vote now? Valid vote options are Yes, No, Maybe.
|
||||||
|
meetbot | Vote using '#vote OPTION'. Only your last vote counts.
|
||||||
|
foo | #vote Yes
|
||||||
|
bar | #vote Absolutely
|
||||||
|
meetbot | bar: Absolutely is not a valid option. Valid options are Yes, No, Maybe.
|
||||||
|
bar | #vote Yes
|
||||||
|
bar | #showvote
|
||||||
|
meetbot | Yes (2): foo, bar
|
||||||
|
foo | #vote No
|
||||||
|
foo | #showvote
|
||||||
|
meetbot | Yes (1): bar
|
||||||
|
meetbot | No (1): foo
|
||||||
|
foo | #endvote
|
||||||
|
meetbot | Voted on "Should we vote now?" Results are
|
||||||
|
meetbot | Yes (1): bar
|
||||||
|
meetbot | No (1): foo
|
97
doc/puppet.rst
Normal file
97
doc/puppet.rst
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
Puppet Master
|
||||||
|
=============
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
Instead of using a cron job, StackForge uses a puppet master to host the puppet
|
||||||
|
manifests and modules. The other nodes then connect to this as puppet agents
|
||||||
|
to get their configuration.
|
||||||
|
|
||||||
|
Puppet Master
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The puppet master is setup using a combination of Apache and mod passenger to
|
||||||
|
ship the data to the clients. To install this:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo apt-get install puppet puppetmaster puppetmaster-passenger
|
||||||
|
|
||||||
|
Note that this may break the first time round due to not-so-perfect packaging
|
||||||
|
involved. You will also need to stop the puppetmaster service and edit the
|
||||||
|
``/etc/defaults/puppetmaster`` file to change ``START=no``. Puppetmaster needs
|
||||||
|
to run first because it creates the SSL CA used to sign puppet agents (the
|
||||||
|
passenger service does not do this).
|
||||||
|
|
||||||
|
This should then allow you to start ``apache2`` which in turn will automatically
|
||||||
|
manage the puppet master.
|
||||||
|
|
||||||
|
Files for puppet master are stored in ``/etc/puppet`` with the subdirectories
|
||||||
|
``manifests`` and ``modules`` being the important ones. In StackForge we have
|
||||||
|
a ``root`` cron job that automatically populates these from our puppet git
|
||||||
|
repository as follows:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
*/15 * * * * sleep $((RANDOM\%600)) && cd /srv/openstack-ci-puppet && /usr/bin/git pull -q && cp /srv/openstack-ci-puppet/manifests/users.pp /etc/puppet/manifests/ && cp /srv/openstack-ci-puppet/manifests/stackforge.pp /etc/puppet/manifests/site.pp && cp -a /srv/openstack-ci-puppet/modules/ /etc/puppet/
|
||||||
|
|
||||||
|
Adding a node
|
||||||
|
-------------
|
||||||
|
|
||||||
|
On the new server connecting to the puppet master:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo apt-get install puppet
|
||||||
|
|
||||||
|
Then edit the ``/etc/default/puppet`` file to look like this:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
# Defaults for puppet - sourced by /etc/init.d/puppet
|
||||||
|
|
||||||
|
# Start puppet on boot?
|
||||||
|
START=yes
|
||||||
|
|
||||||
|
# Startup options
|
||||||
|
DAEMON_OPTS="--server puppet.stackforge.org"
|
||||||
|
|
||||||
|
You can then start the puppet agent with:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo service puppet start
|
||||||
|
|
||||||
|
Once the node has started it will make a request to the puppet master to have
|
||||||
|
its SSL cert signed. On the puppet master:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo puppet cert list
|
||||||
|
|
||||||
|
You should get a list of entries similar to the one below::
|
||||||
|
|
||||||
|
review.novalocal (44:18:BB:DF:08:50:62:70:17:07:82:1F:D5:70:0E:BF)
|
||||||
|
|
||||||
|
If you see the new node there you can sign its cert on the puppet master with:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo puppet cert sign review.novalocal
|
||||||
|
|
||||||
|
Now that it is signed the puppet agent will execute any instructions for its
|
||||||
|
node on the next run (default is every 30 minutes). You can trigger this
|
||||||
|
earlier by restarting the puppet service on the new node.
|
||||||
|
|
||||||
|
Important Notes
|
||||||
|
---------------
|
||||||
|
|
||||||
|
#. The hostname of the nodes **must** match the the forward looking for the DNS.
|
||||||
|
For example the server pointed to with the DNS entry
|
||||||
|
``jenkins.stackforge.org`` must have the hostname ``jenkins.stackforge.org``
|
||||||
|
otherwise the SSL signing or standard run will fail.
|
||||||
|
|
||||||
|
#. Make sure the site manifest **does not** include the puppet cron job, this
|
||||||
|
conflicts with puppet master and can cause issues. The initial puppet run
|
||||||
|
that create users should be done using the puppet agent configuration above.
|
276
doc/puppet_modules.rst
Normal file
276
doc/puppet_modules.rst
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
Puppet Modules
|
||||||
|
==============
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
Much of the OpenStack project infrastructure is deployed and managed using
|
||||||
|
puppet.
|
||||||
|
The OpenStack CI team manage a number of custom puppet modules outlined in this
|
||||||
|
document.
|
||||||
|
|
||||||
|
Doc Server
|
||||||
|
----------
|
||||||
|
|
||||||
|
The doc_server module configures nginx [3]_ to serve the documentation for
|
||||||
|
several specified OpenStack projects. At the moment to add a site to this
|
||||||
|
you need to edit ``modules/doc_server/manifests/init.pp`` and add a line as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
doc_server::site { "swift": }
|
||||||
|
|
||||||
|
In this example nginx will be configured to serve ``swift.openstack.org``
|
||||||
|
from ``/srv/docs/swift`` and ``swift.openstack.org/tarballs/`` from
|
||||||
|
``/srv/tarballs/swift``
|
||||||
|
|
||||||
|
Lodgeit
|
||||||
|
-------
|
||||||
|
|
||||||
|
The lodgeit module installs and configures lodgeit [1]_ on required servers to
|
||||||
|
be used as paste installations. For OpenStack we use
|
||||||
|
`a fork <https://github.com/openstack-ci/lodgeit>`_ of this which is based on
|
||||||
|
one with bugfixes maintained by
|
||||||
|
`dcolish <https://bitbucket.org/dcolish/lodgeit-main>`_ but adds back missing
|
||||||
|
anti-spam features required by Openstack.
|
||||||
|
|
||||||
|
Puppet will configure lodgeit to use drizzle [2]_ as a database backend,
|
||||||
|
nginx [3]_ as a front-end proxy and upstart scripts to run the lodgeit
|
||||||
|
instances. It will store and maintain local branch of the the mercurial
|
||||||
|
repository for lodgeit in ``/tmp/lodgeit-main``.
|
||||||
|
|
||||||
|
To use this module you need to add something similar to the following in the
|
||||||
|
main ``site.pp`` manifest:
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
node "paste.openstack.org" {
|
||||||
|
include openstack_server
|
||||||
|
include lodgeit
|
||||||
|
lodgeit::site { "openstack":
|
||||||
|
port => "5000",
|
||||||
|
image => "header-bg2.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
lodgeit::site { "drizzle":
|
||||||
|
port => "5001"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
In this example we include the lodgeit module which will install all the
|
||||||
|
pre-requisites for Lodgeit as well as creating a checkout ready.
|
||||||
|
The ``lodgeit::site`` calls create the individual paste sites.
|
||||||
|
|
||||||
|
The name in the ``lodgeit::site`` call will be used to determine the URL, path
|
||||||
|
and name of the site. So "openstack" will create ``paste.openstack.org``,
|
||||||
|
place it in ``/srv/lodgeit/openstack`` and give it an upstart script called
|
||||||
|
``openstack-paste``. It will also change the h1 tag to say "Openstack".
|
||||||
|
|
||||||
|
The port number given needs to be a unique port which the lodgeit service will
|
||||||
|
run on. The puppet script will then configure nginx to proxy to that port.
|
||||||
|
|
||||||
|
Finally if an image is given that will be used instead of text inside the h1
|
||||||
|
tag of the site. The images need to be stored in the ``modules/lodgeit/files``
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Lodgeit Backups
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The lodgeit module will automatically create a git repository in ``/var/backups/lodgeit_db``. Inside this every site will have its own SQL file, for example "openstack" will have a file called ``openstack.sql``. Every day a cron job will update the SQL file (one job per file) and commit it to the git repository.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Ideally the SQL files would have a row on every line to keep the diffs stored
|
||||||
|
in git small, but ``drizzledump`` does not yet support this.
|
||||||
|
|
||||||
|
Planet
|
||||||
|
------
|
||||||
|
|
||||||
|
The planet module installs Planet Venus [4]_ along with required dependancies
|
||||||
|
on a server. It also configures specified planets based on options given.
|
||||||
|
|
||||||
|
Planet Venus works by having a cron job which creates static files. In this
|
||||||
|
module the static files are served using nginx [3]_.
|
||||||
|
|
||||||
|
To use this module you need to add something similar to the following into the
|
||||||
|
main ``site.pp`` manifest:
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
node "planet.openstack.org" {
|
||||||
|
include planet
|
||||||
|
|
||||||
|
planet::site { "openstack":
|
||||||
|
git_url => "https://github.com/openstack/openstack-planet.git"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
In this example the name "openstack" is used to create the site
|
||||||
|
``paste.openstack.org``. The site will be served from
|
||||||
|
``/srv/planet/openstack/`` and the checkout of the ``git_url`` supplied will
|
||||||
|
be maintained in ``/var/lib/planet/openstack/``.
|
||||||
|
|
||||||
|
This module will also create a cron job to pull new feed data 3 minutes past each hour.
|
||||||
|
|
||||||
|
The ``git_url`` parameter needs to point to a git repository which stores the
|
||||||
|
planet.ini configuration for the planet (which stores a list of feeds) and any required theme data. This will be pulled every time puppet is run.
|
||||||
|
|
||||||
|
.. _Meetbot_Puppet_Module:
|
||||||
|
|
||||||
|
Meetbot
|
||||||
|
-------
|
||||||
|
|
||||||
|
The meetbot module installs and configures meetbot [5]_ on a server. The
|
||||||
|
meetbot version installed by this module is pulled from the
|
||||||
|
`Openstack CI fork <https://github.com/openstack-ci/meetbot/>`_ of the project.
|
||||||
|
|
||||||
|
It also configures nginix [3]_ to be used for accessing the public IRC logs of
|
||||||
|
the meetings.
|
||||||
|
|
||||||
|
To use this module simply add a section to the site manifest as follows:
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
node "eavesdrop.openstack.org" {
|
||||||
|
include openstack_cron
|
||||||
|
class { 'openstack_server':
|
||||||
|
iptables_public_tcp_ports => [80]
|
||||||
|
}
|
||||||
|
include meetbot
|
||||||
|
|
||||||
|
meetbot::site { "openstack":
|
||||||
|
nick => "openstack",
|
||||||
|
network => "FreeNode",
|
||||||
|
server => "chat.us.freenode.net:7000",
|
||||||
|
url => "eavesdrop.openstack.org",
|
||||||
|
channels => "#openstack #openstack-dev #openstack-meeting",
|
||||||
|
use_ssl => "True"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
You will also need a file ``/root/secret-files/name-nickserv.pass`` where `name`
|
||||||
|
is the name specified in the call to the module (`openstack` in this case).
|
||||||
|
|
||||||
|
Each call to meetbot::site will create setup a meebot in ``/var/lib/meetbot``
|
||||||
|
under a subdirectory of the name of the call to the module. It will also
|
||||||
|
configure nginix to go to that site when the ``/meetings`` directory is
|
||||||
|
specified on the URL.
|
||||||
|
|
||||||
|
The puppet module also creates startup scripts for meetbot and will ensure that
|
||||||
|
it is running on each puppet run.
|
||||||
|
|
||||||
|
Gerrit
|
||||||
|
------
|
||||||
|
|
||||||
|
The Gerrit puppet module configures the basic needs of a Gerrit server. It does
|
||||||
|
not (yet) install Gerrit itself and mostly deals with the configuration files
|
||||||
|
and skinning of Gerrit.
|
||||||
|
|
||||||
|
Using Gerrit
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Gerrit is set up when the following class call is added to a node in the site
|
||||||
|
manifest:
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
|
||||||
|
class { 'gerrit':
|
||||||
|
canonicalweburl => "https://review.stackforge.org/",
|
||||||
|
email => "review@stackforge.org",
|
||||||
|
github_projects => [ {
|
||||||
|
name => 'stackforge/MRaaS',
|
||||||
|
close_pull => 'true'
|
||||||
|
} ],
|
||||||
|
logo => 'stackforge.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
Most of these options are self-explanitory. The github_projects is a list of
|
||||||
|
all projects in GitHub which are managed by the gerrit server.
|
||||||
|
|
||||||
|
Skinning
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
Gerrit is skinned using files supplied by the puppet module. The skin is
|
||||||
|
automatically applied as soon as the module is executed. In the site manifest
|
||||||
|
setting the logo is important:
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
|
||||||
|
class { 'gerrit':
|
||||||
|
...
|
||||||
|
logo => 'openstack.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
This specifies a PNG file which must be stored in the ``modules/gerrit/files/``
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Jenkins Master
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The Jenkins Master puppet module installs and supplies a basic Jenkins
|
||||||
|
configuration. It also supplies a skin to Jenkins to make it look more like an
|
||||||
|
OpenStack site. It does not (yet) install the additional Jenkins plugins used
|
||||||
|
by the OpenStack project.
|
||||||
|
|
||||||
|
Using Jenkins Master
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
In the site manifest a node can be configured to be a Jenkins master simply by
|
||||||
|
adding the class call below:
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
|
||||||
|
class { 'jenkins_master':
|
||||||
|
site => 'jenkins.openstack.org',
|
||||||
|
serveradmin => 'webmaster@openstack.org',
|
||||||
|
logo => 'openstack.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
The ``site`` and ``serveradmin`` parameters are used to configure Apache. You
|
||||||
|
will also need in this instance the following files for Apache to start::
|
||||||
|
|
||||||
|
/etc/ssl/certs/jenkins.openstack.org.pem
|
||||||
|
/etc/ssl/private/jenkins.openstack.org.key
|
||||||
|
/etc/ssl/certs/intermediate.pem
|
||||||
|
|
||||||
|
The ``jenkins.openstack.org`` is replace by the setting in the ``site``
|
||||||
|
parameter.
|
||||||
|
|
||||||
|
Skinning
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
The Jenkins skin uses the `Simple Theme Plugin
|
||||||
|
<http://wiki.jenkins-ci.org/display/JENKINS/Simple+Theme+Plugin>`_ for Jenkins.
|
||||||
|
The puppet module will install and configure most aspects of the skin
|
||||||
|
automatically, with a few adjustments needed.
|
||||||
|
|
||||||
|
In the site.pp file the ``logo`` parameter is important:
|
||||||
|
|
||||||
|
.. code-block:: ruby
|
||||||
|
|
||||||
|
class { 'jenkins_master':
|
||||||
|
...
|
||||||
|
logo => 'openstack.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
This relates to a PNG file that must be in the ``modules/jenkins_master/files/``
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Once puppet installs this and the plugin is installed you need to go into
|
||||||
|
``Manage Jenkins -> Configure System`` and look for the ``Theme`` heading.
|
||||||
|
Assuming we are skinning the main OpenStack Jenkins site, in the ``CSS`` box
|
||||||
|
enter
|
||||||
|
``https://jenkins.openstack.org/plugin/simple-theme-plugin/openstack.css`` and
|
||||||
|
in the ``JS`` box enter
|
||||||
|
``https://jenkins.openstack.org/plugin/simple-theme-plugin/openstack.js``.
|
||||||
|
|
||||||
|
.. rubric:: Footnotes
|
||||||
|
.. [1] `Lodgeit homepage <http://www.pocoo.org/projects/lodgeit/>`_
|
||||||
|
.. [2] `Drizzle homepage <http://www.drizzle.org/>`_
|
||||||
|
.. [3] `nginx homepage <http://nginx.org/en/>`_
|
||||||
|
.. [4] `Planet Venus homepage <http://intertwingly.net/code/venus/docs/index.html>`_
|
||||||
|
.. [5] `Meetbot homepage <http://wiki.debian.org/MeetBot>`_
|
41
doc/stackforge.rst
Normal file
41
doc/stackforge.rst
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
HOWTO: Add a Project to StackForge
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
StackForge is a Gerrit review and Jenkins CI setup similar to that of the main
|
||||||
|
OpenStack project but for use with projects that are not under the main
|
||||||
|
OpenStack umbrella.
|
||||||
|
|
||||||
|
Any project can be added to StackForge as long as it is related to OpenStack in
|
||||||
|
some way.
|
||||||
|
|
||||||
|
Launchpad
|
||||||
|
---------
|
||||||
|
|
||||||
|
All the developers of the project need to sign up to Launchpad and a team is
|
||||||
|
needed for the core project reviewers to join. This team also needs to be
|
||||||
|
a sub-team of the `OpenStack team <https://launchpad.net/~openstack>`_ so that
|
||||||
|
Gerrit will be able to see it.
|
||||||
|
|
||||||
|
GitHub
|
||||||
|
------
|
||||||
|
|
||||||
|
If you already have a branch on GitHub for the project this will need moving to
|
||||||
|
the StackForge GitHub organization. Otherwise a new branch will need creating
|
||||||
|
for you. The OpenStack Core Infrastructure team can assist in this.
|
||||||
|
|
||||||
|
Jenkins and Gerrit
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Until the setup is more automated the OpenStack Core Infrastructure team will
|
||||||
|
need to do the Jenkins and Gerrit portion of the setup too. If you project is
|
||||||
|
Python based we have a `Project Testing Interface <http://wiki.openstack.org/ProjectTestingInterface>`_ that we prefer you use. Otherwise please let the CI
|
||||||
|
team know the testing requirements for Jenkins.
|
||||||
|
|
||||||
|
Contacting the CI Team
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
The best way to get the CI team to help with the above steps is to `file a CI bug <https://bugs.launchpad.net/openstack-ci>`_. We are also available on the
|
||||||
|
#openstack-infra IRC channel or to the `CI Admins email address <mailto:openstack-ci-admins@lists.launchpad.net>`_.
|
77
doc/systems.rst
Normal file
77
doc/systems.rst
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
:title: Infrastructure Systems
|
||||||
|
|
||||||
|
Infrastructure Systems
|
||||||
|
######################
|
||||||
|
|
||||||
|
The OpenStack CI team maintains a number of systems that are critical
|
||||||
|
to the operation of the OpenStack project. At the time of writing,
|
||||||
|
these include:
|
||||||
|
|
||||||
|
* Gerrit (review.openstack.org)
|
||||||
|
* Jenkins (jenkins.openstack.org)
|
||||||
|
* community.openstack.org
|
||||||
|
|
||||||
|
Additionally the team maintains the project sites on Launchpad and
|
||||||
|
GitHub. The following policies have been adopted to ensure the
|
||||||
|
continued and secure operation of the project.
|
||||||
|
|
||||||
|
SSH Access
|
||||||
|
**********
|
||||||
|
|
||||||
|
For any of the systems managed by the CI team, the following practices
|
||||||
|
must be observed for SSH access:
|
||||||
|
|
||||||
|
* SSH access is only permitted with SSH public/private key
|
||||||
|
authentication.
|
||||||
|
* Users must use a strong passphrase to protect their private key. A
|
||||||
|
passphrase of several words, at least one of which is not in a
|
||||||
|
dictionary is advised, or a random string of at least 16
|
||||||
|
characters.
|
||||||
|
* To mitigate the inconvenience of using a long passphrase, users may
|
||||||
|
want to use an SSH agent so that the passphrase is only requested
|
||||||
|
once per desktop session.
|
||||||
|
* Users private keys must never be stored anywhere except their own
|
||||||
|
workstation(s). In particular, they must never be stored on any
|
||||||
|
remote server.
|
||||||
|
* If users need to 'hop' from a server or bastion host to another
|
||||||
|
machine, they must not copy a private key to the intermediate
|
||||||
|
machine (see above). Instead SSH agent forwarding may be used.
|
||||||
|
However due to the potential for a compromised intermediate machine
|
||||||
|
to ask the agent to sign requests without the users knowledge, in
|
||||||
|
this case only an SSH agent that interactively prompts the user
|
||||||
|
each time a signing request (ie, ssh-agent, but not gnome-keyring)
|
||||||
|
is received should be used, and the SSH keys should be added with
|
||||||
|
the confirmation constraint ('ssh-add -c').
|
||||||
|
* The number of SSH keys that are configured to permit access to
|
||||||
|
OpenStack machines should be kept to a minimum.
|
||||||
|
* OpenStack CI machines must use puppet to centrally manage and
|
||||||
|
configure user accounts, and the SSH authorized_keys files from the
|
||||||
|
openstack-ci-puppet repository.
|
||||||
|
* SSH keys should be periodically rotated (at least once per year).
|
||||||
|
During rotation, a new key can be added to puppet for a time, and
|
||||||
|
then the old one removed.
|
||||||
|
|
||||||
|
GitHub Access
|
||||||
|
*************
|
||||||
|
|
||||||
|
To ensure that code review and testing are not bypassed in the public
|
||||||
|
Git repositories, only Gerrit will be permitted to commit code to
|
||||||
|
OpenStack repositories. Because GitHub always allows project
|
||||||
|
administrators to commit code, accounts that have access to manage the
|
||||||
|
GitHub projects necessarily will have commit access to the
|
||||||
|
repositories. Therefore, to avoid inadvertent commits to the public
|
||||||
|
repositories, unique administrative-only accounts must be used to
|
||||||
|
manage the OpenStack GitHub organization and projects. These accounts
|
||||||
|
will not be used to check out or commit code for any project.
|
||||||
|
|
||||||
|
Launchpad Teams
|
||||||
|
***************
|
||||||
|
|
||||||
|
Each OpenStack project should have the following teams on Launchpad:
|
||||||
|
|
||||||
|
* foo -- contributors to project 'foo'
|
||||||
|
* foo-core -- core developers
|
||||||
|
* foo-bugs -- people interested in receieving bug reports
|
||||||
|
* foo-drivers -- people who may approve and target blueprints
|
||||||
|
|
||||||
|
The openstack-admins team should be a member of each of those teams.
|
153
doc/third_party.rst
Normal file
153
doc/third_party.rst
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
HOWTO: Third Party Testing
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
Gerrit has an event stream which can be subscribed to, using this it is possible
|
||||||
|
to test commits against testing systems beyond those supplied by OpenStack's
|
||||||
|
Jenkins setup. It is also possible for these systems to feed information back
|
||||||
|
into Gerrit and they can also leave non-gating votes on Gerrit review requests.
|
||||||
|
|
||||||
|
An example of one such system is `Smokestack <http://smokestack.openstack.org/>`_.
|
||||||
|
Smokestack reads the Gerrit event stream and runs it's own tests on the commits.
|
||||||
|
If one of the tests fails it will publish information and links to the failure
|
||||||
|
on the review in Gerrit.
|
||||||
|
|
||||||
|
Reading the Event Stream
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
It is possible to use ssh to connect to ``review.openstack.org`` on port 29418
|
||||||
|
with your ssh key if you are signed up as an OpenStack developer on Launchpad.
|
||||||
|
|
||||||
|
This will give you a real-time JSON stream of events happening inside Gerrit.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ ssh -p 29418 review.example.com gerrit stream-events
|
||||||
|
|
||||||
|
Will give a stream with an output like this (line breaks and indentation added
|
||||||
|
in this document for readability, the read JSON will be all one line per event):
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
{"type":"comment-added","change":
|
||||||
|
{"project":"openstack/keystone","branch":"stable/essex","topic":"bug/969088","id":"I18ae38af62b4c2b2423e20e436611fc30f844ae1","number":"7385","subject":"Make import_nova_auth only create roles which don\u0027t already exist","owner":
|
||||||
|
{"name":"Chuck Short","email":"chuck.short@canonical.com","username":"zulcss"},"url":"https://review.openstack.org/7385"},
|
||||||
|
"patchSet":
|
||||||
|
{"number":"1","revision":"aff45d69a73033241531f5e3542a8d1782ddd859","ref":"refs/changes/85/7385/1","uploader":
|
||||||
|
{"name":"Chuck Short","email":"chuck.short@canonical.com","username":"zulcss"},
|
||||||
|
"createdOn":1337002189},
|
||||||
|
"author":
|
||||||
|
{"name":"Mark McLoughlin","email":"markmc@redhat.com","username":"markmc"},
|
||||||
|
"approvals":
|
||||||
|
[{"type":"CRVW","description":"Code Review","value":"2"},{"type":"APRV","description":"Approved","value":"0"}],
|
||||||
|
"comment":"Hmm, I actually thought this was in Essex already.\n\nIt\u0027s a pretty annoying little issue for folks migrating for nova auth. Fix is small and pretty safe. Good choice for backporting"}
|
||||||
|
|
||||||
|
For most purposes you will want to trigger on ``patchset-created`` for when a
|
||||||
|
new patchset has been uploaded.
|
||||||
|
|
||||||
|
Further documentation on how to use the events stream can be found in `Gerrit's stream event documentation page <http://gerrit-documentation.googlecode.com/svn/Documentation/2.3/cmd-stream-events.html>`_.
|
||||||
|
|
||||||
|
Posting Result To Gerrit
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
External testing systems can give non-gating votes to Gerrit by means of a -1/+1
|
||||||
|
verify vote. OpenStack Jenkins has extra permissions to give a +2/-2 verify
|
||||||
|
vote which is gating. Comments should also be provided to explain what kind of
|
||||||
|
test failed.. We do also ask that the comments contain public links to the
|
||||||
|
failure so that the developer can see what caused the failure.
|
||||||
|
|
||||||
|
An example of how to post this is as follows:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ ssh -p 29418 review.example.com gerrit review -m '"Test failed on MegaTestSystem <http://megatestsystem.org/tests/1234>"' --verified=-1 c0ff33
|
||||||
|
|
||||||
|
In this example ``c0ff33`` is the commit ID for the review. You can set the
|
||||||
|
verified to either `-1` or `+1` depending on whether or not it passed the tests.
|
||||||
|
|
||||||
|
Further documentation on the `review` command in Gerrit can be found in the `Gerrit review documentation page <http://gerrit-documentation.googlecode.com/svn/Documentation/2.3/cmd-review.html>`_.
|
||||||
|
|
||||||
|
We do suggest cautious testing of these systems and have a development Gerrit
|
||||||
|
setup to test on if required. In SmokeStack's case all failures are manually
|
||||||
|
reviewed before getting pushed to OpenStack, whilst this may no scale it is
|
||||||
|
advisable during initial testing of the setup.
|
||||||
|
|
||||||
|
.. _request-account-label:
|
||||||
|
|
||||||
|
Requesting a Service Account
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
To request a sevice acconut for your system you first need to create a new
|
||||||
|
account in LaunchPad. This account needs to be joined to the
|
||||||
|
`OpenStack Team <https://launchpad.net/~openstack>`_ or one of the related teams
|
||||||
|
so that Gerrit can pick it up. You can then contact the
|
||||||
|
OpenStack CI Admins via `email <mailto:openstack-ci-admins@lists.launchpad.net>`_
|
||||||
|
or the #openstack-infra IRC channel. We will set things up on Gerrit to
|
||||||
|
receive your system's votes.
|
||||||
|
|
||||||
|
Feel free to contact the CI team to arrange setting up a dedicated user so your
|
||||||
|
system can post reviews up using a system name rather than your user name.
|
||||||
|
|
||||||
|
The Jenkins Gerrit Trigger Plugin Way
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
There is a Gerrit Trigger plugin for Jenkins which automates all of the
|
||||||
|
processes described in this document. So if your testing system is Jenkins
|
||||||
|
based you can use it to simplify things. You will still need an account to do
|
||||||
|
this as described in the :ref:`request-account-label` section above.
|
||||||
|
|
||||||
|
The OpenStack version of the Gerrit Trigger plugin for Jenkins can be found on
|
||||||
|
`the Jenkins packaging job <https://jenkins.openstack.org/view/All/job/gerrit-trigger-plugin-package/lastSuccessfulBuild/artifact/gerrithudsontrigger/target/gerrit-trigger.hpi>`_ for it. You can install it using the Advanced tab in the
|
||||||
|
Jenkins Plugin Manager.
|
||||||
|
|
||||||
|
Once installed Jenkins will have a new `Gerrit Trigger` option in the `Manage
|
||||||
|
Jenkins` menu. This should be given the following options::
|
||||||
|
|
||||||
|
Hostname: review.openstack.org
|
||||||
|
Frontend URL: https://review.openstack.org/
|
||||||
|
SSH Port: 29418
|
||||||
|
Username: (the Launchpad user)
|
||||||
|
SSH Key File: (path to the user SSH key)
|
||||||
|
|
||||||
|
Verify
|
||||||
|
------
|
||||||
|
Started: 0
|
||||||
|
Successful: 1
|
||||||
|
Failed: -1
|
||||||
|
Unstable: 0
|
||||||
|
|
||||||
|
Code Review
|
||||||
|
-----------
|
||||||
|
Started: 0
|
||||||
|
Successful: 0
|
||||||
|
Failed: 0
|
||||||
|
Unstable: 0
|
||||||
|
|
||||||
|
(under Advanced Button):
|
||||||
|
|
||||||
|
Stated: (blank)
|
||||||
|
Successful: gerrit approve <CHANGE>,<PATCHSET> --message 'Build Successful <BUILDS_STATS>' --verified <VERIFIED> --code-review <CODE_REVIEW> --submit
|
||||||
|
Failed: gerrit approve <CHANGE>,<PATCHSET> --message 'Build Failed <BUILDS_STATS>' --verified <VERIFIED> --code-review <CODE_REVIEW>
|
||||||
|
Unstable: gerrit approve <CHANGE>,<PATCHSET> --message 'Build Unstable <BUILDS_STATS>' --verified <VERIFIED> --code-review <CODE_REVIEW>
|
||||||
|
|
||||||
|
Note that it is useful to include something in the messages about what testing
|
||||||
|
system is supplying these messages.
|
||||||
|
|
||||||
|
When creating jobs in Jenkins you will have the option to add triggers. You
|
||||||
|
should configure as follows::
|
||||||
|
|
||||||
|
Trigger on Patchset Uploaded: ticked
|
||||||
|
(the rest unticked)
|
||||||
|
|
||||||
|
Type: Plain
|
||||||
|
Pattern: openstack/project-name (where project-name is the name of the project)
|
||||||
|
Branches:
|
||||||
|
Type: Path
|
||||||
|
Pattern: **
|
||||||
|
|
||||||
|
This job will now automatically trigger when a new patchset is uploaded and will
|
||||||
|
report the results to Gerrit automatically.
|
||||||
|
|
189
modules/jenkins_slave/files/slave_scripts/tardiff.py
Executable file
189
modules/jenkins_slave/files/slave_scripts/tardiff.py
Executable file
@ -0,0 +1,189 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# tardiff.py -- compare the tar package with git archive. Error out if
|
||||||
|
# it's different. The files to exclude are stored in a file, one per line,
|
||||||
|
# and it's passed as argument to this script.
|
||||||
|
#
|
||||||
|
# You should run this script from the project directory. For example, if
|
||||||
|
# you are verifying the package for glance project, you should run this
|
||||||
|
# script from that directory.
|
||||||
|
|
||||||
|
import getopt
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import commands
|
||||||
|
|
||||||
|
|
||||||
|
class OpenStackTarDiff:
|
||||||
|
""" main class to verify tar generated in each openstack projects """
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.init_vars()
|
||||||
|
self.validate_args()
|
||||||
|
self.check_env()
|
||||||
|
|
||||||
|
def check_env(self):
|
||||||
|
""" exit if dist/ directory already exists """
|
||||||
|
if not self.package and os.path.exists(self.dist_dir):
|
||||||
|
self.error("dist directory '%s' exist. Please remove it before " \
|
||||||
|
"running this script" % self.dist_dir)
|
||||||
|
|
||||||
|
def validate_args(self):
|
||||||
|
try:
|
||||||
|
opts = getopt.getopt(sys.argv[1:], 'hvp:e:',
|
||||||
|
['help', 'verbose', 'package=',
|
||||||
|
'exclude='])[0]
|
||||||
|
except getopt.GetoptError:
|
||||||
|
self.usage('invalid option selected')
|
||||||
|
|
||||||
|
for opt, value in opts:
|
||||||
|
if (opt in ('-h', '--help')):
|
||||||
|
self.usage()
|
||||||
|
elif (opt in ('-e', '--exclude')):
|
||||||
|
self.e_file = value
|
||||||
|
elif (opt in ('-p', '--package')):
|
||||||
|
self.package = value
|
||||||
|
elif (opt in ('-v', '--verbose')):
|
||||||
|
self.verbose = True
|
||||||
|
else:
|
||||||
|
self.usage('unknown option : ' + opt)
|
||||||
|
if not self.e_file:
|
||||||
|
self.usage('specify file name containing list of files to '
|
||||||
|
'exclude in tar diff')
|
||||||
|
if not os.path.exists(self.e_file):
|
||||||
|
self.usage("file '%s' does not exist" % self.e_file)
|
||||||
|
if self.package and not os.path.exists(self.package):
|
||||||
|
self.usage("package '%s' specified, but does not "
|
||||||
|
"exist" % self.package)
|
||||||
|
|
||||||
|
def init_vars(self):
|
||||||
|
self.dist_dir = 'dist/'
|
||||||
|
self.verbose = False
|
||||||
|
|
||||||
|
self.e_file = None
|
||||||
|
self.project_name = None
|
||||||
|
self.prefix = None
|
||||||
|
self.package = None
|
||||||
|
self.sdist_files = []
|
||||||
|
self.exclude_files = []
|
||||||
|
self.git_files = []
|
||||||
|
self.missing_files = []
|
||||||
|
|
||||||
|
def verify(self):
|
||||||
|
self.get_exclude_files()
|
||||||
|
self.get_project_name()
|
||||||
|
self.get_sdist_files()
|
||||||
|
self.prefix = self.sdist_files[0]
|
||||||
|
self.get_git_files()
|
||||||
|
|
||||||
|
for file in self.git_files:
|
||||||
|
if os.path.basename(file) in self.exclude_files:
|
||||||
|
self.debug("excluding file '%s'" % file)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if file not in self.sdist_files:
|
||||||
|
self.missing_files.append(file)
|
||||||
|
else:
|
||||||
|
#self.debug("file %s matches" % file)
|
||||||
|
pass
|
||||||
|
if len(self.missing_files) > 0:
|
||||||
|
self.error("files missing in package: %s" % self.missing_files)
|
||||||
|
print "SUCCESS: Generated package '%s' is valid" % self.package
|
||||||
|
|
||||||
|
def get_project_name(self):
|
||||||
|
""" get git project name """
|
||||||
|
self.project_name = os.path.basename(os.path.abspath(os.curdir))
|
||||||
|
|
||||||
|
def get_exclude_files(self):
|
||||||
|
""" read the file and get file list """
|
||||||
|
fh = open(self.e_file, 'r')
|
||||||
|
content = fh.readlines()
|
||||||
|
fh.close()
|
||||||
|
self.debug("files to exclude: %s" % content)
|
||||||
|
|
||||||
|
# remove trailing new lines.
|
||||||
|
self.exclude_files = [x.strip() for x in content]
|
||||||
|
|
||||||
|
def get_git_files(self):
|
||||||
|
""" read file list from git archive """
|
||||||
|
git_tar = os.path.join(os.getcwd(), '%s.tar' % self.project_name)
|
||||||
|
try:
|
||||||
|
a_cmd = "git archive -o %s HEAD --prefix=%s" % \
|
||||||
|
(git_tar, self.prefix)
|
||||||
|
self.debug("executing command '%s'" % a_cmd)
|
||||||
|
(status, out) = commands.getstatusoutput(a_cmd)
|
||||||
|
if status != 0:
|
||||||
|
self.debug("command '%s' returned status '%s'" %
|
||||||
|
(a_cmd, status))
|
||||||
|
if os.path.exists(git_tar):
|
||||||
|
os.unlink(git_tar)
|
||||||
|
self.error('git archive failed: %s' % out)
|
||||||
|
except Exception, err:
|
||||||
|
if os.path.exists(git_tar):
|
||||||
|
os.unlink(git_tar)
|
||||||
|
self.error('git archive failed: %s' % err)
|
||||||
|
|
||||||
|
try:
|
||||||
|
tar_cmd = "tar tf %s" % git_tar
|
||||||
|
self.debug("executing command '%s'" % tar_cmd)
|
||||||
|
(status, out) = commands.getstatusoutput(tar_cmd)
|
||||||
|
if status != 0:
|
||||||
|
self.error('invalid tar file: %s' % git_tar)
|
||||||
|
self.git_files = out.split('\n')
|
||||||
|
self.debug("Removing git archive ... %s ..." % git_tar)
|
||||||
|
os.remove(git_tar)
|
||||||
|
except Exception, err:
|
||||||
|
self.error('unable to read tar: %s' % err)
|
||||||
|
|
||||||
|
def get_sdist_files(self):
|
||||||
|
""" create package for project and get file list in it"""
|
||||||
|
if not self.package:
|
||||||
|
try:
|
||||||
|
sdist_cmd = "python setup.py sdist"
|
||||||
|
self.debug("executing command '%s'" % sdist_cmd)
|
||||||
|
(status, out) = commands.getstatusoutput(sdist_cmd)
|
||||||
|
if status != 0:
|
||||||
|
self.error("command '%s' failed" % sdist_cmd)
|
||||||
|
except Exception, err:
|
||||||
|
self.error("command '%s' failed" % (sdist_cmd, err))
|
||||||
|
|
||||||
|
self.package = os.listdir(self.dist_dir)[0]
|
||||||
|
self.package = os.path.join(self.dist_dir, self.package)
|
||||||
|
tar_cmd = "tar tzf %s" % self.package
|
||||||
|
try:
|
||||||
|
self.debug("executing command '%s'" % tar_cmd)
|
||||||
|
(status, out) = commands.getstatusoutput(tar_cmd)
|
||||||
|
if status != 0:
|
||||||
|
self.error("command '%s' failed" % tar_cmd)
|
||||||
|
#self.debug(out)
|
||||||
|
self.sdist_files = out.split('\n')
|
||||||
|
except Exception, err:
|
||||||
|
self.error("command '%s' failed: %s" % (tar_cmd, err))
|
||||||
|
|
||||||
|
def debug(self, msg):
|
||||||
|
if self.verbose:
|
||||||
|
sys.stdout.write('DEBUG: %s\n' % msg)
|
||||||
|
|
||||||
|
def error(self, msg):
|
||||||
|
sys.stderr.write('ERROR: %s\n' % msg)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def usage(self, msg=None):
|
||||||
|
if msg:
|
||||||
|
stream = sys.stderr
|
||||||
|
else:
|
||||||
|
stream = sys.stdout
|
||||||
|
stream.write("usage: %s [--help|h] [-v] "
|
||||||
|
"[-p|--package=sdist_package.tar.gz] "
|
||||||
|
"-e|--exclude=filename\n" \
|
||||||
|
% os.path.basename(sys.argv[0]))
|
||||||
|
if msg:
|
||||||
|
stream.write("\nERROR: " + msg + "\n")
|
||||||
|
exitCode = 1
|
||||||
|
else:
|
||||||
|
exitCode = 0
|
||||||
|
sys.exit(exitCode)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
tardiff = OpenStackTarDiff()
|
||||||
|
tardiff.verify()
|
21
setup.py
Normal file
21
setup.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import datetime
|
||||||
|
from setuptools import setup
|
||||||
|
from sphinx.setup_command import BuildDoc
|
||||||
|
|
||||||
|
ci_cmdclass={}
|
||||||
|
|
||||||
|
class local_BuildDoc(BuildDoc):
|
||||||
|
def run(self):
|
||||||
|
for builder in ['html', 'man']:
|
||||||
|
self.builder = builder
|
||||||
|
self.finalize_options()
|
||||||
|
BuildDoc.run(self)
|
||||||
|
ci_cmdclass['build_sphinx'] = local_BuildDoc
|
||||||
|
|
||||||
|
setup(name='nova',
|
||||||
|
version="%d.%02d" % (datetime.datetime.now().year, datetime.datetime.now().month),
|
||||||
|
description="OpenStack Continuous Integration Scripts",
|
||||||
|
author="OpenStack CI Team",
|
||||||
|
author_email="openstack-ci@lists.launchpad.net",
|
||||||
|
url="http://launchpad.net/openstack-ci",
|
||||||
|
cmdclass=ci_cmdclass)
|
Loading…
Reference in New Issue
Block a user