Adds tty password entry for ironicclient

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: I92da7112221c77efc220374617d503dc2184363e
Closes-Bug: 1382146
This commit is contained in:
John Trowbridge 2014-10-16 13:46:33 -04:00
parent c349063d36
commit 9d6137380b
2 changed files with 54 additions and 4 deletions

View File

@ -19,6 +19,7 @@ Command-line interface to the OpenStack Bare Metal Provisioning
from __future__ import print_function
import argparse
import getpass
import logging
import sys
@ -372,10 +373,22 @@ class IronicShell(object):
"either --os-username or via "
"env[OS_USERNAME]"))
if not args.os_password:
# No password, If we've got a tty, try prompting for it
if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
# Check for Ctl-D
try:
args.os_password = getpass.getpass(
'OpenStack Password: ')
except EOFError:
pass
# No password because we didn't have a tty or the
# user Ctl-D when prompted.
if not args.os_password:
raise exc.CommandError(_("You must provide a password via "
"either --os-password or via "
"env[OS_PASSWORD]"))
"either --os-password, "
"env[OS_PASSWORD], "
"or prompted response"))
if not (args.os_tenant_id or args.os_tenant_name or
args.os_project_id or args.os_project_name):

View File

@ -19,8 +19,10 @@ import sys
import fixtures
import httplib2
import httpretty
from keystoneclient import exceptions as keystone_exc
from keystoneclient.fixture import v2 as ks_v2_fixture
from keystoneclient.fixture import v3 as ks_v3_fixture
import mock
import six
import testtools
from testtools import matchers
@ -33,7 +35,7 @@ from ironicclient.tests import utils
FAKE_ENV = {'OS_USERNAME': 'username',
'OS_PASSWORD': 'password',
'OS_TENANT_NAME': 'tenant_name',
'OS_AUTH_URL': 'http://no.where'}
'OS_AUTH_URL': 'http://no.where/v2.0/'}
FAKE_ENV_KEYSTONE_V2 = {
'OS_USERNAME': 'username',
@ -76,7 +78,6 @@ class ShellTest(utils.BaseTestCase):
out = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = orig
return out
def test_help_unknown_command(self):
@ -119,6 +120,42 @@ class ShellTest(utils.BaseTestCase):
self.make_env(exclude='OS_USERNAME')
self.test_help()
@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 will get a Connection Refused because there is no keystone.
self.assertRaises(keystone_exc.ConnectionRefused,
self.shell, 'node-list')
# Make sure we are actually prompted.
mock_getpass.assert_called_with('OpenStack Password: ')
@mock.patch('sys.stdin', side_effect=mock.MagicMock)
@mock.patch('getpass.getpass', side_effect=EOFError)
def test_password_prompted_ctrlD(self, mock_getpass, mock_stdin):
self.make_env(exclude='OS_PASSWORD')
# We should get Command Error because we mock Ctl-D.
self.assertRaises(exc.CommandError,
self.shell, 'node-list')
# Make sure we are actually prompted.
mock_getpass.assert_called_with('OpenStack Password: ')
@mock.patch('sys.stdin')
def test_no_password_no_tty(self, mock_stdin):
# delete the isatty attribute so that we do not get
# prompted when manually running the tests
del mock_stdin.isatty
required = ('You must provide a password'
' via either --os-password, env[OS_PASSWORD],'
' or prompted response',)
self.make_env(exclude='OS_PASSWORD')
try:
self.shell('node-list')
except exc.CommandError as message:
self.assertEqual(required, message.args)
else:
self.fail('CommandError not raised')
def test_bash_completion(self):
stdout = self.shell('bash-completion')
# just check we have some output