Add configuration show command
Create a `configuration show` command that displays the current configuration of the CLI. Different configurations can be displayed using options such as --os-cloud. Passwords and tokens are redacted by default unless the --unmask option is specified. Closes-Bug: #1476729 Change-Id: I0792365d0c5fa526cd09c0ed88c6bb1e2cb813a7
This commit is contained in:
		 TerryHowe
					TerryHowe
				
			
				
					committed by
					
						 gustavo panizzo
						gustavo panizzo
					
				
			
			
				
	
			
			
			 gustavo panizzo
						gustavo panizzo
					
				
			
						parent
						
							52cd87d090
						
					
				
				
					commit
					1e562cce60
				
			
							
								
								
									
										18
									
								
								doc/source/command-objects/configuration.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								doc/source/command-objects/configuration.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| ============= | ||||
| configuration | ||||
| ============= | ||||
|  | ||||
| Available for all services | ||||
|  | ||||
| configuration show | ||||
| ------------------ | ||||
|  | ||||
| Show the current openstack client configuration.  This command is a little | ||||
| different from other show commands because it does not take a resource name | ||||
| or id to show.  The command line options, such as --os-cloud, can be used to | ||||
| show different configurations. | ||||
|  | ||||
| .. program:: configuration show | ||||
| .. code:: bash | ||||
|  | ||||
|     os configuration show | ||||
| @@ -137,3 +137,9 @@ that appears in :file:`clouds.yaml` | ||||
|       rackspace: | ||||
|         auth: | ||||
|           auth_url: 'https://identity.api.rackspacecloud.com/v2.0/' | ||||
|  | ||||
| Debugging | ||||
| ~~~~~~~~~ | ||||
| You may find the :doc:`config show <command-objects/config>` | ||||
| helpful to debug configuration issues.  It will display your current | ||||
| configuration. | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
|  | ||||
| """Manage access to the clients, including authenticating when needed.""" | ||||
|  | ||||
| import copy | ||||
| import logging | ||||
| import pkg_resources | ||||
| import sys | ||||
| @@ -207,6 +208,9 @@ class ClientManager(object): | ||||
|                                               interface=interface) | ||||
|         return endpoint | ||||
|  | ||||
|     def get_configuration(self): | ||||
|         return copy.deepcopy(self._cli_options.config) | ||||
|  | ||||
|  | ||||
| # Plugin Support | ||||
|  | ||||
|   | ||||
							
								
								
									
										58
									
								
								openstackclient/common/configuration.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								openstackclient/common/configuration.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| #   Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
| #   not use this file except in compliance with the License. You may obtain | ||||
| #   a copy of the License at | ||||
| # | ||||
| #        http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| #   Unless required by applicable law or agreed to in writing, software | ||||
| #   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| #   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| #   License for the specific language governing permissions and limitations | ||||
| #   under the License. | ||||
| # | ||||
|  | ||||
| """Configuration action implementations""" | ||||
|  | ||||
| import logging | ||||
|  | ||||
| from cliff import show | ||||
| import six | ||||
|  | ||||
| REDACTED = "<redacted>" | ||||
|  | ||||
|  | ||||
| class ShowConfiguration(show.ShowOne): | ||||
|     """Display configuration details""" | ||||
|  | ||||
|     log = logging.getLogger(__name__ + '.ShowConfiguration') | ||||
|  | ||||
|     def get_parser(self, prog_name): | ||||
|         parser = super(ShowConfiguration, self).get_parser(prog_name) | ||||
|         mask_group = parser.add_mutually_exclusive_group() | ||||
|         mask_group.add_argument( | ||||
|             "--mask", | ||||
|             dest="mask", | ||||
|             action="store_true", | ||||
|             default=True, | ||||
|             help="Attempt to mask passwords (default)", | ||||
|         ) | ||||
|         mask_group.add_argument( | ||||
|             "--unmask", | ||||
|             dest="mask", | ||||
|             action="store_false", | ||||
|             help="Show password in clear text", | ||||
|         ) | ||||
|         return parser | ||||
|  | ||||
|     def take_action(self, parsed_args): | ||||
|         self.log.debug('take_action(%s)', parsed_args) | ||||
|  | ||||
|         info = self.app.client_manager.get_configuration() | ||||
|         for key, value in six.iteritems(info.pop('auth', {})): | ||||
|             if parsed_args.mask: | ||||
|                 if 'password' in key.lower(): | ||||
|                     value = REDACTED | ||||
|                 if 'token' in key.lower(): | ||||
|                     value = REDACTED | ||||
|             info['auth.' + key] = value | ||||
|         return zip(*sorted(six.iteritems(info))) | ||||
							
								
								
									
										79
									
								
								openstackclient/tests/common/test_configuration.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								openstackclient/tests/common/test_configuration.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| #   Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
