Skip to content

Commit dadb1c0

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Refactor os-client-config usage in from_config"
2 parents 804d835 + effb2a7 commit dadb1c0

File tree

6 files changed

+123
-37
lines changed

6 files changed

+123
-37
lines changed

doc/source/users/guides/connect_from_config.rst

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,13 @@ locations:
3131
* ~/.config/openstack
3232
* /etc/openstack
3333

34-
call :py:func:`~openstack.connection.from_config` with an object that has
35-
the name of the cloud configuration to use.
34+
call :py:func:`~openstack.connection.from_config`. The ``from_config``
35+
function takes three optional arguments, such as **cloud_name**,
36+
which allows you to specify one set of cloud credentials in your
37+
``clouds.yaml`` file. Additionally, **cloud_config** and **options**
38+
allow you to pass in configiration data you may have already received
39+
from ``os-client-config``, as well as additional options that the
40+
``os-client-config`` library may need.
3641

3742
.. literalinclude:: ../examples/connect.py
3843
:pyobject: Opts
@@ -51,16 +56,8 @@ absolute path of a file.::
5156

5257
export OS_CLIENT_CONFIG_FILE=/path/to/my/config/my-clouds.yaml
5358

54-
and call :py:func:`~openstack.connection.from_config` with an object that has
55-
the name of the cloud configuration to use.
56-
57-
.. literalinclude:: ../examples/connect.py
58-
:pyobject: Opts
59-
60-
.. literalinclude:: ../examples/connect.py
61-
:pyobject: create_connection_from_config
62-
63-
.. note:: To enable logging, set ``debug=True`` in the ``Opts`` object.
59+
and call :py:func:`~openstack.connection.from_config` with the **cloud_name**
60+
of the cloud configuration to use, .
6461

6562
.. Create Connection From Environment Variables
6663
--------------------------------------------

examples/connect.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535

3636

3737
class Opts(object):
38-
def __init__(self, test_cloud='test_cloud', debug=False):
39-
self.cloud = test_cloud
38+
def __init__(self, cloud_name='test_cloud', debug=False):
39+
self.cloud = cloud_name
4040
self.debug = debug
4141

4242

@@ -46,7 +46,7 @@ def _get_resource_value(resource_key, default):
4646
except KeyError:
4747
return default
4848

49-
opts = Opts(test_cloud=TEST_CLOUD)
49+
opts = Opts(cloud_name=TEST_CLOUD)
5050
occ = os_client_config.OpenStackConfig()
5151
cloud = occ.get_one_cloud(opts.cloud, argparse=opts)
5252

@@ -62,7 +62,7 @@ def _get_resource_value(resource_key, default):
6262

6363

6464
def create_connection_from_config():
65-
return connection.from_config(opts)
65+
return connection.from_config(cloud_config=cloud, options=opts)
6666

6767

6868
def create_connection(auth_url, region, project_name, username, password):

openstack/connection.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,27 @@
7272
_logger = logging.getLogger(__name__)
7373

7474

75-
def from_config(opts):
76-
"""Create a connection from a configuration.
77-
78-
Create a :class:`~openstack.connection.Connection` from a configuration
79-
similar to a os-client-config CloudConfig.
80-
81-
:param opts: An options class like the :class:`~argparse.Namespace` class.
75+
def from_config(cloud_name=None, cloud_config=None, options=None):
76+
"""Create a Connection using os-client-config
77+
78+
:param str cloud_name: Use the `cloud_name` configuration details when
79+
creating the Connection instance.
80+
:param cloud_config: An instance of
81+
`os_client_config.config.OpenStackConfig`
82+
as returned from the os-client-config library.
83+
If no `config` is provided,
84+
`os_client_config.OpenStackConfig` will be called,
85+
and the provided `cloud_name` will be used in
86+
determining which cloud's configuration details
87+
will be used in creation of the
88+
`Connection` instance.
89+
:param options: An argparse Namespace object; allows direct passing
90+
in of argparse options to be added to the cloud config.
91+
This value is passed to the `argparse` argument of
92+
`os_client_config.config.OpenStackConfig.get_one_cloud`.
8293
8394
:rtype: :class:`~openstack.connection.Connection`
8495
"""
85-
8696
# TODO(thowe): I proposed that service name defaults to None in OCC
8797
defaults = {}
8898
prof = profile.Profile()
@@ -92,17 +102,15 @@ def from_config(opts):
92102
# TODO(thowe): default is 2 which turns into v2 which doesn't work
93103
# this stuff needs to be fixed where we keep version and path separated.
94104
defaults['network_api_version'] = 'v2.0'
95-
96-
# Get the cloud_config
97-
occ = os_client_config.OpenStackConfig(override_defaults=defaults)
98-
cloud_config = occ.get_one_cloud(opts.cloud, argparse=opts)
105+
if cloud_config is None:
106+
occ = os_client_config.OpenStackConfig(override_defaults=defaults)
107+
cloud_config = occ.get_one_cloud(cloud=cloud_name, argparse=options)
99108

100109
if cloud_config.debug:
101110
utils.enable_logging(True, stream=sys.stdout)
102111

103112
# TODO(mordred) we need to add service_type setting to openstacksdk.
104113
# Some clouds have type overridden as well as name.
105-
prof = profile.Profile()
106114
services = [service.service_type for service in prof.get_services()]
107115
for service in cloud_config.get_services():
108116
if service in services:

openstack/tests/functional/base.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
from openstack import service_filter
2020

2121

22+
CLOUD_NAME = os.getenv('OS_CLOUD', 'test_cloud')
23+
24+
2225
def requires_service(**kwargs):
2326
"""Check whether a service is available for this test
2427
@@ -50,14 +53,10 @@ def check(self):
5053

