diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000000..eafad3cc3b --- /dev/null +++ b/doc/conf.py @@ -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 +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = '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) +] diff --git a/doc/gerrit.rst b/doc/gerrit.rst new file mode 100644 index 0000000000..a755dd69db --- /dev/null +++ b/doc/gerrit.rst @@ -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 + + + 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/ + + + + + + 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 + + + SSLOptions +StdEnvVars + + + SSLOptions +StdEnvVars + + + 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/ + + Order allow,deny + Allow from all + ProxyPass http://localhost:8081/ retry=0 + + + + + + +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 + = key expires in n days + w = key expires in n weeks + m = key expires in n months + 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) " + + Real name: Openstack Gerrit + Email address: review@openstack.org + Comment: + You selected this USER-ID: + "Openstack Gerrit " + + 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 + 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 diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000000..143346a78d --- /dev/null +++ b/doc/index.rst @@ -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` + diff --git a/doc/jenkins.rst b/doc/jenkins.rst new file mode 100644 index 0000000000..c8d5611468 --- /dev/null +++ b/doc/jenkins.rst @@ -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. + diff --git a/doc/jenkins_jobs.rst b/doc/jenkins_jobs.rst new file mode 100644 index 0000000000..379f6386d1 --- /dev/null +++ b/doc/jenkins_jobs.rst @@ -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 XML data) +* scm (supplies the 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. diff --git a/doc/meetbot.rst b/doc/meetbot.rst new file mode 100644 index 0000000000..7fc86cd3db --- /dev/null +++ b/doc/meetbot.rst @@ -0,0 +1,89 @@ +Meetbot +============== + +Overview +-------- + +The OpenStack CI team run a slightly modified +`Meetbot `_ to log IRC channel activity and +meeting minutes. Meetbot is a plugin for +`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 `_. 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 diff --git a/doc/puppet.rst b/doc/puppet.rst new file mode 100644 index 0000000000..c69b108644 --- /dev/null +++ b/doc/puppet.rst @@ -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. diff --git a/doc/puppet_modules.rst b/doc/puppet_modules.rst new file mode 100644 index 0000000000..1b271db913 --- /dev/null +++ b/doc/puppet_modules.rst @@ -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 `_ of this which is based on +one with bugfixes maintained by +`dcolish `_ 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 `_ 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 +`_ 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 `_ +.. [2] `Drizzle homepage `_ +.. [3] `nginx homepage `_ +.. [4] `Planet Venus homepage `_ +.. [5] `Meetbot homepage `_ diff --git a/doc/stackforge.rst b/doc/stackforge.rst new file mode 100644 index 0000000000..c89cd06918 --- /dev/null +++ b/doc/stackforge.rst @@ -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 `_ 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 `_ 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 `_. We are also available on the +#openstack-infra IRC channel or to the `CI Admins email address `_. diff --git a/doc/systems.rst b/doc/systems.rst new file mode 100644 index 0000000000..82a22186d3 --- /dev/null +++ b/doc/systems.rst @@ -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. diff --git a/doc/third_party.rst b/doc/third_party.rst new file mode 100644 index 0000000000..631e1a3024 --- /dev/null +++ b/doc/third_party.rst @@ -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 `_. +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 `_. + +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 "' --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 `_. + +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 `_ or one of the related teams +so that Gerrit can pick it up. You can then contact the +OpenStack CI Admins via `email `_ +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 `_ 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 , --message 'Build Successful ' --verified --code-review --submit + Failed: gerrit approve , --message 'Build Failed ' --verified --code-review + Unstable: gerrit approve , --message 'Build Unstable ' --verified --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. + diff --git a/modules/jenkins_slave/files/slave_scripts/tardiff.py b/modules/jenkins_slave/files/slave_scripts/tardiff.py new file mode 100755 index 0000000000..6faaee015c --- /dev/null +++ b/modules/jenkins_slave/files/slave_scripts/tardiff.py @@ -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() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000..d8682dce56 --- /dev/null +++ b/setup.py @@ -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)