Merge "More flexible specification of auth credentials."

This commit is contained in:
Jenkins 2012-01-24 20:32:15 +00:00 committed by Gerrit Code Review
commit 79cc9254d9
6 changed files with 148 additions and 19 deletions

View File

@ -731,11 +731,12 @@ def get_client(options):
specified by the --host and --port options specified by the --host and --port options
supplied to the CLI supplied to the CLI
""" """
creds = dict(username=os.getenv('OS_AUTH_USER'), creds = dict(username=options.username or os.getenv('OS_AUTH_USER'),
password=os.getenv('OS_AUTH_KEY'), password=options.password or os.getenv('OS_AUTH_KEY'),
tenant=os.getenv('OS_AUTH_TENANT'), tenant=options.tenant or os.getenv('OS_AUTH_TENANT'),
auth_url=os.getenv('OS_AUTH_URL'), auth_url=options.auth_url or os.getenv('OS_AUTH_URL'),
strategy=os.getenv('OS_AUTH_STRATEGY', 'noauth')) strategy=options.auth_strategy or \
os.getenv('OS_AUTH_STRATEGY', 'noauth'))
use_ssl = (options.use_ssl or ( use_ssl = (options.use_ssl or (
creds['auth_url'] is not None and creds['auth_url'] is not None and
@ -774,6 +775,21 @@ def create_options(parser):
metavar="TOKEN", default=None, metavar="TOKEN", default=None,
help="Authentication token to use to identify the " help="Authentication token to use to identify the "
"client to the glance server") "client to the glance server")
parser.add_option('-I', '--username', dest="username",
metavar="USER", default=None,
help="User name used to acquire an authentication token")
parser.add_option('-K', '--password', dest="password",
metavar="PASSWORD", default=None,
help="Password used to acquire an authentication token")
parser.add_option('-T', '--tenant', dest="tenant",
metavar="TENANT", default=None,
help="Tenant name")
parser.add_option('-N', '--auth_url', dest="auth_url",
metavar="AUTH_URL", default=None,
help="Authentication URL")
parser.add_option('-S', '--auth_strategy', dest="auth_strategy",
metavar="STRATEGY", default=None,
help="Authentication strategy (keystone or noauth)")
parser.add_option('--limit', dest="limit", metavar="LIMIT", default=10, parser.add_option('--limit', dest="limit", metavar="LIMIT", default=10,
type="int", help="Page size to use while " type="int", help="Page size to use while "
"requesting image metadata") "requesting image metadata")

View File

@ -84,6 +84,32 @@ The final step is to verify that the `OS_AUTH_` crednetials are present::
OS_AUTH_URL=<THIS SHOULD POINT TO KEYSTONE> OS_AUTH_URL=<THIS SHOULD POINT TO KEYSTONE>
OS_AUTH_STRATEGY=keystone OS_AUTH_STRATEGY=keystone
Alternatively, these credentials may be specified using the following
switches to the ``bin/glance`` command:
-I USER, --username=USER
User name used to acquire an authentication token
-K PASSWORD, --password=PASSWORD
Password used to acquire an authentication token
-T TENANT, --tenant=TENANT
Tenant name
-N AUTH_URL, --auth_url=AUTH_URL
Authentication URL
-S STRATEGY, --auth_strategy=STRATEGY
Authentication strategy (keystone or noauth)
Or, if a pre-authenticated token is preferred, the following option allows
the client-side interaction with keystone to be by-passed (useful if a long
sequence of commands is being scripted):
-A TOKEN, --auth_token=TOKEN
Authentication token to use to identify the client to
the glance server
In general the command line switch takes precedence over the corresponding
OS_AUTH_* environment variable, if both are set.
Configuring the Glance servers to use Keystone Configuring the Glance servers to use Keystone
---------------------------------------------- ----------------------------------------------

View File

@ -140,9 +140,19 @@ class KeystoneStrategy(BaseStrategy):
resp, resp_body = self._do_request(token_url, 'GET', headers=headers) resp, resp_body = self._do_request(token_url, 'GET', headers=headers)
def _management_url(self, resp):
for url_header in ('x-image-management-url',
'x-server-management-url',
'x-glance'):
try:
return resp[url_header]
except KeyError as e:
not_found = e
raise not_found
if resp.status in (200, 204): if resp.status in (200, 204):
try: try:
self.management_url = resp['x-server-management-url'] self.management_url = _management_url(self, resp)
self.auth_token = resp['x-auth-token'] self.auth_token = resp['x-auth-token']
except KeyError: except KeyError:
raise exception.AuthorizationFailure() raise exception.AuthorizationFailure()

View File

@ -15,6 +15,9 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import re
import sys
import keystone.manage import keystone.manage
DEFAULT_FIXTURE = [ DEFAULT_FIXTURE = [
@ -85,7 +88,7 @@ DEFAULT_FIXTURE = [
'http://nova.publicinternets.com/v1.1/', 'http://127.0.0.1:8774/v1.1', 'http://nova.publicinternets.com/v1.1/', 'http://127.0.0.1:8774/v1.1',
'http://localhost:8774/v1.1', '1', '0'), 'http://localhost:8774/v1.1', '1', '0'),
('endpointTemplates', 'add', 'RegionOne', 'glance', ('endpointTemplates', 'add', 'RegionOne', 'glance',
'http://glance.publicinternets.com/v1.1/%tenant_id%', 'http://127.0.0.1:%api_port%/v1',
'http://nova.admin-nets.local/v1.1/%tenant_id%', 'http://nova.admin-nets.local/v1.1/%tenant_id%',
'http://127.0.0.1:9292/v1.1/%tenant_id%', '1', '0'), 'http://127.0.0.1:9292/v1.1/%tenant_id%', '1', '0'),
('endpointTemplates', 'add', 'RegionOne', 'cdn', ('endpointTemplates', 'add', 'RegionOne', 'cdn',
@ -140,10 +143,34 @@ DEFAULT_FIXTURE = [
] ]
def _get_subsitutions(args):
substitutions = {}
for arg in args:
matches = re.match('(.*)=(.*)', arg)
if matches:
token = '%%%s%%' % matches.group(1)
value = matches.group(2)
substitutions[token] = value
return substitutions
def _expand(cmd, substitutions):
expanded = ()
for word in cmd:
for token in substitutions.keys():
word = word.replace(token, substitutions[token])
expanded = expanded + (word,)
return expanded
def load_fixture(fixture=DEFAULT_FIXTURE, args=None): def load_fixture(fixture=DEFAULT_FIXTURE, args=None):
substitutions = _get_subsitutions(sys.argv)
keystone.manage.parse_args(args) keystone.manage.parse_args(args)
for cmd in fixture: for cmd in fixture:
keystone.manage.process(*cmd) expanded = _expand(cmd, substitutions)
keystone.manage.process(*expanded)
def main(): def main():

View File

@ -66,6 +66,7 @@ log_file = %(log_file)s
backends = keystone.backends.sqlalchemy backends = keystone.backends.sqlalchemy
service-header-mappings = { service-header-mappings = {
'nova' : 'X-Server-Management-Url', 'nova' : 'X-Server-Management-Url',
'glance' : 'X-Image-Management-Url',
'swift' : 'X-Storage-Url', 'swift' : 'X-Storage-Url',
'cdn' : 'X-CDN-Management-Url'} 'cdn' : 'X-CDN-Management-Url'}
service_host = 0.0.0.0 service_host = 0.0.0.0
@ -247,7 +248,10 @@ class KeystoneTests(functional.FunctionalTest):
keystone_conf = self.auth_server.write_conf(**kwargs) keystone_conf = self.auth_server.write_conf(**kwargs)
datafile = os.path.join(os.path.dirname(__file__), 'data', datafile = os.path.join(os.path.dirname(__file__), 'data',
'keystone_data.py') 'keystone_data.py')
execute("python %s -c %s" % (datafile, keystone_conf))
cmd = "python %s -c %s api_port=%d" % \
(datafile, keystone_conf, self.api_server.bind_port)
execute(cmd)
# Start keystone-auth # Start keystone-auth
exitcode, out, err = self.auth_server.start(**kwargs) exitcode, out, err = self.auth_server.start(**kwargs)

View File

@ -19,6 +19,7 @@
import httplib2 import httplib2
import json import json
import os
from glance.tests import functional from glance.tests import functional
from glance.tests.functional import keystone_utils from glance.tests.functional import keystone_utils
@ -741,21 +742,25 @@ class TestPrivateImagesCli(keystone_utils.KeystoneTests):
bin/glance. bin/glance.
""" """
@skip_if_disabled def setUp(self):
def test_glance_cli(self):
""" """
Test that we can upload an owned image; that we can manipulate Clear environment to ensure that pre-existing $OS_* variables
its is_public setting; and that appropriate authorization do not leak into test.
checks are applied to other (non-admin) users. """
self._clear_os_env()
super(TestPrivateImagesCli, self).setUp()
def _do_test_glance_cli(self, cmd):
"""
Test that we can upload an owned image with a given command line;
that we can manipulate its is_public setting; and that appropriate
authorization checks are applied to other (non-admin) users.
""" """
self.cleanup() self.cleanup()
self.start_servers() self.start_servers()
# Add a non-public image # Add a non-public image using the given glance command line
cmd = ("echo testdata | bin/glance --port=%d --auth_token=%s add " exitcode, out, err = execute("echo testdata | %s" % cmd)
"name=MyImage" %
(self.api_port, keystone_utils.pattieblack_token))
exitcode, out, err = execute(cmd)
self.assertEqual(0, exitcode) self.assertEqual(0, exitcode)
image_id = out.strip()[25:] image_id = out.strip()[25:]
@ -833,3 +838,44 @@ class TestPrivateImagesCli(keystone_utils.KeystoneTests):
self.assertEqual(response['x-image-meta-owner'], '') self.assertEqual(response['x-image-meta-owner'], '')
self.stop_servers() self.stop_servers()
def _clear_os_env(self):
os.environ.pop('OS_AUTH_URL', None)
os.environ.pop('OS_AUTH_STRATEGY', None)
os.environ.pop('OS_AUTH_USER', None)
os.environ.pop('OS_AUTH_KEY', None)
@skip_if_disabled
def test_glance_cli_noauth_strategy(self):
"""
Test the CLI with the noauth strategy defaulted to.
"""
cmd = ("bin/glance --port=%d --auth_token=%s add name=MyImage" %
(self.api_port, keystone_utils.pattieblack_token))
self._do_test_glance_cli(cmd)
@skip_if_disabled
def test_glance_cli_keystone_strategy_switches(self):
"""
Test the CLI with the keystone (v1) strategy enabled via
command line switches.
"""
substitutions = (self.api_port, self.auth_port, 'keystone',
'pattieblack', 'secrete')
cmd = ("bin/glance --port=%d --auth_url=http://localhost:%d/v1.0 "
"--auth_strategy=%s --username=%s --password=%s "
" add name=MyImage" % substitutions)
self._do_test_glance_cli(cmd)
@skip_if_disabled
def test_glance_cli_keystone_strategy_environment(self):
"""
Test the CLI with the keystone strategy enabled via
environment variables.
"""
os.environ['OS_AUTH_URL'] = 'http://localhost:%d/v1.0' % self.auth_port
os.environ['OS_AUTH_STRATEGY'] = 'keystone'
os.environ['OS_AUTH_USER'] = 'pattieblack'
os.environ['OS_AUTH_KEY'] = 'secrete'
cmd = "bin/glance --port=%d add name=MyImage" % self.api_port
self._do_test_glance_cli(cmd)