Skip to content

Commit 46cc7d1

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Add configuration show command"
2 parents e54a15a + 4394287 commit 46cc7d1

7 files changed

Lines changed: 178 additions & 0 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=============
2+
configuration
3+
=============
4+
5+
Available for all services
6+
7+
configuration show
8+
------------------
9+
10+
Show the current openstack client configuration. This command is a little
11+
different from other show commands because it does not take a resource name
12+
or id to show. The command line options, such as --os-cloud, can be used to
13+
show different configurations.
14+
15+
.. program:: configuration show
16+
.. code:: bash
17+
18+
os configuration show

doc/source/configuration.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,9 @@ that appears in :file:`clouds.yaml`
137137
rackspace:
138138
auth:
139139
auth_url: 'https://identity.api.rackspacecloud.com/v2.0/'
140+
141+
Debugging
142+
~~~~~~~~~
143+
You may find the :doc:`config show <command-objects/config>`
144+
helpful to debug configuration issues. It will display your current
145+
configuration.

openstackclient/common/clientmanager.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
"""Manage access to the clients, including authenticating when needed."""
1717

18+
import copy
1819
import logging
1920
import pkg_resources
2021
import sys
@@ -203,6 +204,9 @@ def get_endpoint_for_service_type(self, service_type, region_name=None,
203204
interface=interface)
204205
return endpoint
205206

207+
def get_configuration(self):
208+
return copy.deepcopy(self._cli_options.config)
209+
206210

207211
# Plugin Support
208212

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
"""Configuration action implementations"""
15+
16+
import logging
17+
18+
from cliff import show
19+
import six
20+
21+
REDACTED = "<redacted>"
22+
23+
24+
class ShowConfiguration(show.ShowOne):
25+
"""Display configuration details"""
26+
27+
log = logging.getLogger(__name__ + '.ShowConfiguration')
28+
29+
def get_parser(self, prog_name):
30+
parser = super(ShowConfiguration, self).get_parser(prog_name)
31+
mask_group = parser.add_mutually_exclusive_group()
32+
mask_group.add_argument(
33+
"--mask",
34+
dest="mask",
35+
action="store_true",
36+
default=True,
37+
help="Attempt to mask passwords (default)",
38+
)
39+
mask_group.add_argument(
40+
"--unmask",
41+
dest="mask",
42+
action="store_false",
43+
help="Show password in clear text",
44+
)
45+
return parser
46+
47+
def take_action(self, parsed_args):
48+
self.log.debug('take_action(%s)', parsed_args)
49+
50+
info = self.app.client_manager.get_configuration()
51+
for key, value in six.iteritems(info.pop('auth', {})):
52+
if parsed_args.mask:
53+
if 'password' in key.lower():
54+
value = REDACTED
55+
if 'token' in key.lower():
56+
value = REDACTED
57+
info['auth.' + key] = value
58+
return zip(*sorted(six.iteritems(info)))
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
from openstackclient.common import configuration
15+
from openstackclient.tests import fakes
16+
from openstackclient.tests import utils
17+
18+
19+
class TestConfiguration(utils.TestCommand):
20+
21+
def test_show(self):
22+
arglist = []
23+
verifylist = [('mask', True)]
24+
cmd = configuration.ShowConfiguration(self.app, None)
25+
parsed_args = self.check_parser(cmd, arglist, verifylist)
26+
27+
columns, data = cmd.take_action(parsed_args)
28+
29+
collist = ('auth.password', 'auth.token', 'auth.username',
30+
'identity_api_version', 'region')
31+
self.assertEqual(collist, columns)
32+
datalist = (
33+
configuration.REDACTED,
34+
configuration.REDACTED,
35+
fakes.USERNAME,
36+
fakes.VERSION,
37+
fakes.REGION_NAME,
38+
)
39+
self.assertEqual(datalist, tuple(data))
40+
41+
def test_show_unmask(self):
42+
arglist = ['--unmask']
43+
verifylist = [('mask', False)]
44+
cmd = configuration.ShowConfiguration(self.app, None)
45+
parsed_args = self.check_parser(cmd, arglist, verifylist)
46+
47+
columns, data = cmd.take_action(parsed_args)
48+
49+
collist = ('auth.password', 'auth.token', 'auth.username',
50+
'identity_api_version', 'region')
51+
self.assertEqual(collist, columns)
52+
datalist = (
53+
fakes.PASSWORD,
54+
fakes.AUTH_TOKEN,
55+
fakes.USERNAME,
56+
fakes.VERSION,
57+
fakes.REGION_NAME,
58+
)
59+
self.assertEqual(datalist, tuple(data))
60+
61+
def test_show_mask(self):
62+
arglist = ['--mask']
63+
verifylist = [('mask', True)]
64+
cmd = configuration.ShowConfiguration(self.app, None)
65+
parsed_args = self.check_parser(cmd, arglist, verifylist)
66+
67+
columns, data = cmd.take_action(parsed_args)
68+
69+
collist = ('auth.password', 'auth.token', 'auth.username',
70+
'identity_api_version', 'region')
71+
self.assertEqual(collist, columns)
72+
datalist = (
73+
configuration.REDACTED,
74+
configuration.REDACTED,
75+
fakes.USERNAME,
76+
fakes.VERSION,
77+
fakes.REGION_NAME,
78+
)
79+
self.assertEqual(datalist, tuple(data))

openstackclient/tests/fakes.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
PROJECT_NAME = "poochie"
2929
REGION_NAME = "richie"
3030
INTERFACE = "catchy"
31+
VERSION = "3"
3132

3233
TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN,
3334
user_name=USERNAME)
@@ -102,6 +103,17 @@ def __init__(self):
102103
self.auth_ref = None
103104
self.auth_plugin_name = None
104105

106+
def get_configuration(self):
107+
return {
108+
'auth': {
109+
'username': USERNAME,
110+
'password': PASSWORD,
111+
'token': AUTH_TOKEN,
112+
},
113+
'region': REGION_NAME,
114+
'identity_api_version': VERSION,
115+
}
116+
105117

106118
class FakeModule(object):
107119
def __init__(self, name, version):

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ openstack.cli.base =
4444
volume = openstackclient.volume.client
4545

4646
openstack.common =
47+
configuration_show = openstackclient.common.configuration:ShowConfiguration
4748
extension_list = openstackclient.common.extension:ListExtension
4849
limits_show = openstackclient.common.limits:ShowLimits
4950
quota_set = openstackclient.common.quota:SetQuota

0 commit comments

Comments
 (0)