Add better docs on credential providers

This commit adds some better documentation with an example explaining
how to use the credential providers now in tempest/lib.

Change-Id: I9f6856645094d483f7a3f0f76a40568c28c4e9b1
diff --git a/doc/source/library/credential_providers.rst b/doc/source/library/credential_providers.rst
index 6e14296..7e831cc 100644
--- a/doc/source/library/credential_providers.rst
+++ b/doc/source/library/credential_providers.rst
@@ -5,8 +5,133 @@
 
 These library interfaces are used to deal with allocating credentials on demand
 either dynamically by calling keystone to allocate new credentials, or from
-a list of preprovisioned credentials.
+a list of preprovisioned credentials. These 2 modules are implementations of
+the same abstract credential providers class and can be used interchangably.
+However, each implementation has some additional parameters that are used to
+influence the behavior of the modules. The API reference at the bottom of this
+doc shows the interface definitions for both modules, however that may be a bit
+opaque. You can see some examples of how to leverage this interface below.
 
+Initialization Example
+----------------------
+This example is from Tempest itself (from tempest/common/credentials_factory.py
+just modified slightly) and is how it initializes the credential provider based
+on config::
+
+  from tempest import config
+  from tempest.lib.common import dynamic_creds
+  from tempest.lib.common import preprov_creds
+
+  CONF = config.CONF
+
+  def get_credentials_provider(name, network_resources=None,
+                               force_tenant_isolation=False,
+                               identity_version=None):
+      # If a test requires a new account to work, it can have it via forcing
+      # dynamic credentials. A new account will be produced only for that test.
+      # In case admin credentials are not available for the account creation,
+      # the test should be skipped else it would fail.
+      identity_version = identity_version or CONF.identity.auth_version
+      if CONF.auth.use_dynamic_credentials or force_tenant_isolation:
+          admin_creds = get_configured_admin_credentials(
+              fill_in=True, identity_version=identity_version)
+          return dynamic_creds.DynamicCredentialProvider(
+              name=name,
+              network_resources=network_resources,
+              identity_version=identity_version,
+              admin_creds=admin_creds,
+              identity_admin_domain_scope=CONF.identity.admin_domain_scope,
+              identity_admin_role=CONF.identity.admin_role,
+              extra_roles=CONF.auth.tempest_roles,
+              neutron_available=CONF.service_available.neutron,
+              project_network_cidr=CONF.network.project_network_cidr,
+              project_network_mask_bits=CONF.network.project_network_mask_bits,
+              public_network_id=CONF.network.public_network_id,
+              create_networks=(CONF.auth.create_isolated_networks and not
+                               CONF.network.shared_physical_network),
+              resource_prefix=CONF.resources_prefix,
+              credentials_domain=CONF.auth.default_credentials_domain_name,
+              admin_role=CONF.identity.admin_role,
+              identity_uri=CONF.identity.uri_v3,
+              identity_admin_endpoint_type=CONF.identity.v3_endpoint_type)
+      else:
+          if CONF.auth.test_accounts_file:
+              # Most params are not relevant for pre-created accounts
+              return preprov_creds.PreProvisionedCredentialProvider(
+                  name=name, identity_version=identity_version,
+                  accounts_lock_dir=lockutils.get_lock_path(CONF),
+                  test_accounts_file=CONF.auth.test_accounts_file,
+                  object_storage_operator_role=CONF.object_storage.operator_role,
+                  object_storage_reseller_admin_role=reseller_admin_role,
+                  credentials_domain=CONF.auth.default_credentials_domain_name,
+                  admin_role=CONF.identity.admin_role,
+                  identity_uri=CONF.identity.uri_v3,
+                  identity_admin_endpoint_type=CONF.identity.v3_endpoint_type)
+          else:
+              raise exceptions.InvalidConfiguration(
+                  'A valid credential provider is needed')
+
+This function just returns an initialized credential provider class based on the
+config file. The consumer of this function treats the output as the same
+regardless of whether it's a dynamic or preprovisioned provider object.
+
+Dealing with Credentials
+------------------------
+
+Once you have a credential provider object created the access patterns for
+allocating and removing credentials are the same across both the dynamic
+and preprovisioned credentials. These are defined in the abstract
+CredentialProvider class. At a high level the credentials provider enables
+you to get 3 basic types of credentials at once (per object): a primary, alt,
+and admin. You're also able to allocate a credential by role. These credentials
+are tracked by the provider object and delete must manually be called otherwise
+the created resources will not be deleted (or returned to the pool in the case
+of preprovisioned creds)
+
+Examples
+''''''''
+
+Continuing from the example above, to allocate credentials by the 3 basic types
+you can do the following::
+
+  provider = get_credentials_provider('my_tests')
+  primary_creds = provider.get_primary_creds()
+  alt_creds = provider.get_alt_creds()
+  admin_creds = provider.get_admin_creds()
+  # Make sure to delete the credentials when you're finished
+  provider.clear_creds()
+
+To create and interact with credentials by role you can do the following::
+
+  provider = get_credentials_provider('my_tests')
+  my_role_creds = provider.get_creds_by_role({'roles': ['my_role']})
+  # provider.clear_creds() will clear all creds including those allocated by
+  # role
+  provider.clear_creds()
+
+When multiple roles are specified a set of creds with all the roles assigned
+will be allocated::
+
+  provider = get_credentials_provider('my_tests')
+  my_role_creds = provider.get_creds_by_role({'roles': ['my_role',
+                                                        'my_other_role']})
+  # provider.clear_creds() will clear all creds including those allocated by
+  # role
+  provider.clear_creds()
+
+If you need multiple sets of credentials with the same roles you can also do
+this by leveraging the ``force_new`` kwarg::
+
+  provider = get_credentials_provider('my_tests')
+  my_role_creds = provider.get_creds_by_role({'roles': ['my_role']})
+  my_role_other_creds = provider.get_creds_by_role({'roles': ['my_role']},
+                                                   force_new=True)
+  # provider.clear_creds() will clear all creds including those allocated by
+  # role
+  provider.clear_creds()
+
+API Reference
+=============
 
 ------------------------------
 The dynamic credentials module