summaryrefslogtreecommitdiffstats
path: root/doc/development
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development')
-rw-r--r--doc/development/caching.txt73
-rw-r--r--doc/development/cfg.txt15
-rw-r--r--doc/development/core.txt31
-rw-r--r--doc/development/fam.txt5
-rw-r--r--doc/development/lint.txt50
-rw-r--r--doc/development/option_parsing.txt236
-rw-r--r--doc/development/plugins.txt20
-rw-r--r--doc/development/setup.txt6
-rw-r--r--doc/development/submitting-patches.txt144
-rw-r--r--doc/development/unit-testing.txt5
10 files changed, 518 insertions, 67 deletions
diff --git a/doc/development/caching.txt b/doc/development/caching.txt
new file mode 100644
index 000000000..47d627278
--- /dev/null
+++ b/doc/development/caching.txt
@@ -0,0 +1,73 @@
+.. -*- mode: rst -*-
+
+.. _development-cache:
+
+============================
+ Server-side Caching System
+============================
+
+.. versionadded:: 1.4.0
+
+Bcfg2 caches two kinds of data:
+
+* The contents of all files that it reads in, including (often) an
+ optimized representation. E.g., XML files are cached both in their
+ raw (text) format, and also as :class:`lxml.etree._Element` objects.
+* Arbitrary data, in the server-side caching system documented on this
+ page.
+
+The caching system keeps a single unified cache with all cache data in
+it. Each individual datum stored in the cache is associated with any
+number of "tags" -- simple terms that uniquely identify the datum.
+This lets you very easily expire related data from multiple caches at
+once; for isntance, for expiring all data related to a host:
+
+.. code-block:: python
+
+ Bcfg2.Server.Cache.expire("foo.example.com")
+
+This would expire *all* data related to ``foo.example.com``,
+regardless of which plugin cached it, and so on.
+
+This permits a high level of interoperation between different plugins
+and the cache, which is necessary due to the wide distribution of data
+in Bcfg2 and the many different data sources that can be incorported.
+More technical details about writing code that uses the caches is below.
+
+Currently known caches are:
+
+.. currentmodule:: Bcfg2.Server.Plugins.Packages.Collection
+
++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+
+| Tags | Key(s) | Values | Use |
++=============+=======================================+=================================================+======================================================+
+| Metadata | Hostname | :class:`ClientMetadata | The :ref:`Metadata cache <server-caching>` |
+| | | <Bcfg2.Server.Plugins.Metadata.ClientMetadata>` | |
++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+
+| Probes, | Hostname | ``list`` of group names | Groups set by :ref:`server-plugins-probes-index` |
+| probegroups | | | |
++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+
+| Probes, | Hostname | ``dict`` of ``<probe name>``: | Other data set by :ref:`server-plugins-probes-index` |
+| probedata | | :class:`ProbeData | |
+| | | <Bcfg2.Server.Plugins.Probes.ProbeData>` | |
++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+
+| Packages, | :attr:`Packages Collection cache key | :class:`Collection` | Kept by :ref:`server-plugins-generators-packages` in |
+| collections | <Collection.cachekey>` | | order to expire repository metadata cached on disk |
++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+
+| Packages, | Hostname | :attr:`Packages Collection cache key | Used by the Packages plugin to return Collection |
+| clients | | <Collection.cachekey>` | objects for clients. This is cross-referenced with |
+| | | | the ``Packages, collections`` cache |
++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+
+| Packages, | :attr:`Packages Collection cache key | ``set`` of package names | Cached results from looking up |
+| pkg_groups | <Collection.cachekey>`, | | ``<Package group="..."/>`` entries |
+| | hash of the selected package groups | | |
++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+
+| Packages, | :attr:`Packages Collection cache key | ``set`` of package names | Cached results from resolving complete package sets |
+| pkg_sets | <Collection.cachekey>`, | | for clients |
+| | hash of the initial package selection | | |
++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+
+
+These are enumerated so that they can be expired as needed by other
+plugins or other code points.
+
+.. automodule:: Bcfg2.Server.Cache
diff --git a/doc/development/cfg.txt b/doc/development/cfg.txt
index 6533e0d7a..f93bb42c7 100644
--- a/doc/development/cfg.txt
+++ b/doc/development/cfg.txt
@@ -55,12 +55,6 @@ exceptions:
.. autoexception:: Bcfg2.Server.Plugin.exceptions.PluginInitError
:noindex:
-Global Variables
-================
-
-.. autodata:: Bcfg2.Server.Plugins.Cfg.SETUP
-.. autodata:: Bcfg2.Server.Plugins.Cfg.CFG
-
Existing Cfg Handlers
=====================
@@ -81,18 +75,11 @@ Creators
.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.CfgPrivateKeyCreator
.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgPublicKeyCreator.CfgPublicKeyCreator
-Filters
--------
-
-.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgCatFilter.CfgCatFilter
-.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgDiffFilter.CfgDiffFilter
-
Info Handlers
-------------
.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgDefaultInfo
.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgInfoXML.CfgInfoXML
-.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgLegacyInfo.CfgLegacyInfo
Verifiers
---------
@@ -105,6 +92,6 @@ Other Cfg Objects
These other objects comprise the remainder of the Cfg plugin, and are
included for completeness.
-.. autoattribute:: Bcfg2.Server.Plugins.Cfg.DEFAULT_INFO
.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgEntrySet
.. autoclass:: Bcfg2.Server.Plugins.Cfg.Cfg
+.. automethod:: Bcfg2.Server.Plugins.Cfg.get_cfg
diff --git a/doc/development/core.txt b/doc/development/core.txt
index 886a5538b..f5cc7de67 100644
--- a/doc/development/core.txt
+++ b/doc/development/core.txt
@@ -10,8 +10,10 @@
Bcfg2 1.3 added a pluggable server core system so that the server core
itself can be easily swapped out to use different technologies. It
-currently ships with two backends: a builtin core written from scratch
-using the various server tools in the Python standard library; and an
+currently ships with several backends: a builtin core written from
+scratch using the various server tools in the Python standard library;
+a variant on the builtin core that uses Python 2.6's
+:mod:`multiprocessing` library to process requests in parallel; and an
experimental `CherryPy <http://www.cherrypy.org/>`_ based core. This
page documents the server core interface so that other cores can be
written to take advantage of other technologies, e.g., `Tornado
@@ -20,20 +22,25 @@ written to take advantage of other technologies, e.g., `Tornado
A core implementation needs to:
-* Override :func:`Bcfg2.Server.Core.BaseCore._daemonize` to handle
- daemonization, writing the PID file, and dropping privileges.
-* Override :func:`Bcfg2.Server.Core.BaseCore._run` to handle server
+* Override :func:`Bcfg2.Server.Core.Core._run` to handle server
startup.
-* Override :func:`Bcfg2.Server.Core.BaseCore._block` to run the
+* Override :func:`Bcfg2.Server.Core.Core._block` to run the
blocking server loop.
-* Call :func:`Bcfg2.Server.Core.BaseCore.shutdown` on orderly
+* Call :func:`Bcfg2.Server.Core.Core.shutdown` on orderly
shutdown.
+A core that wants to use the network (i.e., a core that isn't used
+entirely for introspection, as in :ref:`bcfg2-info
+<server-bcfg2-info>`, or other local tasks) should inherit from
+:class:`Bcfg2.Server.Core.NetworkCore`, and must also override
+:func:`Bcfg2.Server.Core.NetworkCore._daemonize` to handle daemonization,
+writing the PID file, and dropping privileges.
+
Nearly all XML-RPC handling is delegated entirely to the core
implementation. It needs to:
-* Call :func:`Bcfg2.Server.Core.BaseCore.authenticate` to authenticate
- clients.
+* Call :func:`Bcfg2.Server.Core.NetworkCore.authenticate` to
+ authenticate clients.
* Handle :exc:`xmlrpclib.Fault` exceptions raised by the exposed
XML-RPC methods as appropriate.
* Dispatch XML-RPC method invocations to the appropriate method,
@@ -59,7 +66,7 @@ Builtin Core
The builtin server core consists of the core implementation
(:class:`Bcfg2.Server.BuiltinCore.Core`) and the XML-RPC server
-implementation (:mod:`Bcfg2.SSLServer`).
+implementation (:mod:`Bcfg2.Server.SSLServer`).
Core
~~~~
@@ -69,7 +76,7 @@ Core
XML-RPC Server
~~~~~~~~~~~~~~
-.. automodule:: Bcfg2.SSLServer
+.. automodule:: Bcfg2.Server.SSLServer
Multiprocessing Core
--------------------
@@ -79,4 +86,4 @@ Multiprocessing Core
CherryPy Core
-------------
-.. automodule:: Bcfg2.Server.CherryPyCore
+.. automodule:: Bcfg2.Server.CherrypyCore
diff --git a/doc/development/fam.txt b/doc/development/fam.txt
index c2c3b14f5..e967aaf68 100644
--- a/doc/development/fam.txt
+++ b/doc/development/fam.txt
@@ -56,11 +56,6 @@ Pseudo
.. automodule:: Bcfg2.Server.FileMonitor.Pseudo
-Fam
----
-
-.. automodule:: Bcfg2.Server.FileMonitor.Fam
-
Gamin
-----
diff --git a/doc/development/lint.txt b/doc/development/lint.txt
index 6c0be960d..56a3d8a66 100644
--- a/doc/development/lint.txt
+++ b/doc/development/lint.txt
@@ -10,14 +10,14 @@
lets you easily write your own plugins to verify various parts of your
Bcfg2 specification.
-Plugins are loaded in one of two ways:
+Plugins are included in a module of the same name as the plugin class
+in :mod:`Bcfg2.Server.Lint`, e.g., :mod:`Bcfg2.Server.Lint.Validate`.
-* They may be included in a module of the same name as the plugin
- class in :mod:`Bcfg2.Server.Lint`, e.g.,
- :mod:`Bcfg2.Server.Lint.Validate`.
-* They may be included directly in a Bcfg2 server plugin, called
- "<plugin>Lint", e.g.,
- :class:`Bcfg2.Server.Plugins.Metadata.MetadataLint`.
+.. note::
+
+ It is no longer possible to include lint plugins directly in a
+ Bcfg2 server plugin, e.g.,
+ :class:`Bcfg2.Server.Plugins.Metadata.MetadataLint`.
Plugin Types
============
@@ -106,15 +106,15 @@ Basics
Existing ``bcfg2-lint`` Plugins
===============================
-AWSTagsLint
------------
+AWSTags
+-------
-.. autoclass:: Bcfg2.Server.Plugins.AWSTags.AWSTagsLint
+.. automodule:: Bcfg2.Server.Lint.AWSTags
-BundlerLint
------------
+Bundler
+-------
-.. autoclass:: Bcfg2.Server.Plugins.Bundler.BundlerLint
+.. automodule:: Bcfg2.Server.Lint.Bundler
Comments
--------
@@ -131,10 +131,10 @@ GroupNames
.. automodule:: Bcfg2.Server.Lint.GroupNames
-GroupPatternsLint
------------------
+GroupPatterns
+-------------
-.. autoclass:: Bcfg2.Server.Plugins.GroupPatterns.GroupPatternsLint
+.. automodule:: Bcfg2.Server.Lint.GroupPatterns
InfoXML
-------
@@ -146,25 +146,25 @@ MergeFiles
.. automodule:: Bcfg2.Server.Lint.MergeFiles
-MetadataLint
-------------
+Metadata
+--------
-.. autoclass:: Bcfg2.Server.Plugins.Metadata.MetadataLint
+.. automodule:: Bcfg2.Server.Lint.Metadata
-PkgmgrLint
-----------
+Pkgmgr
+------
-.. autoclass:: Bcfg2.Server.Plugins.Pkgmgr.PkgmgrLint
+.. automodule:: Bcfg2.Server.Lint.Pkgmgr
RequiredAttrs
-------------
.. automodule:: Bcfg2.Server.Lint.RequiredAttrs
-TemplateHelperLint
-------------------
+TemplateHelper
+--------------
-.. autoclass:: Bcfg2.Server.Plugins.TemplateHelper.TemplateHelperLint
+.. automodule:: Bcfg2.Server.Lint.TemplateHelper
Validate
--------
diff --git a/doc/development/option_parsing.txt b/doc/development/option_parsing.txt
new file mode 100644
index 000000000..52da8fced
--- /dev/null
+++ b/doc/development/option_parsing.txt
@@ -0,0 +1,236 @@
+.. -*- mode: rst -*-
+
+.. _development-option-parsing:
+
+====================
+Bcfg2 Option Parsing
+====================
+
+Bcfg2 uses an option parsing mechanism based on the Python
+:mod:`argparse` module. It does several very useful things that
+``argparse`` does not:
+
+* Collects options from various places, which lets us easily specify
+ per-plugin options, for example;
+* Automatically loads components (such as plugins);
+* Synthesizes option values from the command line, config files, and
+ environment variables;
+* Can dynamically create commands with many subcommands (e.g.,
+ bcfg2-info and bcfg2-admin); and
+* Supports keeping documentation inline with the option declaration,
+ which will make it easier to generate man pages.
+
+
+Collecting Options
+==================
+
+One of the more important features of the option parser is its ability
+to automatically collect options from loaded components (e.g., Bcfg2
+server plugins). Given the highly pluggable architecture of Bcfg2,
+this helps ensure two things:
+
+#. We do not have to specify all options in all places, or even in
+ most places. Options are specified alongside the class(es) that use
+ them.
+#. All options needed for a given script to run are guaranteed to be
+ loaded, without the need to specify all components that script uses
+ manually.
+
+For instance, assume a few plugins:
+
+* The ``Foo`` plugin takes one option, ``--foo``
+* The ``Bar`` plugin takes two options, ``--bar`` and ``--force``
+
+The plugins are used by the ``bcfg2-quux`` command, which itself takes
+two options: ``--plugins`` (which selects the plugins) and
+``--test``. The options would be selected at runtime, so for instance
+these would be valid:
+
+.. code-block:: bash
+
+ bcfg2-quux --plugins Foo --foo --test
+ bcfg2-quux --plugins Foo,Bar --foo --bar --force
+ bcfg2-quux --plugins Bar --force
+
+But this would not:
+
+ bcfg2-quux --plugins Foo --bar
+
+The help message would reflect the options that are available to the
+default set of plugins. (For this reason, allowing component lists to
+be set in the config file is very useful; that way, usage messages
+reflect the components in the config file.)
+
+Components (in this example, the plugins) can be classes or modules.
+There is no required interface for an option component. They may
+*optionally* have:
+
+* An ``options`` attribute that is a list of
+ :class:`Bcfg2.Options.Options.Option` objects or option groups.
+* A function or static method, ``options_parsed_hook``, that is called
+ when all options have been parsed. (This will be called again if
+ :func:`Bcfg2.Options.Parser.Parser.reparse` is called.)
+
+Options are collected through two primary mechanisms:
+
+#. The :class:`Bcfg2.Options.Actions.ComponentAction` class. When a
+ ComponentAction subclass is used as the action of an option, then
+ options contained in the classes (or modules) given in the option
+ value will be added to the parser.
+#. Modules that are not loaded via a
+ :class:`Bcfg2.Options.Actions.ComponentAction` option may load
+ options at runtime.
+
+Since it is preferred to add components instead of just options,
+loading options at runtime is generally best accomplished by creating
+a container object whose only purpose is to hold options. For
+instance:
+
+.. code-block:: python
+
+ def foo():
+ # do stuff
+
+ class _OptionContainer(object):
+ options = [
+ Bcfg2.Options.BooleanOption("--foo", help="Enable foo")]
+
+ @staticmethod
+ def options_parsed_hook():
+ if Bcfg2.Options.setup.foo:
+ foo()
+
+ Bcfg2.Options.get_parser().add_component(_OptionContainer)
+
+The Bcfg2.Options module
+========================
+
+.. currentmodule:: Bcfg2.Options
+
+.. autodata:: setup
+
+Options
+-------
+
+The base :class:`Bcfg2.Options.Option` object represents an option.
+Unlike options in :mod:`argparse`, an Option object does not need to
+be associated with an option parser; it exists on its own.
+
+.. autoclass:: Option
+.. autoclass:: PathOption
+.. autoclass:: BooleanOption
+.. autoclass:: PositionalArgument
+
+The Parser
+----------
+
+.. autoclass:: Parser
+.. autofunction:: get_parser
+.. autoexception:: OptionParserException
+
+Option Groups
+-------------
+
+Options can be grouped in various meaningful ways. This uses a
+variety of :mod:`argparse` functionality behind the scenes.
+
+In all cases, options can be added to groups in-line by simply
+specifying them in the object group constructor:
+
+.. code-block:: python
+
+ options = [
+ Bcfg2.Options.ExclusiveOptionGroup(
+ Bcfg2.Options.Option(...),
+ Bcfg2.Options.Option(...),
+ required=True),
+ ....]
+
+Nesting object groups is supported in theory, but barely tested.
+
+.. autoclass:: OptionGroup
+.. autoclass:: ExclusiveOptionGroup
+.. autoclass:: Subparser
+.. autoclass:: WildcardSectionGroup
+
+Subcommands
+-----------
+
+This library makes it easier to work with programs that have a large
+number of subcommands (e.g., :ref:`bcfg2-info <server-bcfg2-info>` and
+:ref:`bcfg2-admin <server-admin-index>`).
+
+The normal implementation pattern is this:
+
+#. Define all of your subcommands as children of
+ :class:`Bcfg2.Options.Subcommand`.
+#. Define a :class:`Bcfg2.Options.CommandRegistry` object that will be
+ used to register all of the commands. Registering a command
+ collect its options and adds it as a
+ :class:`Bcfg2.Options.Subparser` option group to the main option
+ parser.
+#. Register your commands with
+ :func:`Bcfg2.Options.register_commands`, parse options, and run.
+
+:mod:`Bcfg2.Server.Admin` provides a fairly simple implementation,
+where the CLI class is itself the command registry:
+
+.. code-block:: python
+
+ class CLI(Bcfg2.Options.CommandRegistry):
+ def __init__(self):
+ Bcfg2.Options.CommandRegistry.__init__(self)
+ Bcfg2.Options.register_commands(self.__class__,
+ globals().values(),
+ parent=AdminCmd)
+ parser = Bcfg2.Options.get_parser(
+ description="Manage a running Bcfg2 server",
+ components=[self])
+ parser.parse()
+
+In this case, commands are collected from amongst all global variables
+(the most likely scenario), and they must be children of
+:class:`Bcfg2.Server.Admin.AdminCmd`, which itself subclasses
+:class:`Bcfg2.Options.Subcommand`.
+
+Commands are defined by subclassing :class:`Bcfg2.Options.Subcommand`.
+At a minimum, the :func:`Bcfg2.Options.Subcommand.run` method must be
+overridden, and a docstring written.
+
+.. autoclass:: Subcommand
+.. autoclass:: HelpCommand
+.. autoclass:: CommandRegistry
+.. autofunction:: register_commands
+
+Actions
+-------
+
+Several custom argparse `actions
+<http://docs.python.org/dev/library/argparse.html#action>`_ provide
+some of the option collection magic of :mod:`Bcfg2.Options`.
+
+.. autoclass:: ConfigFileAction
+.. autoclass:: ComponentAction
+.. autoclass:: PluginsAction
+
+Option Types
+------------
+
+:mod:`Bcfg2.Options` provides a number of useful types for use as the `type
+<http://docs.python.org/dev/library/argparse.html#type>`_ keyword
+argument to
+the :class:`Bcfg2.Options.Option` constructor.
+
+.. autofunction:: Bcfg2.Options.Types.path
+.. autofunction:: Bcfg2.Options.Types.comma_list
+.. autofunction:: Bcfg2.Options.Types.colon_list
+.. autofunction:: Bcfg2.Options.Types.octal
+.. autofunction:: Bcfg2.Options.Types.username
+.. autofunction:: Bcfg2.Options.Types.groupname
+.. autofunction:: Bcfg2.Options.Types.timeout
+.. autofunction:: Bcfg2.Options.Types.size
+
+Common Options
+--------------
+
+.. autoclass:: Common
diff --git a/doc/development/plugins.txt b/doc/development/plugins.txt
index 3f2a888ac..e4f16b84d 100644
--- a/doc/development/plugins.txt
+++ b/doc/development/plugins.txt
@@ -128,13 +128,15 @@ The two attributes you need to know about are:
of the caching mode. See :ref:`server-caching` for a description of
each mode.
* :attr:`Bcfg2.Server.Core.metadata_cache`: A dict-like
- :class:`Bcfg2.Cache.Cache` object that stores the cached data.
+ :class:`Bcfg2.Server.Cache.Cache` object that stores the cached
+ data.
:class:`Bcfg2.Server.Plugin.base.Plugin` objects have access to the
:class:`Bcfg2.Server.Core` object as ``self.core``. In general,
-you'll be interested in the :func:`Bcfg2.Cache.Cache.expire` method;
-if called with no arguments, it expires all cached data; if called
-with one string argument, it expires cached data for the named client.
+you'll be interested in the :func:`Bcfg2.Server.Cache.Cache.expire`
+method; if called with no arguments, it expires all cached data; if
+called with one string argument, it expires cached data for the named
+client.
It's important, therefore, that your Connector plugin can either track
when changes are made to the group membership it reports, and expire
@@ -163,7 +165,7 @@ Tracking Execution Time
.. versionadded:: 1.3.0
Statistics can and should track execution time statistics using
-:mod:`Bcfg2.Statistics`. This module tracks execution time for the
+:mod:`Bcfg2.Server.Statistics`. This module tracks execution time for the
server core and for plugins, and exposes that data via ``bcfg2-admin
perf``. This data can be invaluable for locating bottlenecks or other
performance issues.
@@ -184,13 +186,13 @@ This will track the execution time of ``do_something``.
More granular usage is possible by using :func:`time.time` to manually
determine the execution time of a given event and calling
-:func:`Bcfg2.Statistics.Statistics.add_value` with an appropriate
+:func:`Bcfg2.Server.Statistics.Statistics.add_value` with an appropriate
statistic name.
-Bcfg2.Statistics
-^^^^^^^^^^^^^^^^
+Bcfg2.Server.Statistics
+^^^^^^^^^^^^^^^^^^^^^^^
-.. automodule:: Bcfg2.Statistics
+.. automodule:: Bcfg2.Server.Statistics
Plugin Helper Classes
---------------------
diff --git a/doc/development/setup.txt b/doc/development/setup.txt
index 05ad4157f..42aa0b023 100644
--- a/doc/development/setup.txt
+++ b/doc/development/setup.txt
@@ -1,4 +1,5 @@
.. -*- mode: rst -*-
+.. vim: ft=rst
.. _development-setup:
@@ -12,6 +13,11 @@ Checking Out a Copy of the Code
git clone https://github.com/Bcfg2/bcfg2.git
+.. note::
+
+ The URL above is read-only. If you are planning on submitting patches
+ upstream, please see :ref:`development-submitting-patches`.
+
* Add :file:`bcfg2/src/sbin` to your :envvar:`PATH` environment variable
* Add :file:`bcfg2/src/lib` to your :envvar:`PYTHONPATH` environment variable
diff --git a/doc/development/submitting-patches.txt b/doc/development/submitting-patches.txt
new file mode 100644
index 000000000..04492e6e1
--- /dev/null
+++ b/doc/development/submitting-patches.txt
@@ -0,0 +1,144 @@
+.. -*- mode: rst -*-
+.. vim: ft=rst
+
+.. _development-submitting-patches:
+
+==================
+Submitting Patches
+==================
+
+The purpose of this document is to assist those who may be less familiar
+with git in submitting patches upstream. While git is powerful, it can
+be somewhat confusing to those who don't use it regularly (and even
+those who do).
+
+.. note::
+
+ We prefer more in-depth commit messages than those
+ given below which are purely for brevity in this guide. See
+ http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
+ for more about creating proper git commit messages.
+
+.. _Github: https://github.com/
+
+`Github`_
+=========
+
+These steps outline one way of submitting patches via `Github`_. First,
+you will want to `fork <https://github.com/Bcfg2/bcfg2/fork>`_ the
+upstream Bcfg2 repository.
+
+Create a local branch
+---------------------
+
+Once you have forked the upstream repository, you should clone a local
+copy (where <YOUR USERNAME> is your github username).
+
+::
+
+ git clone git@github.com:<YOUR USERNAME>/bcfg2.git
+
+Create a local feature/bugfix branch off the appropriate upstream
+branch. For example, let's say we want to submit a bugfix for
+:program:`bcfg2-info` against the 1.2.x series. We can create a
+``fix-bcfg2-info`` branch which is a copy of the ``maint-1.2`` branch.
+
+::
+
+ git branch fix-bcfg2-info maint-1.2
+ git checkout fix-bcfg2-info
+
+Commit changes to your local branch
+-----------------------------------
+
+Next make whatever changes need to be made and commit them to the
+``fix-bcfg2-info`` branch.
+
+::
+
+ git add src/sbin/bcfg2-info
+ git commit -m "Fix bcfg2-info bug"
+
+Now you need to push your ``fix-bcfg2-info`` branch to github.
+
+::
+
+ git push origin fix-bcfg2-info
+
+Submit pull request
+-------------------
+
+Next, submit a pull request against the proper branch (in this case,
+https://github.com/username/bcfg2/pull/new/fix-bcfg2-info -- again,
+username is your github username). At the top of the pull request, you can
+edit the upstream branch you are targetting so that you create the pull
+request against the proper upstream branch (in this case, ``maint-1.2``).
+
+All that's left to do is to write up a description of your pull request
+and click **Send pull request**. Since your local branch is specific to
+this fix, you can add additional commits if needed and push them. They
+will automatically be added to the pull request.
+
+Remove local branch
+-------------------
+
+Once we have merged your pull request, you can safely delete your local
+feature/bugfix branch. To do so, you must first checkout a different branch.
+
+::
+
+ git checkout master # switch to a different branch
+ git branch -d fix-bcfg2-info # delete your local copy of fix-bcfg2-info
+ git push origin :fix-bcfg2-info # delete fix-bcfg2-info from github
+
+Mailing List
+============
+
+The following lists the steps needed to use git's facilities for
+emailing patches to the mailing list.
+
+Commit changes to your local clone
+----------------------------------
+
+For example, let's say we want to fix a big in :program:`bcfg2-info`.
+For the 1.2.x series.
+
+::
+
+ git clone https://github.com/Bcfg2/bcfg2.git
+ git checkout maint-1.2
+ # make changes
+ git add src/sbin/bcfg2-info
+ git commit -m "Fix bcfg2-info bug"
+
+Setup git for gmail (optional)
+------------------------------
+
+If you would like to use the GMail SMTP server, you can add the following
+to your ~/.gitconfig file as per the :manpage:`git-send-email(1)` manpage.
+
+::
+
+ [sendemail]
+ smtpencryption = tls
+ smtpserver = smtp.gmail.com
+ smtpuser = yourname@gmail.com
+ smtpserverport = 587
+
+Format patches
+--------------
+
+Use git to create patches formatted for email with the following.
+
+::
+
+ git format-patch --cover-letter -M origin/maint-1.2 -o outgoing/
+
+
+Send emails to the mailing list
+-------------------------------
+
+Edit ``outgoing/0000-*`` and then send your emails to the mailing list
+(bcfg-dev@lists.mcs.anl.gov)::
+
+ git send-email outgoing/*
diff --git a/doc/development/unit-testing.txt b/doc/development/unit-testing.txt
index 7311f49d7..8007e8c75 100644
--- a/doc/development/unit-testing.txt
+++ b/doc/development/unit-testing.txt
@@ -1,4 +1,5 @@
.. -*- mode: rst -*-
+.. vim: ft=rst
.. _development-unit-testing:
@@ -13,7 +14,7 @@ You will first need to install the `Python Mock Module`_ and `Python
Nose`_ modules. You can then run the existing tests with the
following:
-.. code-block: bash
+.. code-block: sh
cd testsuite
nosetests
@@ -123,7 +124,7 @@ writing tests for the base :class:`Bcfg2.Server.Plugin.base.Plugin`
class, which all Bcfg2 :ref:`server-plugins-index` inherit from via
the :mod:`Plugin interfaces <Bcfg2.Server.Plugin.interfaces>`,
yielding several levels of often-multiple inheritance. To make this
-easier, our unit tests adhere to several design considerations:
+easier, our unit tests adhere to several design considerations.
Inherit Tests
-------------