diff --git a/doc/source/contributors/create/examples/resource/fake.py b/doc/source/contributors/create/examples/resource/fake.py
new file mode 100644
index 000000000..e87416f09
--- /dev/null
+++ b/doc/source/contributors/create/examples/resource/fake.py
@@ -0,0 +1,29 @@
+# Apache 2 header omitted for brevity
+
+from openstack.fake import fake_service
+from openstack import resource
+
+
+class Fake(resource.Resource):
+ resource_key = "resource"
+ resources_key = "resources"
+ base_path = "/fake"
+ service = fake_service.FakeService()
+ id_attribute = "name"
+
+ allow_create = True
+ allow_retrieve = True
+ allow_update = True
+ allow_delete = True
+ allow_list = True
+ allow_head = True
+
+ #: The transaction date and time.
+ timestamp = resource.prop("x-timestamp")
+ #: The name of this resource.
+ name = resource.prop("name")
+ #: The value of the resource. Also available in headers.
+ value = resource.prop("value", alias="x-resource-value")
+ #: Is this resource cool? If so, set it to True.
+ #: This is a multi-line comment about cool stuff.
+ cool = resource.prop("cool", type=bool)
diff --git a/doc/source/contributors/create/examples/resource/fake_service.py b/doc/source/contributors/create/examples/resource/fake_service.py
new file mode 100644
index 000000000..5d1bfb586
--- /dev/null
+++ b/doc/source/contributors/create/examples/resource/fake_service.py
@@ -0,0 +1,13 @@
+# Apache 2 header omitted for brevity
+
+from openstack.auth import service_filter
+
+
+class FakeService(service_filter.ServiceFilter):
+ """The fake service."""
+
+ valid_versions = [service_filter.ValidVersion('v2')]
+
+ def __init__(self, version=None):
+ """Create a fake service."""
+ super(FakeService, self).__init__(service_type='fake', version=version)
diff --git a/doc/source/contributors/create/resource.rst b/doc/source/contributors/create/resource.rst
new file mode 100644
index 000000000..f4552b53d
--- /dev/null
+++ b/doc/source/contributors/create/resource.rst
@@ -0,0 +1,191 @@
+Creating a New Resource
+=======================
+
+This guide will walk you through how to add resources for a service.
+
+Naming Conventions
+------------------
+
+Above all, names across this project conform to Python's naming standards,
+as laid out in `PEP 8 `_.
+
+The relevant details we need to know are as follows:
+
+ * Module names are lower case, and separated by underscores if more than
+ one word. For example, ``openstack.object_store``
+ * Class names are capitalized, with no spacing, and each subsequent word is
+ capitalized in a name. For example, ``ServerMetadata``.
+ * Attributes on classes, including methods, are lower case and separated
+ by underscores. For example, ``allow_list`` or ``get_data``.
+
+Services
+********
+
+Services in the OpenStack SDK are named after their program name, not their
+code name. For example, the project often known as "Nova" is always called
+"compute" within this SDK.
+
+This guide walks through creating service for an OpenStack program called
+"Fake". Following our guidelines, the code for its service would
+live under the ``openstack.fake`` namespace. What follows is the creation
+of a :class:`~openstack.resource.Resource` class for the "Fake" service.
+
+Resources
+*********
+
+Resources are named after the server-side resource, which is set in the
+``base_path`` attribute of the resource class. This guide creates a
+resouce class for the ``/fake`` server resource, so the resource module
+is called ``fake.py`` and the class is called ``Fake``.
+
+An Example
+----------
+
+``openstack/fake/fake_service.py``
+
+.. literalinclude:: examples/resource/fake_service.py
+ :language: Python
+ :linenos:
+
+``openstack/fake/v2/fake.py``
+
+.. literalinclude:: examples/resource/fake.py
+ :language: Python
+ :linenos:
+
+``fake.Fake`` Attributes
+------------------------
+
+Each service's resources inherit from :class:`~openstack.resource.Resource`,
+so they can override any of the base attributes to fit the way their
+particular resource operates.
+
+``resource_key`` and ``resources_key``
+**************************************
+
+These attributes are set based on how your resource responds with data.
+The default values for each of these are ``None``, which works fine
+when your resource returns a JSON body that can be used directly without a
+top-level key, such as ``{"name": "Ernie Banks", ...}"``.
+
+However, our ``Fake`` resource returns JSON bodies that have the details of
+the resource one level deeper, such as
+``{"resources": {"name": "Ernie Banks", ...}, {...}}``. It does a similar
+thing with single resources, putting them inside a dictionary keyed on
+``"resource"``.
+
+By setting ``Fake.resource_key`` on *line 8*, we tell the ``Resource.create``,
+``Resource.get``, and ``Resource.update`` methods that we're either sending
+or receiving a resource that is in a dictionary with that key.
+
+By setting ``Fake.resources_key`` on *line 9*, we tell the ``Resource.list``
+method that we're expecting to receive multiple resources inside a dictionary
+with that key.
+
+``base_path``
+*************
+
+The ``base_path`` is the URL we're going to use to make requests for this
+resource. In this case, *line 10* sets ``base_path = "/fake"``, which also
+corresponds to the name of our class, ``Fake``.
+
+Most resources follow this basic formula. Some cases are more complex, where
+the URL to make requests to has to contain some extra data. The volume service
+has several resources which make either basic requests or detailed requests,
+so they use ``base_path = "/volumes/%s(detailed)"``. Before a request is made,
+if ``detailed = True``, they convert it to a string so the URL becomes
+``/volumes/detailed``. If it's ``False``, they only send ``/volumes/``.
+
+``service``
+***********
+
+*Line 11* is an instance of the service we're implementing. Each resource
+ties itself to the service through this setting, so that the proper URL
+can be constructed.
+
+In ``fake_service.py``, we specify the valid versions as well as what this
+service is called in the service catalog. When a request is made for this
+resource, the Session now knows how to construct the appropriate URL using
+this ``FakeService`` instance.
+
+``id_attribute``
+****************
+
+*Line 12* specifies that this resource uses a different identifier than
+the default of ``id``. While IDs are used internally, such as for creating
+request URLs to interact with an individual resource, they are exposed for
+consistency so users always have one place to find the resource's identity.
+
+Supported Operations
+--------------------
+
+The base :class:`~openstack.resource.Resource` disallows all types of requests
+by default, requiring each resource to specify which requests they support.
+On *lines 14-19*, our ``Fake`` resource specifies that it'll work with all
+of the operations.
+
+In order to have the following methods work, you must allow the corresponding
+value by setting it to ``True``:
+
++----------------------------------------------+----------------+
+| :class:`~openstack.resource.Resource.create` | allow_create |
++----------------------------------------------+----------------+
+| :class:`~openstack.resource.Resource.delete` | allow_delete |
++----------------------------------------------+----------------+
+| :class:`~openstack.resource.Resource.head` | allow_head |
++----------------------------------------------+----------------+
+| :class:`~openstack.resource.Resource.list` | allow_list |
++----------------------------------------------+----------------+
+| :class:`~openstack.resource.Resource.get` | allow_retrieve |
++----------------------------------------------+----------------+
+| :class:`~openstack.resource.Resource.update` | allow_update |
++----------------------------------------------+----------------+
+
+An additional attribute to set is ``put_update`` if your service uses ``PUT``
+requests in order to update a resource. By default, ``PATCH`` requests are
+used for ``Resource.update``.
+
+Properties
+----------
+
+The way resource classes communicate values between the user and the server
+are :class:`~openstack.resource.prop` objects. These act similarly to Python's
+built-in property objects, but they share only the name - they're not the same.
+
+Properties are set based on the contents of a response body or headers.
+Based on what your resource returns, you should set ``prop``\s to map
+those those values to ones on your :class:`~openstack.resource.Resource`
+object.
+
+*Line 22* sets a prop for ``timestamp`` , which will cause the
+``Fake.timestamp`` attribute to contain the value returned in an
+``X-Timestamp`` header, such as from a ``Fake.head`` request.
+
+*Line 24* sets a prop for ``name``, which is a value returned in a body, such
+as from a ``Fake.get`` request. Note from *line 12* that ``name`` is
+specified its ``id`` attribute, so when this resource
+is populated from a response, ``Fake.name`` and ``Fake.id`` are the same
+value.
+
+*Line 26* sets a prop which contains an alias. ``Fake.value`` will be set
+when a response body contains a ``value``, or when a header contains
+``X-Resource-Value``.
+
+*Line 28* specifies a type to be checked before sending the value in a request.
+In this case, we can only set ``Fake.cool`` to either ``True`` or ``False``,
+otherwise a TypeError will be raised if the value can't be converted to the
+expected type.
+
+Documentation
+-------------
+
+We use Sphinx's ``autodoc`` feature in order to build API documentation for
+each resource we expose. The attributes we override from
+:class:`~openstack.resource.Resource` don't need to be documented, but any
+:class:`~openstack.resource.prop` attributes must be. All you need to do is
+add a comment *above* the line to document, with a colon following the
+pound-sign.
+
+*Lines 21, 23, 25, and 27-28* are comments which will then appear in the API
+documentation. As shown in *lines 27 & 28*, these comments can span multiple
+lines.
diff --git a/doc/source/contributors/index.rst b/doc/source/contributors/index.rst
index c302d3fc3..08c071800 100644
--- a/doc/source/contributors/index.rst
+++ b/doc/source/contributors/index.rst
@@ -1,2 +1,74 @@
-Contributors
-============
+Contributing to the OpenStack SDK
+=================================
+
+This section of documentation pertains to those who wish to contribute to the
+development of this SDK. If you're looking for documentation on how to use
+the SDK to build applications, please see the `user <../users>`_ section.
+
+About the Project
+-----------------
+
+The OpenStack SDK is a Stackforge project aimed at providing a complete
+software development kit for the programs which make up the OpenStack
+community. It is a set of Python-based libraries, documentation, examples,
+and tools released under the Apache 2 license.
+
+Contacting the Developers
+-------------------------
+
+IRC
+***
+
+The developers of this project are available in the
+`#openstack-sdks `_
+channel on Freenode. This channel includes conversation on SDKs and tools
+within the general OpenStack community, including OpenStackClient as well
+as occasional talk about SDKs created for languages outside of Python.
+
+Email
+*****
+
+The `openstack-dev `_
+mailing list fields questions of all types on OpenStack. Using the
+``[python-openstacksdk]`` filter to begin your email subject will ensure
+that the message gets to SDK developers.
+
+Development Environment
+-----------------------
+
+The first step towards contributing code and documentation is to setup your
+development environment. We use a pretty standard setup, but it is fully
+documented in our `setup `_ section.
+
+.. toctree::
+ :maxdepth: 2
+
+ setup
+
+Project Layout
+--------------
+
+The project contains a top-level ``openstack`` package, which houses several
+modules that form the foundation upon which each service's API is built on.
+Under the ``openstack`` package are packages for each of those services,
+such as ``openstack.compute``.
+
+.. toctree::
+
+ layout
+
+Adding Features
+---------------
+
+Does this SDK not do what you need it to do? Is it missing a service? Are you
+a developer on another project who wants to add their service? You're in the
+right place. Below are examples of how to add new features to the
+OpenStack SDK.
+
+.. toctree::
+ :maxdepth: 2
+
+ create/resource
+
+.. TODO(briancurtin): document how to create a proxy
+.. TODO(briancurtin): document how to create auth plugins
diff --git a/doc/source/contributors/contributing.rst b/doc/source/contributors/layout.rst
similarity index 55%
rename from doc/source/contributors/contributing.rst
rename to doc/source/contributors/layout.rst
index e51dacf50..edeac05c6 100644
--- a/doc/source/contributors/contributing.rst
+++ b/doc/source/contributors/layout.rst
@@ -1,123 +1,12 @@
-============
-Contributing
-============
+How the SDK is organized
+========================
-python-openstacksdk is a Stackforge project, mirrored on `GitHub`_. Bugs and
-Blueprints are handled on `Launchpad`_. Code reviews are hosted on `Gerrit`_.
+The following diagram shows how the project is laid out.
-.. _GitHub: https://github.com/stackforge/python-openstacksdk
-.. _Launchpad: https://launchpad.net/python-openstacksdk
-.. _Gerrit: https://review.openstack.org/#/q/project:stackforge/python-openstacksdk,n,z
-
-Getting Setup
--------------
-
-Python
-******
-
-The python-openstacksdk project supports Python versions 2.6, 2.7, 3.3+, and
-pypy, so you'll need to have at least one of those to get started.
-
-virtualenv
-**********
-
-Rather than installing the project's dependencies into your system-wide Python
-installation, you should create a virtual environment for this project.
-
-Install
-^^^^^^^
-
-Debian based platforms::
-
- apt-get install -y python-virtualenv
-
-RedHat based platforms::
-
- yum install -y python-virtualenv
-
-Other::
-
- pip install virtualenv
-
-Setup
-^^^^^
-::
-
- $ virtualenv sdk
- New python executable in sdk/bin/python
- Installing setuptools, pip...done.
- $ source sdk/bin/activate
- (sdk)$
-
-Getting the code
-****************
-
-If you haven't contributed in the openstack community before, be sure to read:
-
- http://docs.openstack.org/infra/manual/developers.html
- http://docs.openstack.org/infra/manual/developers.html#development-workflow
-
-and then you'll be ready to::
-
- git clone https://github.com/stackforge/python-openstacksdk.git
-
-tox
-***
-
-We use `tox `_ as our test runner, as it provides
-the ability to run your test against multiple versions. Going back to the
-`Python`_ section, ideally you have all of the versions installed so tox
-will accurately reflect how your code will run through the
-`continuous integration `_ system.::
-
- (sdk)$ pip install tox
-
-To run tox, just execute the ``tox`` command. With no arguments, it runs
-everything in our ``tox.ini`` file. You can also give it a specific
-environment to run.::
-
- (sdk)$ tox
- (sdk)$ tox -e py33
-
-Using the code
-**************
-
-To run the examples or otherwise use the SDK within your environment, you'll
-need to get the project's dependencies.::
-
- (sdk)$ python setup.py develop
- ...
- (sdk)$ python
- >>> import openstack
-
-
-Project Layout
---------------
-
-The code is laid out in the following structure. This example shows files
-relevant to working with code for the compute service's servers.::
-
- openstack/
- connection.py
- resource.py
- session.py
- transport.py
- auth/
- identity/
- v2.py
- v3.py
- compute/
- compute_service.py
- v2/
- server.py
- _proxy.py
- tests/
- compute/
- v2/
- test_server.py
+.. literalinclude:: layout.txt
Session
-*******
+-------
The :class:`openstack.session.Session` manages an authenticator,
transport, and user preferences. It exposes methods corresponding to
@@ -125,8 +14,8 @@ HTTP verbs, and injects your authentication token into a request,
determines any service preferences callers may have set, gets the endpoint
from the authenticator, and sends the request out through the transport.
-Authenticator
-^^^^^^^^^^^^^
+Auth
+----
As the `Session`_ needs a way to get a token and endpoint, it is constructed
with either a ``v2.Auth`` or ``v3.Auth`` object from
@@ -135,7 +24,7 @@ service and are able to handle things like authentication tokens and their
expiration, and the service catalog.
Transport
-^^^^^^^^^
+---------
The :class:`openstack.transport.Transport` class in is built on
`requests.Session `_
@@ -151,7 +40,7 @@ follows a
that isn't suitable for this library.
Resource
-********
+--------
The :class:`openstack.resource.Resource` base class is the building block
of any service implementation. ``Resource`` objects correspond to the
@@ -187,17 +76,25 @@ string replacement is used, e.g., ``base_path = "/servers/%(server_id)s/ips"``.
``resource_key`` and ``resources_key`` are attributes to set when a
``Resource`` returns more than one item in a response, or otherwise
requires a key to obtain the response value. For example, the ``Server``
-class sets ``resource_key = "server"`` and ``resource_keys = "servers"``
-to support the fact that multiple ``Server``\s can be returned, and each
-is identified with a singular noun in the response.
+class sets ``resource_key = "server"`` as an individual ``Server`` is
+stored in a dictionary keyed with the singular noun,
+and ``resource_keys = "servers"`` as multiple ``Server``\s are stored in
+a dictionary keyed with the plural noun in the response.
Proxy
-*****
+-----
Each service implements a ``Proxy`` class, within the
``openstack//vX/_proxy.py`` module. For example, the v2 compute
service's ``Proxy`` exists in ``openstack/compute/v2/_proxy.py``.
+This ``Proxy`` class manages a :class:`~openstack.sessions.Session` and
+provides a higher-level interface for users to work with via a
+:class:`~openstack.connection.Connection` instance. Rather than requiring
+users to maintain their own session and work with lower-level
+:class:`~openstack.resource.Resource` objects, the ``Proxy`` interface
+offers a place to make things easier for the caller.
+
Each ``Proxy`` class implements methods which act on the underlying
``Resource`` classes which represent the service. For example::
@@ -214,7 +111,7 @@ under construction, as we figure out the best way to implement them in a
way which will apply nicely across all of the services.
Connection
-**********
+----------
The :class:`openstack.connection.Connection` class builds atop a ``Session``
object, and provides a higher level interface constructed of ``Proxy``
@@ -227,26 +124,3 @@ to this SDK, managing the lower level connecton bits and exposing the
If you've built proper ``Resource`` objects and implemented methods on the
corresponding ``Proxy`` object, the high-level interface to your service
should now be exposed.
-
-Contacting the Team
--------------------
-
-IRC
-***
-
-The developers of this project are available in the
-`#openstack-sdks `_
-channel on Freenode.
-
-Email
-*****
-
-The `openstack-dev `_
-mailing list fields questions of all types on OpenStack. Using the
-``[python-openstacksdk]`` filter to begin your email subject will ensure
-that the message gets to SDK developers.
-
-If you're interested in communicating one-on-one, the following developers
-of the project are available:
-
-* Brian Curtin
diff --git a/doc/source/contributors/layout.txt b/doc/source/contributors/layout.txt
new file mode 100644
index 000000000..169d9ec21
--- /dev/null
+++ b/doc/source/contributors/layout.txt
@@ -0,0 +1,18 @@
+openstack/
+ connection.py
+ resource.py
+ session.py
+ transport.py
+ auth/
+ identity/
+ v2.py
+ v3.py
+ compute/
+ compute_service.py
+ v2/
+ server.py
+ _proxy.py
+ tests/
+ compute/
+ v2/
+ test_server.py
diff --git a/doc/source/contributors/setup.rst b/doc/source/contributors/setup.rst
new file mode 100644
index 000000000..36b828f05
--- /dev/null
+++ b/doc/source/contributors/setup.rst
@@ -0,0 +1,164 @@
+Creating a Development Environment
+==================================
+
+Required Tools
+--------------
+
+Python
+******
+
+As the OpenStack SDK is developed in Python, you will need at least one
+version of Python installed. It is strongly preferred that you have at least
+one of version 2 and one of version 3 so that your tests are run against both.
+Our continuous integration system runs against several versions, so ultimately
+we will have the proper test coverage, but having multiple versions locally
+results in less time spent in code review when changes unexpectedly break
+other versions.
+
+Python can be downloaded from https://www.python.org/downloads.
+
+virtualenv
+**********
+
+In order to isolate our development environment from the system-based Python
+installation, we use `virtualenv `_.
+This allows us to install all of our necessary dependencies without
+interfering with anything else, and preventing others from interfering with us.
+Virtualenv must be installed on your system in order to use it, and it can be
+had from PyPI, via pip, as follows. Note that you may need to run this
+as an administrator in some situations.::
+
+ $ apt-get install python-virtualenv # Debian based platforms
+ $ yum install python-virtualenv # Red Hat based platforms
+ $ pip install virtualenv # Mac OS X and other platforms
+
+You can create a virtualenv in any location. A common usage is to store all
+of your virtualenvs in the same place, such as under your home directory.
+To create a virtualenv for the default Python, likely a version 2, run
+the following::
+
+ $ virtualenv $HOME/envs/sdk
+
+To create an environment for a different version, such as Python 3, run
+the following::
+
+ $ virtualenv -p python3.4 $HOME/envs/sdk3
+
+When you want to enable your environment so that you can develop inside of it,
+you *activate* it. To activate an environment, run the /bin/activate
+script inside of it, like the following::
+
+ $ source $HOME/envs/sdk3/bin/activate
+ (sdk3)$
+
+Once you are activated, you will see the environment name in front of your
+command prompt. In order to exit that environment, run the ``deactivate``
+command.
+
+tox
+***
+
+We use `tox `_ as our test runner,
+which allows us to run the same test commands against multiple versions
+of Python. Inside any of the virtualenvs you use for working on the SDK,
+run the following to install ``tox`` into it.::
+
+ (sdk3)$ pip install tox
+
+Git
+***
+
+The source of the OpenStack SDK is stored in Git. In order to work with our
+source repository, you must have Git installed on your system. If your
+system has a package manager, it can likely be had from there. If not,
+you can find downloads or the source at http://git-scm.com.
+
+Getting the Source Code
+-----------------------
+
+.. TODO(briancurtin): We should try and distill the following document
+ into the minimally necessary parts to include directly in this section.
+ I've talked to several people who are discouraged by that large of a
+ document to go through before even getting into the project they want
+ to work on. I don't want that to happen to us because we have the potential
+ to be more public facing than a lot of other projects.
+
+.. note:: Before checking out the code, please read the OpenStack
+ `Developer's Guide `_
+ for details on how to use the continuous integration and code
+ review systems that we use.
+
+The canonical Git repository is hosted on openstack.org at
+http://git.openstack.org/cgit/stackforge/python-openstacksdk/, with a
+mirror on GitHub at https://github.com/stackforge/python-openstacksdk.
+Because of how Git works, you can create a local clone from either of those,
+or your own personal fork.::
+
+ (sdk3)$ git clone git@github.com:briancurtin/python-openstacksdk.git
+ (sdk3)$ cd python-openstacksdk
+
+Installing Dependencies
+-----------------------
+
+In order to work with the SDK locally, such as in the interactive interpreter
+or to run example scripts, you need to install the project's dependencies.::
+
+ (sdk3)$ pip install -r requirements.txt
+
+After the downloads and installs are complete, you'll have a fully functional
+environment to use the SDK in. This step installs the following dependencies.
+
+* `oslo.utils `_, which we use
+ for its ``timeutils`` module when calculating if or when authentication
+ tokens are considered expired.
+* `pbr `_, or the Python Build
+ Reasonableness project. pbr injects a set of common defaults which are used
+ throughout the OpenStack project.
+* `requests `_, which we use in the
+ :class:`~openstack.transport.Transport` class to handle HTTP requests and
+ responses.
+* `six `_, which we use for compatibility
+ across Python 2 and 3.
+* `stevedore `_, which we use for
+ working with plugins. stevedore builds on setuptools ``entry_points``.
+
+Running the Tests
+-----------------
+
+In order to run the entire test suite, simply run the ``tox`` command inside
+of your source checkout. This will attempt to run every test command listed
+inside of ``tox.ini``, which includes Python 2.6, 2.7, 3.3, 3.4, PyPy, and
+a PEP 8 check. You should run the full test suite on all versions before
+submitting changes for review in order to avoid unexpected failures in
+the continuous integration system.::
+
+ (sdk3)$ tox
+ ...
+ py33: commands succeeded
+ py34: commands succeeded
+ py26: commands succeeded
+ py27: commands succeeded
+ pypy: commands succeeded
+ pep8: commands succeeded
+ congratulations :)
+
+During development, it may be more convenient to run a subset of the tests
+to keep test time to a minimum. You can choose to run the tests only on one
+version. A step further is to run only the tests you are working on.::
+
+ (sdk3)$ tox -e py34 # Run run the tests on Python 3.4
+ (sdk3)$ tox -e py34 TestContainer # Run only the TestContainer tests on 3.4
+
+Building the Documentation
+--------------------------
+
+Our documentation is written in reStructured Text and is built using
+Sphinx. A ``docs`` command is availble in our ``tox.ini``, allowing you
+to build the documentation like you'd run tests. The ``docs`` command is
+not evaluated by default.::
+
+ (sdk3)$ tox -e docs
+
+That command will cause the documentation, which lives in the ``docs`` folder,
+to be built. HTML output is the most commonly referenced, which is located
+in ``docs/build/html``.