5154

5255
class BaseFunctionalTest(unittest.TestCase):
53-
class Opts(object):
54-
def __init__(self):
55-
self.cloud = os.getenv('OS_CLOUD', 'test_cloud')
5656

5757
@classmethod
5858
def setUpClass(cls):
59-
opts = cls.Opts()
60-
cls.conn = connection.from_config(opts)
59+
cls.conn = connection.from_config(cloud_name=CLOUD_NAME)
6160

6261
@classmethod
6362
def assertIs(cls, expected, actual):

openstack/tests/functional/image/v2/test_image.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@
1818

1919
class TestImage(base.BaseFunctionalTest):
2020

21-
class ImageOpts(base.BaseFunctionalTest.Opts):
21+
class ImageOpts(object):
2222
def __init__(self):
23-
super(TestImage.ImageOpts, self).__init__()
2423
self.image_api_version = '2'
2524

2625
@classmethod
2726
def setUpClass(cls):
2827
opts = cls.ImageOpts()
29-
cls.conn = connection.from_config(opts)
28+
cls.conn = connection.from_config(cloud_name=base.CLOUD_NAME,
29+
options=opts)
3030

3131
cls.img = cls.conn.image.upload_image(
3232
name=TEST_IMAGE_NAME,

openstack/tests/unit/test_connection.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@
1010
# License for the specific language governing permissions and limitations
1111
# under the License.
1212

13+
import os
14+
import tempfile
15+
1316
import mock
17+
import os_client_config
1418

1519
from openstack.auth.identity import v2
1620
from openstack import connection
@@ -19,6 +23,24 @@
1923
from openstack import transport
2024

2125

26+
CONFIG_AUTH_URL = "http://127.0.0.1:5000/v2.0"
27+
CONFIG_USERNAME = "BozoTheClown"
28+
CONFIG_PASSWORD = "TopSecret"
29+
CONFIG_PROJECT = "TheGrandPrizeGame"
30+
31+
CLOUD_CONFIG = """
32+
clouds:
33+
sample:
34+
region_name: RegionOne
35+
auth:
36+
auth_url: {auth_url}
37+
username: {username}
38+
password: {password}
39+
project_name: {project}
40+
""".format(auth_url=CONFIG_AUTH_URL, username=CONFIG_USERNAME,
41+
password=CONFIG_PASSWORD, project=CONFIG_PROJECT)
42+
43+
2244
class TestConnection(base.TestCase):
2345
def setUp(self):
2446
super(TestConnection, self).setUp()
@@ -85,3 +107,63 @@ def test_custom_user_agent(self):
85107
conn = connection.Connection(authenticator=self.auth,
86108
user_agent=user_agent)
87109
self.assertTrue(conn.transport._user_agent.startswith(user_agent))
110+
111+
def _prepare_test_config(self):
112+
# Create a temporary directory where our test config will live
113+
# and insert it into the search path via OS_CLIENT_CONFIG_FILE.
114+
# NOTE: If OCC stops popping OS_C_C_F off of os.environ, this
115+
# will need to change to respect that. It currently works between
116+
# tests because the environment variable is always wiped by OCC itself.
117+
config_dir = tempfile.mkdtemp()
118+
config_path = os.path.join(config_dir, "clouds.yaml")
119+
120+
with open(config_path, "w") as conf:
121+
conf.write(CLOUD_CONFIG)
122+
123+
os.environ["OS_CLIENT_CONFIG_FILE"] = config_path
124+
125+
def test_from_config_given_data(self):
126+
self._prepare_test_config()
127+
128+
data = os_client_config.OpenStackConfig().get_one_cloud("sample")
129+
130+
sot = connection.from_config(cloud_config=data)
131+
132+
self.assertEqual(CONFIG_USERNAME,
133+
sot.authenticator.auth_plugin.username)
134+
self.assertEqual(CONFIG_PASSWORD,
135+
sot.authenticator.auth_plugin.password)
136+
self.assertEqual(CONFIG_AUTH_URL,
137+
sot.authenticator.auth_plugin.auth_url)
138+
self.assertEqual(CONFIG_PROJECT,
139+
sot.authenticator.auth_plugin.tenant_name)
140+
141+
def test_from_config_given_name(self):
142+
self._prepare_test_config()
143+
144+
sot = connection.from_config(cloud_name="sample")
145+
146+
self.assertEqual(CONFIG_USERNAME,
147+
sot.authenticator.auth_plugin.username)
148+
self.assertEqual(CONFIG_PASSWORD,
149+
sot.authenticator.auth_plugin.password)
150+
self.assertEqual(CONFIG_AUTH_URL,
151+
sot.authenticator.auth_plugin.auth_url)
152+
self.assertEqual(CONFIG_PROJECT,
153+
sot.authenticator.auth_plugin.tenant_name)
154+
155+
def test_from_config_given_options(self):
156+
self._prepare_test_config()
157+
158+
version = "100"
159+
160+
class Opts(object):
161+
compute_api_version = version
162+
163+
sot = connection.from_config(cloud_name="sample", options=Opts)
164+
165+
pref = sot.session.profile.get_preference("compute")
166+
167+
# NOTE: Along the way, the `v` prefix gets added so we can build
168+
# up URLs with it.
169+
self.assertEqual("v" + version, pref.version)

0 commit comments

Comments
 (0)