Adds tty password entry for cinderclient
Added functionality from keystoneclient to fallback to the tty for password entry if no password is given via the environment or the --os-password option. Change-Id: If5b27cb8c67712860faa24d543ed48eaa542f28b Closes-Bug: 1357559
This commit is contained in:
@@ -21,6 +21,7 @@ Command-line interface to the OpenStack Cinder API.
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import getpass
|
||||||
import glob
|
import glob
|
||||||
import imp
|
import imp
|
||||||
import itertools
|
import itertools
|
||||||
@@ -504,7 +505,6 @@ class OpenStackCinderShell(object):
|
|||||||
ks_logger.setLevel(logging.DEBUG)
|
ks_logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
def main(self, argv):
|
def main(self, argv):
|
||||||
|
|
||||||
# Parse args once to find version and debug settings
|
# Parse args once to find version and debug settings
|
||||||
parser = self.get_base_parser()
|
parser = self.get_base_parser()
|
||||||
(options, args) = parser.parse_known_args(argv)
|
(options, args) = parser.parse_known_args(argv)
|
||||||
@@ -554,7 +554,6 @@ class OpenStackCinderShell(object):
|
|||||||
args.service_type, args.service_name,
|
args.service_type, args.service_name,
|
||||||
args.volume_service_name, args.os_cacert,
|
args.volume_service_name, args.os_cacert,
|
||||||
args.os_auth_system)
|
args.os_auth_system)
|
||||||
|
|
||||||
if os_auth_system and os_auth_system != "keystone":
|
if os_auth_system and os_auth_system != "keystone":
|
||||||
auth_plugin = cinderclient.auth_plugin.load_plugin(os_auth_system)
|
auth_plugin = cinderclient.auth_plugin.load_plugin(os_auth_system)
|
||||||
else:
|
else:
|
||||||
@@ -581,9 +580,20 @@ class OpenStackCinderShell(object):
|
|||||||
"env[OS_USERNAME].")
|
"env[OS_USERNAME].")
|
||||||
|
|
||||||
if not os_password:
|
if not os_password:
|
||||||
raise exc.CommandError("You must provide a password "
|
# No password, If we've got a tty, try prompting for it
|
||||||
"through --os-password or "
|
if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
|
||||||
"env[OS_PASSWORD].")
|
# Check for Ctl-D
|
||||||
|
try:
|
||||||
|
os_password = getpass.getpass('OS Password: ')
|
||||||
|
except EOFError:
|
||||||
|
pass
|
||||||
|
# No password because we didn't have a tty or the
|
||||||
|
# user Ctl-D when prompted.
|
||||||
|
if not os_password:
|
||||||
|
raise exc.CommandError("You must provide a password "
|
||||||
|
"through --os-password, "
|
||||||
|
"env[OS_PASSWORD] "
|
||||||
|
"or, prompted response.")
|
||||||
|
|
||||||
if not (os_tenant_name or os_tenant_id):
|
if not (os_tenant_name or os_tenant_id):
|
||||||
raise exc.CommandError("You must provide a tenant ID "
|
raise exc.CommandError("You must provide a tenant ID "
|
||||||
|
@@ -16,6 +16,7 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import fixtures
|
import fixtures
|
||||||
|
import mock
|
||||||
import requests_mock
|
import requests_mock
|
||||||
from six import moves
|
from six import moves
|
||||||
from testtools import matchers
|
from testtools import matchers
|
||||||
@@ -24,6 +25,7 @@ from cinderclient import exceptions
|
|||||||
from cinderclient import shell
|
from cinderclient import shell
|
||||||
from cinderclient.tests import utils
|
from cinderclient.tests import utils
|
||||||
from cinderclient.tests.fixture_data import keystone_client
|
from cinderclient.tests.fixture_data import keystone_client
|
||||||
|
import keystoneclient.exceptions as ks_exc
|
||||||
from keystoneclient.exceptions import DiscoveryFailure
|
from keystoneclient.exceptions import DiscoveryFailure
|
||||||
|
|
||||||
|
|
||||||
@@ -33,10 +35,14 @@ class ShellTest(utils.TestCase):
|
|||||||
'OS_USERNAME': 'username',
|
'OS_USERNAME': 'username',
|
||||||
'OS_PASSWORD': 'password',
|
'OS_PASSWORD': 'password',
|
||||||
'OS_TENANT_NAME': 'tenant_name',
|
'OS_TENANT_NAME': 'tenant_name',
|
||||||
'OS_AUTH_URL': 'http://no.where',
|
'OS_AUTH_URL': 'http://no.where/v2.0',
|
||||||
}
|
}
|
||||||
|
|
||||||
# Patch os.environ to avoid required auth info.
|
# Patch os.environ to avoid required auth info.
|
||||||
|
def make_env(self, exclude=None):
|
||||||
|
env = dict((k, v) for k, v in self.FAKE_ENV.items() if k != exclude)
|
||||||
|
self.useFixture(fixtures.MonkeyPatch('os.environ', env))
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(ShellTest, self).setUp()
|
super(ShellTest, self).setUp()
|
||||||
for var in self.FAKE_ENV:
|
for var in self.FAKE_ENV:
|
||||||
@@ -110,6 +116,15 @@ class ShellTest(utils.TestCase):
|
|||||||
self.assertEqual(v3_url, os_auth_url, "Expected v3 url")
|
self.assertEqual(v3_url, os_auth_url, "Expected v3 url")
|
||||||
self.assertEqual(v2_url, None, "Expected no v2 url")
|
self.assertEqual(v2_url, None, "Expected no v2 url")
|
||||||
|
|
||||||
|
@mock.patch('sys.stdin', side_effect=mock.MagicMock)
|
||||||
|
@mock.patch('getpass.getpass', return_value='password')
|
||||||
|
def test_password_prompted(self, mock_getpass, mock_stdin):
|
||||||
|
self.make_env(exclude='OS_PASSWORD')
|
||||||
|
# We should get a Connection Refused because there is no keystone.
|
||||||
|
self.assertRaises(ks_exc.ConnectionRefused, self.shell, 'list')
|
||||||
|
# Make sure we are actually prompted.
|
||||||
|
mock_getpass.assert_called_with('OS Password: ')
|
||||||
|
|
||||||
|
|
||||||
class CinderClientArgumentParserTest(utils.TestCase):
|
class CinderClientArgumentParserTest(utils.TestCase):
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user