| #   not use this file except in compliance with the License. You may obtain | ||||
| #   a copy of the License at | ||||
| # | ||||
| #        http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| #   Unless required by applicable law or agreed to in writing, software | ||||
| #   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| #   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| #   License for the specific language governing permissions and limitations | ||||
| #   under the License. | ||||
| # | ||||
|  | ||||
| from openstackclient.common import configuration | ||||
| from openstackclient.tests import fakes | ||||
| from openstackclient.tests import utils | ||||
|  | ||||
|  | ||||
| class TestConfiguration(utils.TestCommand): | ||||
|  | ||||
|     def test_show(self): | ||||
|         arglist = [] | ||||
|         verifylist = [('mask', True)] | ||||
|         cmd = configuration.ShowConfiguration(self.app, None) | ||||
|         parsed_args = self.check_parser(cmd, arglist, verifylist) | ||||
|  | ||||
|         columns, data = cmd.take_action(parsed_args) | ||||
|  | ||||
|         collist = ('auth.password', 'auth.token', 'auth.username', | ||||
|                    'identity_api_version', 'region') | ||||
|         self.assertEqual(collist, columns) | ||||
|         datalist = ( | ||||
|             configuration.REDACTED, | ||||
|             configuration.REDACTED, | ||||
|             fakes.USERNAME, | ||||
|             fakes.VERSION, | ||||
|             fakes.REGION_NAME, | ||||
|         ) | ||||
|         self.assertEqual(datalist, tuple(data)) | ||||
|  | ||||
|     def test_show_unmask(self): | ||||
|         arglist = ['--unmask'] | ||||
|         verifylist = [('mask', False)] | ||||
|         cmd = configuration.ShowConfiguration(self.app, None) | ||||
|         parsed_args = self.check_parser(cmd, arglist, verifylist) | ||||
|  | ||||
|         columns, data = cmd.take_action(parsed_args) | ||||
|  | ||||
|         collist = ('auth.password', 'auth.token', 'auth.username', | ||||
|                    'identity_api_version', 'region') | ||||
|         self.assertEqual(collist, columns) | ||||
|         datalist = ( | ||||
|             fakes.PASSWORD, | ||||
|             fakes.AUTH_TOKEN, | ||||
|             fakes.USERNAME, | ||||
|             fakes.VERSION, | ||||
|             fakes.REGION_NAME, | ||||
|         ) | ||||
|         self.assertEqual(datalist, tuple(data)) | ||||
|  | ||||
|     def test_show_mask(self): | ||||
|         arglist = ['--mask'] | ||||
|         verifylist = [('mask', True)] | ||||
|         cmd = configuration.ShowConfiguration(self.app, None) | ||||
|         parsed_args = self.check_parser(cmd, arglist, verifylist) | ||||
|  | ||||
|         columns, data = cmd.take_action(parsed_args) | ||||
|  | ||||
|         collist = ('auth.password', 'auth.token', 'auth.username', | ||||
|                    'identity_api_version', 'region') | ||||
|         self.assertEqual(collist, columns) | ||||
|         datalist = ( | ||||
|             configuration.REDACTED, | ||||
|             configuration.REDACTED, | ||||
|             fakes.USERNAME, | ||||
|             fakes.VERSION, | ||||
|             fakes.REGION_NAME, | ||||
|         ) | ||||
|         self.assertEqual(datalist, tuple(data)) | ||||
| @@ -28,6 +28,7 @@ PASSWORD = "scratchy" | ||||
| PROJECT_NAME = "poochie" | ||||
| REGION_NAME = "richie" | ||||
| INTERFACE = "catchy" | ||||
| VERSION = "3" | ||||
|  | ||||
| TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN, | ||||
|                                      user_name=USERNAME) | ||||
| @@ -102,6 +103,17 @@ class FakeClientManager(object): | ||||
|         self.auth_ref = None | ||||
|         self.auth_plugin_name = None | ||||
|  | ||||
|     def get_configuration(self): | ||||
|         return { | ||||
|             'auth': { | ||||
|                 'username': USERNAME, | ||||
|                 'password': PASSWORD, | ||||
|                 'token': AUTH_TOKEN, | ||||
|             }, | ||||
|             'region': REGION_NAME, | ||||
|             'identity_api_version': VERSION, | ||||
|         } | ||||
|  | ||||
|  | ||||
| class FakeModule(object): | ||||
|     def __init__(self, name, version): | ||||
|   | ||||
| @@ -44,6 +44,7 @@ openstack.cli.base = | ||||
|     volume = openstackclient.volume.client | ||||
|  | ||||
| openstack.common = | ||||
|     configuration_show = openstackclient.common.configuration:ShowConfiguration | ||||
|     extension_list = openstackclient.common.extension:ListExtension | ||||
|     limits_show = openstackclient.common.limits:ShowLimits | ||||
|     quota_set = openstackclient.common.quota:SetQuota | ||||
|   | ||||
		Reference in New Issue
	
	Block a user