diff --git a/README.rst b/README.rst index 00a361de8..9725cd521 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ Python bindings to the OpenStack Nova API -================================================== +========================================= This is a client for the OpenStack Nova API. There's a Python API (the ``novaclient`` module), and a command-line script (``nova``). Each diff --git a/doc/source/api.rst b/doc/source/api.rst index 8bcb219b3..ded67ed60 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1,5 +1,5 @@ The :mod:`novaclient` Python API -================================== +================================ .. module:: novaclient :synopsis: A client for the OpenStack Nova API. @@ -14,7 +14,10 @@ First create a client instance with your credentials:: >>> from novaclient import client >>> nova = client.Client(VERSION, USERNAME, PASSWORD, PROJECT_ID, AUTH_URL) -Here ``VERSION`` can be: ``1.1``, ``2``. +Here ``VERSION`` can be a string or ``novaclient.api_versions.APIVersion`` obj. +If you prefer string value, you can use ``1.1`` (deprecated now), ``2`` or +``2.X`` (where X is a microversion). + Alternatively, you can create a client instance using the keystoneclient session API:: @@ -23,9 +26,9 @@ session API:: >>> from keystoneclient import session >>> from novaclient import client >>> auth = v2.Password(auth_url=AUTH_URL, - username=USERNAME, - password=PASSWORD, - tenant_name=PROJECT_ID) + ... username=USERNAME, + ... password=PASSWORD, + ... tenant_name=PROJECT_ID) >>> sess = session.Session(auth=auth) >>> nova = client.Client(VERSION, session=sess) @@ -33,6 +36,23 @@ For more information on this keystoneclient API, see `Using Sessions`_. .. _Using Sessions: http://docs.openstack.org/developer/python-keystoneclient/using-sessions.html +It is also possible to use an instance as a context manager in which case +there will be a session kept alive for the duration of the with statement:: + + >>> from novaclient import client + >>> with client.Client(VERSION, USERNAME, PASSWORD, + ... PROJECT_ID, AUTH_URL) as nova: + ... nova.servers.list() + ... nova.flavors.list() + ... + +It is also possible to have a permanent (process-long) connection pool, +by passing a connection_pool=True:: + + >>> from novaclient import client + >>> nova = client.Client(VERSION, USERNAME, PASSWORD, PROJECT_ID, + ... AUTH_URL, connection_pool=True) + Then call methods on its managers:: >>> nova.servers.list() @@ -51,6 +71,13 @@ Then call methods on its managers:: >>> nova.servers.create("my-server", flavor=fl) +.. warning:: Direct initialization of ``novaclient.v2.client.Client`` object + can cause you to "shoot yourself in the foot". See launchpad bug-report + `1493576`_ for more details. + +.. _1493576: https://launchpad.net/bugs/1493576 + + Reference --------- diff --git a/novaclient/client.py b/novaclient/client.py index 159255540..f7ac8702a 100644 --- a/novaclient/client.py +++ b/novaclient/client.py @@ -785,6 +785,27 @@ def get_client_class(version): def Client(version, *args, **kwargs): - """Initialize client object based on given version.""" + """Initialize client object based on given version. + + HOW-TO: + The simplest way to create a client instance is initialization with your + credentials:: + + >>> from novaclient import client + >>> nova = client.Client(VERSION, USERNAME, PASSWORD, + ... PROJECT_ID, AUTH_URL) + + Here ``VERSION`` can be a string or + ``novaclient.api_versions.APIVersion`` obj. If you prefer string value, + you can use ``1.1`` (deprecated now), ``2`` or ``2.X`` + (where X is a microversion). + + + Alternatively, you can create a client instance using the keystoneclient + session API. See "The novaclient Python API" page at + python-novaclient's doc. + """ api_version, client_class = _get_client_class_and_version(version) - return client_class(api_version=api_version, *args, **kwargs) + kwargs.pop("direct_use", None) + return client_class(api_version=api_version, direct_use=False, + *args, **kwargs) diff --git a/novaclient/v2/client.py b/novaclient/v2/client.py index 1c195d5a1..d48c062f8 100644 --- a/novaclient/v2/client.py +++ b/novaclient/v2/client.py @@ -14,6 +14,7 @@ # under the License. from novaclient import client +from novaclient.i18n import _LW from novaclient.v2 import agents from novaclient.v2 import aggregates from novaclient.v2 import availability_zones @@ -53,44 +54,8 @@ class Client(object): """ Top-level object to access the OpenStack Compute API. - Create an instance with your creds:: - - >>> client = Client(USERNAME, PASSWORD, PROJECT_ID, AUTH_URL) - - Or, alternatively, you can create a client instance using the - keystoneclient.session API:: - - >>> from keystoneclient.auth.identity import v2 - >>> from keystoneclient import session - >>> from novaclient import client - >>> auth = v2.Password(auth_url=AUTH_URL, - username=USERNAME, - password=PASSWORD, - tenant_name=PROJECT_ID) - >>> sess = session.Session(auth=auth) - >>> nova = client.Client(VERSION, session=sess) - - Then call methods on its managers:: - - >>> nova.servers.list() - ... - >>> nova.flavors.list() - ... - - It is also possible to use an instance as a context manager in which - case there will be a session kept alive for the duration of the with - statement:: - - >>> with Client(USERNAME, PASSWORD, PROJECT_ID, AUTH_URL) as client: - ... client.servers.list() - ... client.flavors.list() - ... - - It is also possible to have a permanent (process-long) connection pool, - by passing a connection_pool=True:: - - >>> client = Client(USERNAME, PASSWORD, PROJECT_ID, - ... AUTH_URL, connection_pool=True) + .. warning:: All scripts and projects should not initialize this class + directly. It should be done via `novaclient.client.Client` interface. """ def __init__(self, username=None, api_key=None, project_id=None, @@ -103,7 +68,7 @@ class Client(object): auth_system='keystone', auth_plugin=None, auth_token=None, cacert=None, tenant_id=None, user_id=None, connection_pool=False, session=None, auth=None, - api_version=None, **kwargs): + api_version=None, direct_use=True, **kwargs): """ :param str username: Username :param str api_key: API Key @@ -136,6 +101,15 @@ class Client(object): :param api_version: Compute API version :type api_version: novaclient.api_versions.APIVersion """ + if direct_use: + import warnings + + warnings.warn( + _LW("'novaclient.v2.client.Client' is not designed to be " + "initialized directly. It is inner class of novaclient. " + "Please, use 'novaclient.client.Client' instead. " + "Related lp bug-report: 1493576")) + # FIXME(comstud): Rename the api_key argument above when we # know it's not being used as keyword argument