Merge "Ensure Connection can be made from keyword arguments" into stable/queens
This commit is contained in:
commit
5de34797ab
|
@ -1,17 +1,19 @@
|
|||
===========================================
|
||||
Configuring os-client-config Applications
|
||||
===========================================
|
||||
.. _openstack-config:
|
||||
|
||||
========================================
|
||||
Configuring OpenStack SDK Applications
|
||||
========================================
|
||||
|
||||
.. _config-environment-variables:
|
||||
|
||||
Environment Variables
|
||||
---------------------
|
||||
|
||||
`os-client-config` honors all of the normal `OS_*` variables. It does not
|
||||
`openstacksdk` honors all of the normal `OS_*` variables. It does not
|
||||
provide backwards compatibility to service-specific variables such as
|
||||
`NOVA_USERNAME`.
|
||||
|
||||
If you have OpenStack environment variables set, `os-client-config` will
|
||||
If you have OpenStack environment variables set, `openstacksdk` will
|
||||
produce a cloud config object named `envvars` containing your values from the
|
||||
environment. If you don't like the name `envvars`, that's ok, you can override
|
||||
it by setting `OS_CLOUD_NAME`.
|
||||
|
@ -29,7 +31,7 @@ for trove set
|
|||
Config Files
|
||||
------------
|
||||
|
||||
`os-client-config` will look for a file called `clouds.yaml` in the following
|
||||
`openstacksdk` will look for a file called `clouds.yaml` in the following
|
||||
locations:
|
||||
|
||||
* Current Directory
|
||||
|
@ -58,7 +60,7 @@ Site Specific File Locations
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In addition to `~/.config/openstack` and `/etc/openstack` - some platforms
|
||||
have other locations they like to put things. `os-client-config` will also
|
||||
have other locations they like to put things. `openstacksdk` will also
|
||||
look in an OS specific config dir
|
||||
|
||||
* `USER_CONFIG_DIR`
|
||||
|
@ -111,7 +113,7 @@ You may note a few things. First, since `auth_url` settings are silly
|
|||
and embarrassingly ugly, known cloud vendor profile information is included and
|
||||
may be referenced by name. One of the benefits of that is that `auth_url`
|
||||
isn't the only thing the vendor defaults contain. For instance, since
|
||||
Rackspace lists `rax:database` as the service type for trove, `os-client-config`
|
||||
Rackspace lists `rax:database` as the service type for trove, `openstacksdk`
|
||||
knows that so that you don't have to. In case the cloud vendor profile is not
|
||||
available, you can provide one called `clouds-public.yaml`, following the same
|
||||
location rules previously mentioned for the config files.
|
||||
|
@ -129,7 +131,7 @@ Auth Settings
|
|||
-------------
|
||||
|
||||
Keystone has auth plugins - which means it's not possible to know ahead of time
|
||||
which auth settings are needed. `os-client-config` sets the default plugin type
|
||||
which auth settings are needed. `openstacksdk` sets the default plugin type
|
||||
to `password`, which is what things all were before plugins came about. In
|
||||
order to facilitate validation of values, all of the parameters that exist
|
||||
as a result of a chosen plugin need to go into the auth dict. For password
|
||||
|
@ -167,7 +169,7 @@ file.
|
|||
SSL Settings
|
||||
------------
|
||||
|
||||
When the access to a cloud is done via a secure connection, `os-client-config`
|
||||
When the access to a cloud is done via a secure connection, `openstacksdk`
|
||||
will always verify the SSL cert by default. This can be disabled by setting
|
||||
`verify` to `False`. In case the cert is signed by an unknown CA, a specific
|
||||
cacert can be provided via `cacert`. **WARNING:** `verify` will always have
|
||||
|
@ -195,7 +197,7 @@ Cache Settings
|
|||
--------------
|
||||
|
||||
Accessing a cloud is often expensive, so it's quite common to want to do some
|
||||
client-side caching of those operations. To facilitate that, `os-client-config`
|
||||
client-side caching of those operations. To facilitate that, `openstacksdk`
|
||||
understands passing through cache settings to dogpile.cache, with the following
|
||||
behaviors:
|
||||
|
||||
|
@ -209,7 +211,7 @@ times on a per-resource basis by passing values, in seconds to an expiration
|
|||
mapping keyed on the singular name of the resource. A value of `-1` indicates
|
||||
that the resource should never expire.
|
||||
|
||||
`os-client-config` does not actually cache anything itself, but it collects
|
||||
`openstacksdk` does not actually cache anything itself, but it collects
|
||||
and presents the cache information so that your various applications that
|
||||
are connecting to OpenStack can share a cache should you desire.
|
||||
|
||||
|
|
|
@ -13,184 +13,13 @@ Connection Object
|
|||
:members:
|
||||
|
||||
|
||||
Transition from Profile
|
||||
=======================
|
||||
Transitioning from Profile
|
||||
--------------------------
|
||||
|
||||
.. note:: This section describes migrating code from a previous interface of
|
||||
python-openstacksdk and can be ignored by people writing new code.
|
||||
Support exists for users coming from older releases of OpenStack SDK who have
|
||||
been using the :class:`~openstack.profile.Profile` interface.
|
||||
|
||||
If you have code that currently uses the ``openstack.profile.Profile`` object
|
||||
and/or an ``authenticator`` instance from an object based on
|
||||
``openstack.auth.base.BaseAuthPlugin``, that code should be updated to use the
|
||||
`openstack.config.cloud_region.CloudRegion` object instead.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
Writing Code that Works with Both
|
||||
---------------------------------
|
||||
|
||||
These examples should all work with both the old and new interface, with one
|
||||
caveat. With the old interface, the ``CloudConfig`` object comes from the
|
||||
``os-client-config`` library, and in the new interface that has been moved
|
||||
into the SDK. In order to write code that works with both the old and new
|
||||
interfaces, use the following code to import the config namespace:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
try:
|
||||
from openstack import config as occ
|
||||
except ImportError:
|
||||
from os_client_config import config as occ
|
||||
|
||||
The examples will assume that the config module has been imported in that
|
||||
manner.
|
||||
|
||||
.. note:: Yes, there is an easier and less verbose way to do all of these.
|
||||
These are verbose to handle both the old and new interfaces in the
|
||||
same codebase.
|
||||
|
||||
Replacing authenticator
|
||||
-----------------------
|
||||
|
||||
There is no direct replacement for ``openstack.auth.base.BaseAuthPlugin``.
|
||||
``python-openstacksdk`` uses the `keystoneauth`_ library for authentication
|
||||
and HTTP interactions. `keystoneauth`_ has `auth plugins`_ that can be used
|
||||
to control how authentication is done. The ``auth_type`` config parameter
|
||||
can be set to choose the correct authentication method to be used.
|
||||
|
||||
Replacing Profile
|
||||
-----------------
|
||||
|
||||
The right way to replace the use of ``openstack.profile.Profile`` depends
|
||||
a bit on what you're trying to accomplish. Common patterns are listed below,
|
||||
but in general the approach is either to pass a cloud name to the
|
||||
`openstack.connection.Connection` constructor, or to construct a
|
||||
`openstack.config.cloud_region.CloudRegion` object and pass it to the
|
||||
constructor.
|
||||
|
||||
All of the examples on this page assume that you want to support old and
|
||||
new interfaces simultaneously. There are easier and less verbose versions
|
||||
of each that are available if you can just make a clean transition.
|
||||
|
||||
Getting a Connection to a named cloud from clouds.yaml
|
||||
------------------------------------------------------
|
||||
|
||||
If you want is to construct a `openstack.connection.Connection` based on
|
||||
parameters configured in a ``clouds.yaml`` file, or from environment variables:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import openstack.connection
|
||||
|
||||
conn = connection.from_config(cloud_name='name-of-cloud-you-want')
|
||||
|
||||
Getting a Connection from python arguments avoiding clouds.yaml
|
||||
---------------------------------------------------------------
|
||||
|
||||
If, on the other hand, you want to construct a
|
||||
`openstack.connection.Connection`, but are in a context where reading config
|
||||
from a clouds.yaml file is undesirable, such as inside of a Service:
|
||||
|
||||
* create a `openstack.config.loader.OpenStackConfig` object, telling
|
||||
it to not load yaml files. Optionally pass an ``app_name`` and
|
||||
``app_version`` which will be added to user-agent strings.
|
||||
* get a `openstack.config.cloud_region.CloudRegion` object from it
|
||||
* get a `openstack.connection.Connection`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
try:
|
||||
from openstack import config as occ
|
||||
except ImportError:
|
||||
from os_client_config import config as occ
|
||||
from openstack import connection
|
||||
|
||||
loader = occ.OpenStackConfig(
|
||||
load_yaml_files=False,
|
||||
app_name='spectacular-app',
|
||||
app_version='1.0')
|
||||
cloud_region = loader.get_one_cloud(
|
||||
region_name='my-awesome-region',
|
||||
auth_type='password',
|
||||
auth=dict(
|
||||
auth_url='https://auth.example.com',
|
||||
username='amazing-user',
|
||||
user_domain_name='example-domain',
|
||||
project_name='astounding-project',
|
||||
user_project_name='example-domain',
|
||||
password='super-secret-password',
|
||||
))
|
||||
conn = connection.from_config(cloud_config=cloud_region)
|
||||
|
||||
.. note:: app_name and app_version are completely optional, and auth_type
|
||||
defaults to 'password'. They are shown here for clarity as to
|
||||
where they should go if they want to be set.
|
||||
|
||||
Getting a Connection from python arguments and optionally clouds.yaml
|
||||
---------------------------------------------------------------------
|
||||
|
||||
If you want to make a connection from python arguments and want to allow
|
||||
one of them to optionally be ``cloud`` to allow selection of a named cloud,
|
||||
it's essentially the same as the previous example, except without
|
||||
``load_yaml_files=False``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
try:
|
||||
from openstack import config as occ
|
||||
except ImportError:
|
||||
from os_client_config import config as occ
|
||||
from openstack import connection
|
||||
|
||||
loader = occ.OpenStackConfig(
|
||||
app_name='spectacular-app',
|
||||
app_version='1.0')
|
||||
cloud_region = loader.get_one_cloud(
|
||||
region_name='my-awesome-region',
|
||||
auth_type='password',
|
||||
auth=dict(
|
||||
auth_url='https://auth.example.com',
|
||||
username='amazing-user',
|
||||
user_domain_name='example-domain',
|
||||
project_name='astounding-project',
|
||||
user_project_name='example-domain',
|
||||
password='super-secret-password',
|
||||
))
|
||||
conn = connection.from_config(cloud_config=cloud_region)
|
||||
|
||||
Parameters to get_one_cloud
|
||||
---------------------------
|
||||
|
||||
The most important things to note are:
|
||||
|
||||
* ``auth_type`` specifies which kind of authentication plugin to use. It
|
||||
controls how authentication is done, as well as what parameters are required.
|
||||
* ``auth`` is a dictionary containing the parameters needed by the auth plugin.
|
||||
The most common information it needs are user, project, domain, auth_url
|
||||
and password.
|
||||
* The rest of the keyword arguments to
|
||||
``openstack.config.loader.OpenStackConfig.get_one_cloud`` are either
|
||||
parameters needed by the `keystoneauth Session`_ object, which control how
|
||||
HTTP connections are made, or parameters needed by the
|
||||
`keystoneauth Adapter`_ object, which control how services are found in the
|
||||
Keystone Catalog.
|
||||
|
||||
For `keystoneauth Adapter`_ parameters, since there is one
|
||||
`openstack.connection.Connection` object but many services, per-service
|
||||
parameters are formed by using the official ``service_type`` of the service
|
||||
in question. For instance, to override the endpoint for the ``compute``
|
||||
service, the parameter ``compute_endpoint_override`` would be used.
|
||||
|
||||
``region_name`` in ``openstack.profile.Profile`` was a per-service parameter.
|
||||
This is no longer a valid concept. An `openstack.connection.Connection` is a
|
||||
connection to a region of a cloud. If you are in an extreme situation where
|
||||
you have one service in one region and a different service in a different
|
||||
region, you must use two different `openstack.connection.Connection` objects.
|
||||
|
||||
.. note:: service_type, although a parameter for keystoneauth1.adapter.Adapter,
|
||||
is not a valid parameter for get_one_cloud. service_type is the key
|
||||
by which services are referred, so saying
|
||||
'compute_service_type="henry"' doesn't have any meaning.
|
||||
|
||||
.. _keystoneauth: https://docs.openstack.org/keystoneauth/latest/
|
||||
.. _auth plugins: https://docs.openstack.org/keystoneauth/latest/authentication-plugins.html
|
||||
.. _keystoneauth Adapter: https://docs.openstack.org/keystoneauth/latest/api/keystoneauth1.html#keystoneauth1.adapter.Adapter
|
||||
.. _keystoneauth Session: https://docs.openstack.org/keystoneauth/latest/api/keystoneauth1.html#keystoneauth1.session.Session
|
||||
transition_from_profile
|
||||
|
|
|
@ -48,10 +48,11 @@ API Documentation
|
|||
-----------------
|
||||
|
||||
Service APIs are exposed through a two-layered approach. The classes
|
||||
exposed through our *Connection* interface are the place to start if you're
|
||||
an application developer consuming an OpenStack cloud. The *Resource*
|
||||
interface is the layer upon which the *Connection* is built, with
|
||||
*Connection* methods accepting and returning *Resource* objects.
|
||||
exposed through our `Connection Interface`_ are
|
||||
the place to start if you're an application developer consuming an OpenStack
|
||||
cloud. The `Resource Interface`_ is the layer upon which the
|
||||
`Connection Interface`_ is built, with methods on `Service Proxies`_ accepting
|
||||
and returning :class:`~openstack.resource.Resource` objects.
|
||||
|
||||
The Cloud Abstraction layer has a data model.
|
||||
|
||||
|
@ -61,26 +62,35 @@ The Cloud Abstraction layer has a data model.
|
|||
model
|
||||
|
||||
Connection Interface
|
||||
********************
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A *Connection* instance maintains your cloud config, session and authentication
|
||||
information providing you with a set of higher-level interfaces to work with
|
||||
OpenStack services.
|
||||
A :class:`~openstack.connection.Connection` instance maintains your cloud
|
||||
config, session and authentication information providing you with a set of
|
||||
higher-level interfaces to work with OpenStack services.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
connection
|
||||
|
||||
Once you have a *Connection* instance, the following services may be exposed
|
||||
to you via the :class:`~openstack.proxy.BaseProxy` interface.
|
||||
Once you have a :class:`~openstack.connection.Connection` instance, services
|
||||
are accessed through instances of :class:`~openstack.proxy.BaseProxy` or
|
||||
subclasses of it that exist as attributes on the
|
||||
:class:`~openstack.connection.Connection`.
|
||||
|
||||
.. autoclass:: openstack.proxy.BaseProxy
|
||||
:members:
|
||||
|
||||
The combination of your ``CloudRegion`` and the catalog of the cloud
|
||||
in question control which services are exposed, but listed below are the ones
|
||||
provided by the SDK.
|
||||
.. _service-proxies:
|
||||
|
||||
Service Proxies
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
The following service proxies exist on the
|
||||
:class:`~openstack.connection.Connection`. The service proxies are all always
|
||||
present on the :class:`~openstack.connection.Connection` object, but the
|
||||
combination of your ``CloudRegion`` and the catalog of the cloud in question
|
||||
control which services can be used.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
@ -103,16 +113,19 @@ provided by the SDK.
|
|||
Workflow <proxies/workflow>
|
||||
|
||||
Resource Interface
|
||||
******************
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The *Resource* layer is a lower-level interface to communicate with OpenStack
|
||||
services. While the classes exposed by the *Connection* build a convenience
|
||||
layer on top of this, *Resources* can be used directly. However, the most
|
||||
common usage of this layer is in receiving an object from a class in the
|
||||
*Connection* layer, modifying it, and sending it back into the *Connection*
|
||||
layer, such as to update a resource on the server.
|
||||
The *Resource* layer is a lower-level interface to
|
||||
communicate with OpenStack services. While the classes exposed by the
|
||||
`Service Proxies`_ build a convenience layer on top of
|
||||
this, :class:`~openstack.resource.Resource` objects can be
|
||||
used directly. However, the most common usage of this layer is in receiving
|
||||
an object from a class in the `Connection Interface_`, modifying it, and
|
||||
sending it back to the `Service Proxies`_ layer, such as to update a resource
|
||||
on the server.
|
||||
|
||||
The following services have exposed *Resource* classes.
|
||||
The following services have exposed :class:`~openstack.resource.Resource`
|
||||
classes.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
@ -132,7 +145,7 @@ The following services have exposed *Resource* classes.
|
|||
Workflow <resources/workflow/index>
|
||||
|
||||
Low-Level Classes
|
||||
*****************
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The following classes are not commonly used by application developers,
|
||||
but are used to construct applications to talk to OpenStack APIs. Typically
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
Transition from Profile
|
||||
=======================
|
||||
|
||||
.. note:: This section describes migrating code from a previous interface of
|
||||
python-openstacksdk and can be ignored by people writing new code.
|
||||
|
||||
If you have code that currently uses the :class:`~openstack.profile.Profile`
|
||||
object and/or an ``authenticator`` instance from an object based on
|
||||
``openstack.auth.base.BaseAuthPlugin``, that code should be updated to use the
|
||||
:class:`~openstack.config.cloud_region.CloudRegion` object instead.
|
||||
|
||||
.. important::
|
||||
|
||||
:class:`~openstack.profile.Profile` is going away. Existing code using it
|
||||
should be migrated as soon as possible.
|
||||
|
||||
Writing Code that Works with Both
|
||||
---------------------------------
|
||||
|
||||
These examples should all work with both the old and new interface, with one
|
||||
caveat. With the old interface, the ``CloudConfig`` object comes from the
|
||||
``os-client-config`` library, and in the new interface that has been moved
|
||||
into the SDK. In order to write code that works with both the old and new
|
||||
interfaces, use the following code to import the config namespace:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
try:
|
||||
from openstack import config as occ
|
||||
except ImportError:
|
||||
from os_client_config import config as occ
|
||||
|
||||
The examples will assume that the config module has been imported in that
|
||||
manner.
|
||||
|
||||
.. note:: Yes, there is an easier and less verbose way to do all of these.
|
||||
These are verbose to handle both the old and new interfaces in the
|
||||
same codebase.
|
||||
|
||||
Replacing authenticator
|
||||
-----------------------
|
||||
|
||||
There is no direct replacement for ``openstack.auth.base.BaseAuthPlugin``.
|
||||
``python-openstacksdk`` uses the `keystoneauth`_ library for authentication
|
||||
and HTTP interactions. `keystoneauth`_ has `auth plugins`_ that can be used
|
||||
to control how authentication is done. The ``auth_type`` config parameter
|
||||
can be set to choose the correct authentication method to be used.
|
||||
|
||||
Replacing Profile
|
||||
-----------------
|
||||
|
||||
The right way to replace the use of ``openstack.profile.Profile`` depends
|
||||
a bit on what you're trying to accomplish. Common patterns are listed below,
|
||||
but in general the approach is either to pass a cloud name to the
|
||||
`openstack.connection.Connection` constructor, or to construct a
|
||||
`openstack.config.cloud_region.CloudRegion` object and pass it to the
|
||||
constructor.
|
||||
|
||||
All of the examples on this page assume that you want to support old and
|
||||
new interfaces simultaneously. There are easier and less verbose versions
|
||||
of each that are available if you can just make a clean transition.
|
||||
|
||||
Getting a Connection to a named cloud from clouds.yaml
|
||||
------------------------------------------------------
|
||||
|
||||
If you want is to construct a `openstack.connection.Connection` based on
|
||||
parameters configured in a ``clouds.yaml`` file, or from environment variables:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import openstack.connection
|
||||
|
||||
conn = connection.from_config(cloud_name='name-of-cloud-you-want')
|
||||
|
||||
Getting a Connection from python arguments avoiding clouds.yaml
|
||||
---------------------------------------------------------------
|
||||
|
||||
If, on the other hand, you want to construct a
|
||||
`openstack.connection.Connection`, but are in a context where reading config
|
||||
from a clouds.yaml file is undesirable, such as inside of a Service:
|
||||
|
||||
* create a `openstack.config.loader.OpenStackConfig` object, telling
|
||||
it to not load yaml files. Optionally pass an ``app_name`` and
|
||||
``app_version`` which will be added to user-agent strings.
|
||||
* get a `openstack.config.cloud_region.CloudRegion` object from it
|
||||
* get a `openstack.connection.Connection`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
try:
|
||||
from openstack import config as occ
|
||||
except ImportError:
|
||||
from os_client_config import config as occ
|
||||
from openstack import connection
|
||||
|
||||
loader = occ.OpenStackConfig(
|
||||
load_yaml_files=False,
|
||||
app_name='spectacular-app',
|
||||
app_version='1.0')
|
||||
cloud_region = loader.get_one_cloud(
|
||||
region_name='my-awesome-region',
|
||||
auth_type='password',
|
||||
auth=dict(
|
||||
auth_url='https://auth.example.com',
|
||||
username='amazing-user',
|
||||
user_domain_name='example-domain',
|
||||
project_name='astounding-project',
|
||||
user_project_name='example-domain',
|
||||
password='super-secret-password',
|
||||
))
|
||||
conn = connection.from_config(cloud_config=cloud_region)
|
||||
|
||||
.. note:: app_name and app_version are completely optional, and auth_type
|
||||
defaults to 'password'. They are shown here for clarity as to
|
||||
where they should go if they want to be set.
|
||||
|
||||
Getting a Connection from python arguments and optionally clouds.yaml
|
||||
---------------------------------------------------------------------
|
||||
|
||||
If you want to make a connection from python arguments and want to allow
|
||||
one of them to optionally be ``cloud`` to allow selection of a named cloud,
|
||||
it's essentially the same as the previous example, except without
|
||||
``load_yaml_files=False``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
try:
|
||||
from openstack import config as occ
|
||||
except ImportError:
|
||||
from os_client_config import config as occ
|
||||
from openstack import connection
|
||||
|
||||
loader = occ.OpenStackConfig(
|
||||
app_name='spectacular-app',
|
||||
app_version='1.0')
|
||||
cloud_region = loader.get_one_cloud(
|
||||
region_name='my-awesome-region',
|
||||
auth_type='password',
|
||||
auth=dict(
|
||||
auth_url='https://auth.example.com',
|
||||
username='amazing-user',
|
||||
user_domain_name='example-domain',
|
||||
project_name='astounding-project',
|
||||
user_project_name='example-domain',
|
||||
password='super-secret-password',
|
||||
))
|
||||
conn = connection.from_config(cloud_config=cloud_region)
|
||||
|
||||
Parameters to get_one_cloud
|
||||
---------------------------
|
||||
|
||||
The most important things to note are:
|
||||
|
||||
* ``auth_type`` specifies which kind of authentication plugin to use. It
|
||||
controls how authentication is done, as well as what parameters are required.
|
||||
* ``auth`` is a dictionary containing the parameters needed by the auth plugin.
|
||||
The most common information it needs are user, project, domain, auth_url
|
||||
and password.
|
||||
* The rest of the keyword arguments to
|
||||
``openstack.config.loader.OpenStackConfig.get_one_cloud`` are either
|
||||
parameters needed by the `keystoneauth Session`_ object, which control how
|
||||
HTTP connections are made, or parameters needed by the
|
||||
`keystoneauth Adapter`_ object, which control how services are found in the
|
||||
Keystone Catalog.
|
||||
|
||||
For `keystoneauth Adapter`_ parameters, since there is one
|
||||
`openstack.connection.Connection` object but many services, per-service
|
||||
parameters are formed by using the official ``service_type`` of the service
|
||||
in question. For instance, to override the endpoint for the ``compute``
|
||||
service, the parameter ``compute_endpoint_override`` would be used.
|
||||
|
||||
``region_name`` in ``openstack.profile.Profile`` was a per-service parameter.
|
||||
This is no longer a valid concept. An `openstack.connection.Connection` is a
|
||||
connection to a region of a cloud. If you are in an extreme situation where
|
||||
you have one service in one region and a different service in a different
|
||||
region, you must use two different `openstack.connection.Connection` objects.
|
||||
|
||||
.. note:: service_type, although a parameter for keystoneauth1.adapter.Adapter,
|
||||
is not a valid parameter for get_one_cloud. service_type is the key
|
||||
by which services are referred, so saying
|
||||
'compute_service_type="henry"' doesn't have any meaning.
|
||||
|
||||
.. _keystoneauth: https://docs.openstack.org/keystoneauth/latest/
|
||||
.. _auth plugins: https://docs.openstack.org/keystoneauth/latest/authentication-plugins.html
|
||||
.. _keystoneauth Adapter: https://docs.openstack.org/keystoneauth/latest/api/keystoneauth1.html#keystoneauth1.adapter.Adapter
|
||||
.. _keystoneauth Session: https://docs.openstack.org/keystoneauth/latest/api/keystoneauth1.html#keystoneauth1.session.Session
|
|
@ -18,6 +18,42 @@ __all__ = [
|
|||
]
|
||||
|
||||
from openstack._log import enable_logging # noqa
|
||||
import openstack.config
|
||||
import openstack.connection
|
||||
|
||||
connect = openstack.connection.Connection
|
||||
|
||||
def connect(
|
||||
cloud=None,
|
||||
app_name=None, app_version=None,
|
||||
options=None,
|
||||
load_yaml_config=True, load_envvars=True,
|
||||
**kwargs):
|
||||
"""Create a :class:`~openstack.connection.Connection`
|
||||
|
||||
:param string cloud:
|
||||
The name of the configuration to load from clouds.yaml. Defaults
|
||||
to 'envvars' which will load
|
||||
:param argparse.Namespace options:
|
||||
An argparse Namespace object. allows direct passing in of
|
||||
argparse options to be added to the cloud config. Values
|
||||
of None and '' will be removed.
|
||||
:param bool load_yaml_config:
|
||||
Whether or not to load config settings from clouds.yaml files.
|
||||
Defaults to True.
|
||||
:param bool load_envvars:
|
||||
Whether or not to load config settings from environment variables.
|
||||
Defaults to True.
|
||||
:param kwargs:
|
||||
Additional configuration options.
|
||||
|
||||
:returns: openstack.connnection.Connection
|
||||
:raises: keystoneauth1.exceptions.MissingRequiredOptions
|
||||
on missing required auth parameters
|
||||
"""
|
||||
cloud_region = openstack.config.get_cloud_region(
|
||||
cloud=cloud,
|
||||
app_name=app_name, app_version=app_version,
|
||||
load_yaml_config=load_yaml_config,
|
||||
load_envvars=load_envvars,
|
||||
options=options, **kwargs)
|
||||
return openstack.connection.Connection(config=cloud_region)
|
||||
|
|
|
@ -16,23 +16,20 @@ import sys
|
|||
|
||||
from openstack.config.loader import OpenStackConfig # noqa
|
||||
|
||||
_config = None
|
||||
|
||||
|
||||
def get_cloud_region(
|
||||
service_key=None, options=None,
|
||||
app_name=None, app_version=None,
|
||||
load_yaml_config=True,
|
||||
load_envvars=True,
|
||||
**kwargs):
|
||||
load_yaml_config = kwargs.pop('load_yaml_config', True)
|
||||
global _config
|
||||
if not _config:
|
||||
_config = OpenStackConfig(
|
||||
load_yaml_config=load_yaml_config,
|
||||
app_name=app_name, app_version=app_version)
|
||||
config = OpenStackConfig(
|
||||
load_yaml_config=load_yaml_config,
|
||||
app_name=app_name, app_version=app_version)
|
||||
if options:
|
||||
_config.register_argparse_arguments(options, sys.argv, service_key)
|
||||
config.register_argparse_arguments(options, sys.argv, service_key)
|
||||
parsed_options = options.parse_known_args(sys.argv)
|
||||
else:
|
||||
parsed_options = None
|
||||
|
||||
return _config.get_one(options=parsed_options, **kwargs)
|
||||
return config.get_one(options=parsed_options, **kwargs)
|
||||
|
|
|
@ -35,7 +35,9 @@ def _make_key(key, service_type):
|
|||
return "_".join([service_type, key])
|
||||
|
||||
|
||||
def from_session(session, name=None, config=None, **kwargs):
|
||||
def from_session(session, name=None, region_name=None,
|
||||
force_ipv4=False,
|
||||
app_name=None, app_version=None, **kwargs):
|
||||
"""Construct a CloudRegion from an existing `keystoneauth1.session.Session`
|
||||
|
||||
When a Session already exists, we don't actually even need to go through
|
||||
|
@ -43,20 +45,30 @@ def from_session(session, name=None, config=None, **kwargs):
|
|||
The only parameters that are really needed are adapter/catalog related.
|
||||
|
||||
:param keystoneauth1.session.session session:
|
||||
An existing Session to use.
|
||||
An existing authenticated Session to use.
|
||||
:param str name:
|
||||
A name to use for this cloud region in logging. If left empty, the
|
||||
hostname of the auth_url found in the Session will be used.
|
||||
:param dict config:
|
||||
:param str region_name:
|
||||
The region name to connect to.
|
||||
:param bool force_ipv4:
|
||||
Whether or not to disable IPv6 support. Defaults to False.
|
||||
:param str app_name:
|
||||
Name of the application to be added to User Agent.
|
||||
:param str app_version:
|
||||
Version of the application to be added to User Agent.
|
||||
:param kwargs:
|
||||
Config settings for this cloud region.
|
||||
"""
|
||||
# If someone is constructing one of these from a Session, then they are
|
||||
# not using a named config. Use the hostname of their auth_url instead.
|
||||
name = name or urllib.parse.urlparse(session.auth.auth_url).hostname
|
||||
config_dict = config_defaults.get_defaults()
|
||||
config_dict.update(config or {})
|
||||
config_dict.update(**kwargs)
|
||||
return CloudRegion(
|
||||
name=name, session=session, config=config_dict, **kwargs)
|
||||
name=name, session=session, config=config_dict,
|
||||
region_name=region_name, force_ipv4=force_ipv4,
|
||||
app_name=app_name, app_version=app_version)
|
||||
|
||||
|
||||
class CloudRegion(object):
|
||||
|
|
|
@ -183,11 +183,12 @@ class OpenStackConfig(object):
|
|||
envvar_prefix=None, secure_files=None,
|
||||
pw_func=None, session_constructor=None,
|
||||
app_name=None, app_version=None,
|
||||
load_yaml_config=True):
|
||||
load_yaml_config=True, load_envvars=True):
|
||||
self.log = _log.setup_logging('openstack.config')
|
||||
self._session_constructor = session_constructor
|
||||
self._app_name = app_name
|
||||
self._app_version = app_version
|
||||
self._load_envvars = load_envvars
|
||||
|
||||
if load_yaml_config:
|
||||
self._config_files = config_files or CONFIG_FILES
|
||||
|
@ -198,11 +199,11 @@ class OpenStackConfig(object):
|
|||
self._secure_files = []
|
||||
self._vendor_files = []
|
||||
|
||||
config_file_override = os.environ.get('OS_CLIENT_CONFIG_FILE')
|
||||
config_file_override = self._get_envvar('OS_CLIENT_CONFIG_FILE')
|
||||
if config_file_override:
|
||||
self._config_files.insert(0, config_file_override)
|
||||
|
||||
secure_file_override = os.environ.get('OS_CLIENT_SECURE_FILE')
|
||||
secure_file_override = self._get_envvar('OS_CLIENT_SECURE_FILE')
|
||||
if secure_file_override:
|
||||
self._secure_files.insert(0, secure_file_override)
|
||||
|
||||
|
@ -231,12 +232,12 @@ class OpenStackConfig(object):
|
|||
else:
|
||||
# Get the backwards compat value
|
||||
prefer_ipv6 = get_boolean(
|
||||
os.environ.get(
|
||||
self._get_envvar(
|
||||
'OS_PREFER_IPV6', client_config.get(
|
||||
'prefer_ipv6', client_config.get(
|
||||
'prefer-ipv6', True))))
|
||||
force_ipv4 = get_boolean(
|
||||
os.environ.get(
|
||||
self._get_envvar(
|
||||
'OS_FORCE_IPV4', client_config.get(
|
||||
'force_ipv4', client_config.get(
|
||||
'broken-ipv6', False))))
|
||||
|
@ -248,7 +249,7 @@ class OpenStackConfig(object):
|
|||
self.force_ipv4 = True
|
||||
|
||||
# Next, process environment variables and add them to the mix
|
||||
self.envvar_key = os.environ.get('OS_CLOUD_NAME', 'envvars')
|
||||
self.envvar_key = self._get_envvar('OS_CLOUD_NAME', 'envvars')
|
||||
if self.envvar_key in self.cloud_config['clouds']:
|
||||
raise exceptions.OpenStackConfigException(
|
||||
'"{0}" defines a cloud named "{1}", but'
|
||||
|
@ -257,13 +258,14 @@ class OpenStackConfig(object):
|
|||
' file-based clouds.'.format(self.config_filename,
|
||||
self.envvar_key))
|
||||
|
||||
self.default_cloud = os.environ.get('OS_CLOUD')
|
||||
self.default_cloud = self._get_envvar('OS_CLOUD')
|
||||
|
||||
envvars = _get_os_environ(envvar_prefix=envvar_prefix)
|
||||
if envvars:
|
||||
self.cloud_config['clouds'][self.envvar_key] = envvars
|
||||
if not self.default_cloud:
|
||||
self.default_cloud = self.envvar_key
|
||||
if load_envvars:
|
||||
envvars = _get_os_environ(envvar_prefix=envvar_prefix)
|
||||
if envvars:
|
||||
self.cloud_config['clouds'][self.envvar_key] = envvars
|
||||
if not self.default_cloud:
|
||||
self.default_cloud = self.envvar_key
|
||||
|
||||
if not self.default_cloud and self.cloud_config['clouds']:
|
||||
if len(self.cloud_config['clouds'].keys()) == 1:
|
||||
|
@ -320,6 +322,11 @@ class OpenStackConfig(object):
|
|||
# password = self._pw_callback(prompt="Password: ")
|
||||
self._pw_callback = pw_func
|
||||
|
||||
def _get_envvar(self, key, default=None):
|
||||
if not self._load_envvars:
|
||||
return default
|
||||
return os.environ.get(key, default)
|
||||
|
||||
def get_extra_config(self, key, defaults=None):
|
||||
"""Fetch an arbitrary extra chunk of config, laying in defaults.
|
||||
|
||||
|
@ -700,7 +707,7 @@ class OpenStackConfig(object):
|
|||
p.add_argument(
|
||||
'--os-cloud',
|
||||
metavar='<name>',
|
||||
default=os.environ.get('OS_CLOUD', None),
|
||||
default=self._get_envvar('OS_CLOUD', None),
|
||||
help='Named cloud to connect to')
|
||||
|
||||
# we need to peek to see if timeout was actually passed, since
|
||||
|
|
|
@ -12,67 +12,148 @@
|
|||
|
||||
"""
|
||||
The :class:`~openstack.connection.Connection` class is the primary interface
|
||||
to the Python SDK it maintains a context for a connection to a cloud provider.
|
||||
The connection has an attribute to access each supported service.
|
||||
|
||||
Examples
|
||||
--------
|
||||
to the Python SDK. It maintains a context for a connection to a region of
|
||||
a cloud provider. The :class:`~openstack.connection.Connection` has an
|
||||
attribute to access each OpenStack service.
|
||||
|
||||
At a minimum, the :class:`~openstack.connection.Connection` class needs to be
|
||||
created with a config or the parameters to build one.
|
||||
|
||||
Create a connection
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
While the overall system is very flexible, there are four main use cases
|
||||
for different ways to create a :class:`~openstack.connection.Connection`.
|
||||
|
||||
The preferred way to create a connection is to manage named configuration
|
||||
settings in your clouds.yaml file and refer to them by name.::
|
||||
* Using config settings and keyword arguments as described in
|
||||
:ref:`openstack-config`
|
||||
* Using only keyword arguments passed to the constructor ignoring config files
|
||||
and environment variables.
|
||||
* Using an existing authenticated `keystoneauth1.session.Session`, such as
|
||||
might exist inside of an OpenStack service operational context.
|
||||
* Using an existing :class:`~openstack.config.cloud_region.CloudRegion`.
|
||||
|
||||
Using config settings
|
||||
---------------------
|
||||
|
||||
For users who want to create a :class:`~openstack.connection.Connection` making
|
||||
use of named clouds in ``clouds.yaml`` files, ``OS_`` environment variables
|
||||
and python keyword arguments, the :func:`openstack.connect` factory function
|
||||
is the recommended way to go:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import openstack
|
||||
|
||||
conn = openstack.connect(cloud='example', region_name='earth1')
|
||||
|
||||
If the application in question is a command line application that should also
|
||||
accept command line arguments, an `argparse.Namespace` can be passed to
|
||||
:func:`openstack.connect` that will have relevant arguments added to it and
|
||||
then subsequently consumed by the construtor:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import argparse
|
||||
import openstack
|
||||
|
||||
options = argparse.ArgumentParser(description='Awesome OpenStack App')
|
||||
conn = openstack.connect(options=options)
|
||||
|
||||
Using Only Keyword Arguments
|
||||
----------------------------
|
||||
|
||||
If the application wants to avoid loading any settings from ``clouds.yaml`` or
|
||||
environment variables, use the :class:`~openstack.connection.Connection`
|
||||
constructor directly. As long as the ``cloud`` argument is omitted or ``None``,
|
||||
the :class:`~openstack.connection.Connection` constructor will not load
|
||||
settings from files or the environment.
|
||||
|
||||
.. note::
|
||||
|
||||
This is a different default behavior than the :func:`~openstack.connect`
|
||||
factory function. In :func:`~openstack.connect` if ``cloud`` is omitted
|
||||
or ``None``, a default cloud will be loaded, defaulting to the ``envvars``
|
||||
cloud if it exists.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from openstack import connection
|
||||
|
||||
conn = connection.Connection(cloud='example', region_name='earth1')
|
||||
conn = connection.Connection(
|
||||
region_name='example-region',
|
||||
auth=dict(
|
||||
auth_url='https://auth.example.com',
|
||||
username='amazing-user',
|
||||
password='super-secret-password',
|
||||
project_id='33aa1afc-03fe-43b8-8201-4e0d3b4b8ab5',
|
||||
user_domain_id='054abd68-9ad9-418b-96d3-3437bb376703'),
|
||||
compute_api_version='2',
|
||||
identity_interface='internal')
|
||||
|
||||
Per-service settings as needed by `keystoneauth1.adapter.Adapter` such as
|
||||
``api_version``, ``service_name``, and ``interface`` can be set, as seen
|
||||
above, by prefixing them with the official ``service-type`` name of the
|
||||
service. ``region_name`` is a setting for the entire
|
||||
:class:`~openstack.config.cloud_region.CloudRegion` and cannot be set per
|
||||
service.
|
||||
|
||||
From existing authenticated Session
|
||||
-----------------------------------
|
||||
|
||||
For applications that already have an authenticated Session, simply passing
|
||||
it to the :class:`~openstack.connection.Connection` constructor is all that
|
||||
is needed:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from openstack import connection
|
||||
|
||||
conn = connection.Connection(
|
||||
session=session,
|
||||
region_name='example-region',
|
||||
compute_api_version='2',
|
||||
identity_interface='internal')
|
||||
|
||||
From existing CloudRegion
|
||||
-------------------------
|
||||
|
||||
If you already have an :class:`~openstack.config.cloud_region.CloudRegion`
|
||||
you can pass it in instead.::
|
||||
you can pass it in instead:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from openstack import connection
|
||||
import openstack.config
|
||||
|
||||
config = openstack.config.OpenStackConfig.get_one(
|
||||
config = openstack.config.get_cloud_region(
|
||||
cloud='example', region_name='earth')
|
||||
conn = connection.Connection(config=config)
|
||||
|
||||
It's also possible to pass in parameters directly if needed. The following
|
||||
example constructor uses the default identity password auth
|
||||
plugin and provides a username and password.::
|
||||
Using the Connection
|
||||
--------------------
|
||||
|
||||
from openstack import connection
|
||||
auth_args = {
|
||||
'auth_url': 'http://172.20.1.108:5000/v3',
|
||||
'project_name': 'admin',
|
||||
'user_domain_name': 'default',
|
||||
'project_domain_name': 'default',
|
||||
'username': 'admin',
|
||||
'password': 'admin',
|
||||
}
|
||||
conn = connection.Connection(**auth_args)
|
||||
Services are accessed through an attribute named after the service's official
|
||||
service-type.
|
||||
|
||||
List
|
||||
~~~~
|
||||
|
||||
Services are accessed through an attribute named after the service's official
|
||||
service-type. A list of all the projects is retrieved in this manner::
|
||||
An iterator containing a list of all the projects is retrieved in this manner:
|
||||
|
||||
projects = [project for project in conn.identity.projects()]
|
||||
.. code-block:: python
|
||||
|
||||
projects = conn.identity.projects()
|
||||
|
||||
Find or create
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
If you wanted to make sure you had a network named 'zuul', you would first
|
||||
try to find it and if that fails, you would create it::
|
||||
|
||||
network = conn.network.find_network("zuul")
|
||||
if network is None:
|
||||
network = conn.network.create_network({"name": "zuul"})
|
||||
network = conn.network.create_network(name="zuul")
|
||||
|
||||
Additional information about the services can be found in the
|
||||
:ref:`service-proxies` documentation.
|
||||
"""
|
||||
__all__ = [
|
||||
'from_config',
|
||||
|
@ -88,6 +169,7 @@ import six
|
|||
from openstack import _log
|
||||
from openstack import _meta
|
||||
from openstack import config as _config
|
||||
from openstack.config import cloud_region
|
||||
from openstack import exceptions
|
||||
from openstack import service_description
|
||||
from openstack import task_manager
|
||||
|
@ -119,11 +201,11 @@ def from_config(cloud=None, config=None, options=None, **kwargs):
|
|||
:rtype: :class:`~openstack.connection.Connection`
|
||||
"""
|
||||
# TODO(mordred) Backwards compat while we transition
|
||||
cloud = cloud or kwargs.get('cloud_name')
|
||||
config = config or kwargs.get('cloud_config')
|
||||
cloud = kwargs.pop('cloud_name', cloud)
|
||||
config = kwargs.pop('cloud_config', config)
|
||||
if config is None:
|
||||
config = _config.OpenStackConfig().get_one(
|
||||
cloud=cloud, argparse=options)
|
||||
cloud=cloud, argparse=options, **kwargs)
|
||||
|
||||
return Connection(config=config)
|
||||
|
||||
|
@ -167,11 +249,12 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta)):
|
|||
User Agent.
|
||||
:param authenticator: DEPRECATED. Only exists for short-term backwards
|
||||
compatibility for python-openstackclient while we
|
||||
transition. See `Transition from Profile`_ for
|
||||
details.
|
||||
transition. See :doc:`transition_from_profile`
|
||||
for details.
|
||||
:param profile: DEPRECATED. Only exists for short-term backwards
|
||||
compatibility for python-openstackclient while we
|
||||
transition. See `Transition from Profile`_ for details.
|
||||
transition. See :doc:`transition_from_profile`
|
||||
for details.
|
||||
:param extra_services: List of
|
||||
:class:`~openstack.service_description.ServiceDescription`
|
||||
objects describing services that openstacksdk otherwise does not
|
||||
|
@ -193,12 +276,20 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta)):
|
|||
# python-openstackclient to not use the profile interface.
|
||||
self.config = openstack.profile._get_config_from_profile(
|
||||
profile, authenticator, **kwargs)
|
||||
else:
|
||||
openstack_config = _config.OpenStackConfig(
|
||||
elif session:
|
||||
self.config = cloud_region.from_session(
|
||||
session=session,
|
||||
app_name=app_name, app_version=app_version,
|
||||
load_yaml_config=profile is None)
|
||||
self.config = openstack_config.get_one(
|
||||
cloud=cloud, validate=session is None, **kwargs)
|
||||
load_yaml_config=False,
|
||||
load_envvars=False,
|
||||
**kwargs)
|
||||
else:
|
||||
self.config = _config.get_cloud_region(
|
||||
cloud=cloud,
|
||||
app_name=app_name, app_version=app_version,
|
||||
load_yaml_config=cloud is not None,
|
||||
load_envvars=cloud is not None,
|
||||
**kwargs)
|
||||
|
||||
if self.config.name:
|
||||
tm_name = ':'.join([
|
||||
|
|
|
@ -78,8 +78,11 @@ class TestConnection(base.RequestsMockTestCase):
|
|||
|
||||
def test_session_provided(self):
|
||||
mock_session = mock.Mock(spec=session.Session)
|
||||
mock_session.auth = mock.Mock()
|
||||
mock_session.auth.auth_url = 'https://auth.example.com'
|
||||
conn = connection.Connection(session=mock_session, cert='cert')
|
||||
self.assertEqual(mock_session, conn.session)
|
||||
self.assertEqual('auth.example.com', conn.config.name)
|
||||
|
||||
def test_create_session(self):
|
||||
conn = connection.Connection(cloud='sample')
|
||||
|
|
Loading…
Reference in New Issue