Merge "Use session when not specified token or endpoint"
This commit is contained in:
@@ -349,111 +349,101 @@ class OpenStackImagesShell(object):
|
|||||||
ks_session.auth = auth
|
ks_session.auth = auth
|
||||||
return ks_session
|
return ks_session
|
||||||
|
|
||||||
def _get_endpoint_and_token(self, args):
|
def _get_kwargs_for_create_session(self, args):
|
||||||
|
if not args.os_username:
|
||||||
|
raise exc.CommandError(
|
||||||
|
_("You must provide a username via"
|
||||||
|
" either --os-username or "
|
||||||
|
"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('OS 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, "
|
||||||
|
"env[OS_PASSWORD], "
|
||||||
|
"or prompted response"))
|
||||||
|
|
||||||
|
# Validate password flow auth
|
||||||
|
project_info = (
|
||||||
|
args.os_tenant_name or args.os_tenant_id or (
|
||||||
|
args.os_project_name and (
|
||||||
|
args.os_project_domain_name or
|
||||||
|
args.os_project_domain_id
|
||||||
|
)
|
||||||
|
) or args.os_project_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if not project_info:
|
||||||
|
# tenant is deprecated in Keystone v3. Use the latest
|
||||||
|
# terminology instead.
|
||||||
|
raise exc.CommandError(
|
||||||
|
_("You must provide a project_id or project_name ("
|
||||||
|
"with project_domain_name or project_domain_id) "
|
||||||
|
"via "
|
||||||
|
" --os-project-id (env[OS_PROJECT_ID])"
|
||||||
|
" --os-project-name (env[OS_PROJECT_NAME]),"
|
||||||
|
" --os-project-domain-id "
|
||||||
|
"(env[OS_PROJECT_DOMAIN_ID])"
|
||||||
|
" --os-project-domain-name "
|
||||||
|
"(env[OS_PROJECT_DOMAIN_NAME])"))
|
||||||
|
|
||||||
|
if not args.os_auth_url:
|
||||||
|
raise exc.CommandError(
|
||||||
|
_("You must provide an auth url via"
|
||||||
|
" either --os-auth-url or "
|
||||||
|
"via env[OS_AUTH_URL]"))
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
'auth_url': args.os_auth_url,
|
||||||
|
'username': args.os_username,
|
||||||
|
'user_id': args.os_user_id,
|
||||||
|
'user_domain_id': args.os_user_domain_id,
|
||||||
|
'user_domain_name': args.os_user_domain_name,
|
||||||
|
'password': args.os_password,
|
||||||
|
'tenant_name': args.os_tenant_name,
|
||||||
|
'tenant_id': args.os_tenant_id,
|
||||||
|
'project_name': args.os_project_name,
|
||||||
|
'project_id': args.os_project_id,
|
||||||
|
'project_domain_name': args.os_project_domain_name,
|
||||||
|
'project_domain_id': args.os_project_domain_id,
|
||||||
|
'insecure': args.insecure,
|
||||||
|
'cacert': args.os_cacert,
|
||||||
|
'cert': args.os_cert,
|
||||||
|
'key': args.os_key
|
||||||
|
}
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def _get_versioned_client(self, api_version, args):
|
||||||
endpoint = self._get_image_url(args)
|
endpoint = self._get_image_url(args)
|
||||||
auth_token = args.os_auth_token
|
auth_token = args.os_auth_token
|
||||||
|
|
||||||
auth_req = (hasattr(args, 'func') and
|
auth_req = (hasattr(args, 'func') and
|
||||||
utils.is_authentication_required(args.func))
|
utils.is_authentication_required(args.func))
|
||||||
|
if not auth_req or (endpoint and auth_token):
|
||||||
if auth_req and not (endpoint and auth_token):
|
|
||||||
if not args.os_username:
|
|
||||||
raise exc.CommandError(
|
|
||||||
_("You must provide a username via"
|
|
||||||
" either --os-username or "
|
|
||||||
"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('OS 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, "
|
|
||||||
"env[OS_PASSWORD], "
|
|
||||||
"or prompted response"))
|
|
||||||
|
|
||||||
# Validate password flow auth
|
|
||||||
project_info = (
|
|
||||||
args.os_tenant_name or args.os_tenant_id or (
|
|
||||||
args.os_project_name and (
|
|
||||||
args.os_project_domain_name or
|
|
||||||
args.os_project_domain_id
|
|
||||||
)
|
|
||||||
) or args.os_project_id
|
|
||||||
)
|
|
||||||
|
|
||||||
if not project_info:
|
|
||||||
# tenant is deprecated in Keystone v3. Use the latest
|
|
||||||
# terminology instead.
|
|
||||||
raise exc.CommandError(
|
|
||||||
_("You must provide a project_id or project_name ("
|
|
||||||
"with project_domain_name or project_domain_id) "
|
|
||||||
"via "
|
|
||||||
" --os-project-id (env[OS_PROJECT_ID])"
|
|
||||||
" --os-project-name (env[OS_PROJECT_NAME]),"
|
|
||||||
" --os-project-domain-id "
|
|
||||||
"(env[OS_PROJECT_DOMAIN_ID])"
|
|
||||||
" --os-project-domain-name "
|
|
||||||
"(env[OS_PROJECT_DOMAIN_NAME])"))
|
|
||||||
|
|
||||||
if not args.os_auth_url:
|
|
||||||
raise exc.CommandError(
|
|
||||||
_("You must provide an auth url via"
|
|
||||||
" either --os-auth-url or "
|
|
||||||
"via env[OS_AUTH_URL]"))
|
|
||||||
|
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'auth_url': args.os_auth_url,
|
'token': auth_token,
|
||||||
'username': args.os_username,
|
|
||||||
'user_id': args.os_user_id,
|
|
||||||
'user_domain_id': args.os_user_domain_id,
|
|
||||||
'user_domain_name': args.os_user_domain_name,
|
|
||||||
'password': args.os_password,
|
|
||||||
'tenant_name': args.os_tenant_name,
|
|
||||||
'tenant_id': args.os_tenant_id,
|
|
||||||
'project_name': args.os_project_name,
|
|
||||||
'project_id': args.os_project_id,
|
|
||||||
'project_domain_name': args.os_project_domain_name,
|
|
||||||
'project_domain_id': args.os_project_domain_id,
|
|
||||||
'insecure': args.insecure,
|
'insecure': args.insecure,
|
||||||
|
'timeout': args.timeout,
|
||||||
'cacert': args.os_cacert,
|
'cacert': args.os_cacert,
|
||||||
'cert': args.os_cert,
|
'cert': args.os_cert,
|
||||||
'key': args.os_key
|
'key': args.os_key,
|
||||||
|
'ssl_compression': args.ssl_compression
|
||||||
}
|
}
|
||||||
ks_session = self._get_keystone_session(**kwargs)
|
else:
|
||||||
auth_token = args.os_auth_token or ks_session.get_token()
|
kwargs = self._get_kwargs_for_create_session(args)
|
||||||
|
kwargs = {'session': self._get_keystone_session(**kwargs)}
|
||||||
|
|
||||||
endpoint_type = args.os_endpoint_type or 'public'
|
return glanceclient.Client(api_version, endpoint, **kwargs)
|
||||||
service_type = args.os_service_type or 'image'
|
|
||||||
endpoint = args.os_image_url or ks_session.get_endpoint(
|
|
||||||
service_type=service_type,
|
|
||||||
interface=endpoint_type,
|
|
||||||
region_name=args.os_region_name)
|
|
||||||
|
|
||||||
return endpoint, auth_token
|
|
||||||
|
|
||||||
def _get_versioned_client(self, api_version, args):
|
|
||||||
endpoint, token = self._get_endpoint_and_token(args)
|
|
||||||
|
|
||||||
kwargs = {
|
|
||||||
'token': token,
|
|
||||||
'insecure': args.insecure,
|
|
||||||
'timeout': args.timeout,
|
|
||||||
'cacert': args.os_cacert,
|
|
||||||
'cert': args.os_cert,
|
|
||||||
'key': args.os_key,
|
|
||||||
'ssl_compression': args.ssl_compression
|
|
||||||
}
|
|
||||||
client = glanceclient.Client(api_version, endpoint, **kwargs)
|
|
||||||
return client
|
|
||||||
|
|
||||||
def _cache_schemas(self, options, client, home_dir='~/.glanceclient'):
|
def _cache_schemas(self, options, client, home_dir='~/.glanceclient'):
|
||||||
homedir = os.path.expanduser(home_dir)
|
homedir = os.path.expanduser(home_dir)
|
||||||
|
@@ -153,14 +153,14 @@ class ShellTest(testutils.TestCase):
|
|||||||
def test_help(self):
|
def test_help(self):
|
||||||
shell = openstack_shell.OpenStackImagesShell()
|
shell = openstack_shell.OpenStackImagesShell()
|
||||||
argstr = '--os-image-api-version 2 help'
|
argstr = '--os-image-api-version 2 help'
|
||||||
with mock.patch.object(shell, '_get_endpoint_and_token') as et_mock:
|
with mock.patch.object(shell, '_get_keystone_session') as et_mock:
|
||||||
actual = shell.main(argstr.split())
|
actual = shell.main(argstr.split())
|
||||||
self.assertEqual(0, actual)
|
self.assertEqual(0, actual)
|
||||||
self.assertFalse(et_mock.called)
|
self.assertFalse(et_mock.called)
|
||||||
|
|
||||||
def test_blank_call(self):
|
def test_blank_call(self):
|
||||||
shell = openstack_shell.OpenStackImagesShell()
|
shell = openstack_shell.OpenStackImagesShell()
|
||||||
with mock.patch.object(shell, '_get_endpoint_and_token') as et_mock:
|
with mock.patch.object(shell, '_get_keystone_session') as et_mock:
|
||||||
actual = shell.main('')
|
actual = shell.main('')
|
||||||
self.assertEqual(0, actual)
|
self.assertEqual(0, actual)
|
||||||
self.assertFalse(et_mock.called)
|
self.assertFalse(et_mock.called)
|
||||||
@@ -172,7 +172,7 @@ class ShellTest(testutils.TestCase):
|
|||||||
def test_help_v2_no_schema(self):
|
def test_help_v2_no_schema(self):
|
||||||
shell = openstack_shell.OpenStackImagesShell()
|
shell = openstack_shell.OpenStackImagesShell()
|
||||||
argstr = '--os-image-api-version 2 help image-create'
|
argstr = '--os-image-api-version 2 help image-create'
|
||||||
with mock.patch.object(shell, '_get_endpoint_and_token') as et_mock:
|
with mock.patch.object(shell, '_get_keystone_session') as et_mock:
|
||||||
actual = shell.main(argstr.split())
|
actual = shell.main(argstr.split())
|
||||||
self.assertEqual(0, actual)
|
self.assertEqual(0, actual)
|
||||||
self.assertNotIn('<unavailable>', actual)
|
self.assertNotIn('<unavailable>', actual)
|
||||||
@@ -275,15 +275,13 @@ class ShellTest(testutils.TestCase):
|
|||||||
# authenticate to get the verison list *and* to excuted the command.
|
# authenticate to get the verison list *and* to excuted the command.
|
||||||
# This is not the ideal behavior and it should be fixed in a follow
|
# This is not the ideal behavior and it should be fixed in a follow
|
||||||
# up patch.
|
# up patch.
|
||||||
self._assert_auth_plugin_args()
|
|
||||||
|
|
||||||
@mock.patch('glanceclient.v1.client.Client')
|
@mock.patch('glanceclient.v1.client.Client')
|
||||||
def test_auth_plugin_invocation_with_v1(self, v1_client):
|
def test_auth_plugin_invocation_with_v1(self, v1_client):
|
||||||
args = '--os-image-api-version 1 image-list'
|
args = '--os-image-api-version 1 image-list'
|
||||||
glance_shell = openstack_shell.OpenStackImagesShell()
|
glance_shell = openstack_shell.OpenStackImagesShell()
|
||||||
glance_shell.main(args.split())
|
glance_shell.main(args.split())
|
||||||
self.assertEqual(1, self.v2_auth.call_count)
|
self.assertEqual(0, self.v2_auth.call_count)
|
||||||
self._assert_auth_plugin_args()
|
|
||||||
|
|
||||||
@mock.patch('glanceclient.v2.client.Client')
|
@mock.patch('glanceclient.v2.client.Client')
|
||||||
def test_auth_plugin_invocation_with_v2(self,
|
def test_auth_plugin_invocation_with_v2(self,
|
||||||
@@ -291,8 +289,7 @@ class ShellTest(testutils.TestCase):
|
|||||||
args = '--os-image-api-version 2 image-list'
|
args = '--os-image-api-version 2 image-list'
|
||||||
glance_shell = openstack_shell.OpenStackImagesShell()
|
glance_shell = openstack_shell.OpenStackImagesShell()
|
||||||
glance_shell.main(args.split())
|
glance_shell.main(args.split())
|
||||||
self.assertEqual(1, self.v2_auth.call_count)
|
self.assertEqual(0, self.v2_auth.call_count)
|
||||||
self._assert_auth_plugin_args()
|
|
||||||
|
|
||||||
@mock.patch('glanceclient.v1.client.Client')
|
@mock.patch('glanceclient.v1.client.Client')
|
||||||
def test_auth_plugin_invocation_with_unversioned_auth_url_with_v1(
|
def test_auth_plugin_invocation_with_unversioned_auth_url_with_v1(
|
||||||
@@ -301,7 +298,6 @@ class ShellTest(testutils.TestCase):
|
|||||||
DEFAULT_UNVERSIONED_AUTH_URL)
|
DEFAULT_UNVERSIONED_AUTH_URL)
|
||||||
glance_shell = openstack_shell.OpenStackImagesShell()
|
glance_shell = openstack_shell.OpenStackImagesShell()
|
||||||
glance_shell.main(args.split())
|
glance_shell.main(args.split())
|
||||||
self._assert_auth_plugin_args()
|
|
||||||
|
|
||||||
@mock.patch('glanceclient.v2.client.Client')
|
@mock.patch('glanceclient.v2.client.Client')
|
||||||
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
|
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas',
|
||||||
@@ -312,7 +308,6 @@ class ShellTest(testutils.TestCase):
|
|||||||
'image-list') % DEFAULT_UNVERSIONED_AUTH_URL
|
'image-list') % DEFAULT_UNVERSIONED_AUTH_URL
|
||||||
glance_shell = openstack_shell.OpenStackImagesShell()
|
glance_shell = openstack_shell.OpenStackImagesShell()
|
||||||
glance_shell.main(args.split())
|
glance_shell.main(args.split())
|
||||||
self._assert_auth_plugin_args()
|
|
||||||
|
|
||||||
@mock.patch('glanceclient.Client')
|
@mock.patch('glanceclient.Client')
|
||||||
def test_endpoint_token_no_auth_req(self, mock_client):
|
def test_endpoint_token_no_auth_req(self, mock_client):
|
||||||
@@ -333,22 +328,17 @@ class ShellTest(testutils.TestCase):
|
|||||||
glance_shell.main(args)
|
glance_shell.main(args)
|
||||||
self.assertEqual(1, mock_client.call_count)
|
self.assertEqual(1, mock_client.call_count)
|
||||||
|
|
||||||
@mock.patch('sys.stdin', side_effect=mock.MagicMock)
|
|
||||||
@mock.patch('getpass.getpass', return_value='password')
|
|
||||||
@mock.patch('glanceclient.v2.client.Client')
|
@mock.patch('glanceclient.v2.client.Client')
|
||||||
def test_password_prompted_with_v2(self, v2_client,
|
def test_password_prompted_with_v2(self, v2_client):
|
||||||
mock_getpass, mock_stdin):
|
|
||||||
self.requests.post(self.token_url, exc=requests.ConnectionError)
|
self.requests.post(self.token_url, exc=requests.ConnectionError)
|
||||||
|
|
||||||
cli2 = mock.MagicMock()
|
cli2 = mock.MagicMock()
|
||||||
v2_client.return_value = cli2
|
v2_client.return_value = cli2
|
||||||
cli2.http_client.get.return_value = (None, {'versions': []})
|
cli2.http_client.get.return_value = (None, {'versions': []})
|
||||||
glance_shell = openstack_shell.OpenStackImagesShell()
|
glance_shell = openstack_shell.OpenStackImagesShell()
|
||||||
self.make_env(exclude='OS_PASSWORD')
|
os.environ['OS_PASSWORD'] = 'password'
|
||||||
self.assertRaises(ks_exc.ConnectionRefused,
|
self.assertRaises(exc.CommunicationError,
|
||||||
glance_shell.main, ['image-list'])
|
glance_shell.main, ['image-list'])
|
||||||
# Make sure we are actually prompted.
|
|
||||||
mock_getpass.assert_called_once_with('OS Password: ')
|
|
||||||
|
|
||||||
@mock.patch('sys.stdin', side_effect=mock.MagicMock)
|
@mock.patch('sys.stdin', side_effect=mock.MagicMock)
|
||||||
@mock.patch('getpass.getpass', side_effect=EOFError)
|
@mock.patch('getpass.getpass', side_effect=EOFError)
|
||||||
@@ -561,16 +551,14 @@ class ShellTestWithKeystoneV3Auth(ShellTest):
|
|||||||
args = '--os-image-api-version 1 image-list'
|
args = '--os-image-api-version 1 image-list'
|
||||||
glance_shell = openstack_shell.OpenStackImagesShell()
|
glance_shell = openstack_shell.OpenStackImagesShell()
|
||||||
glance_shell.main(args.split())
|
glance_shell.main(args.split())
|
||||||
self.assertEqual(1, self.v3_auth.call_count)
|
self.assertEqual(0, self.v3_auth.call_count)
|
||||||
self._assert_auth_plugin_args()
|
|
||||||
|
|
||||||
@mock.patch('glanceclient.v2.client.Client')
|
@mock.patch('glanceclient.v2.client.Client')
|
||||||
def test_auth_plugin_invocation_with_v2(self, v2_client):
|
def test_auth_plugin_invocation_with_v2(self, v2_client):
|
||||||
args = '--os-image-api-version 2 image-list'
|
args = '--os-image-api-version 2 image-list'
|
||||||
glance_shell = openstack_shell.OpenStackImagesShell()
|
glance_shell = openstack_shell.OpenStackImagesShell()
|
||||||
glance_shell.main(args.split())
|
glance_shell.main(args.split())
|
||||||
self.assertEqual(1, self.v3_auth.call_count)
|
self.assertEqual(0, self.v3_auth.call_count)
|
||||||
self._assert_auth_plugin_args()
|
|
||||||
|
|
||||||
@mock.patch('keystoneclient.discover.Discover',
|
@mock.patch('keystoneclient.discover.Discover',
|
||||||
side_effect=ks_exc.ClientException())
|
side_effect=ks_exc.ClientException())
|
||||||
|
Reference in New Issue
Block a user