Merge "More flexible specification of auth credentials."
This commit is contained in:
commit
79cc9254d9
26
bin/glance
26
bin/glance
@ -731,11 +731,12 @@ def get_client(options):
|
||||
specified by the --host and --port options
|
||||
supplied to the CLI
|
||||
"""
|
||||
creds = dict(username=os.getenv('OS_AUTH_USER'),
|
||||
password=os.getenv('OS_AUTH_KEY'),
|
||||
tenant=os.getenv('OS_AUTH_TENANT'),
|
||||
auth_url=os.getenv('OS_AUTH_URL'),
|
||||
strategy=os.getenv('OS_AUTH_STRATEGY', 'noauth'))
|
||||
creds = dict(username=options.username or os.getenv('OS_AUTH_USER'),
|
||||
password=options.password or os.getenv('OS_AUTH_KEY'),
|
||||
tenant=options.tenant or os.getenv('OS_AUTH_TENANT'),
|
||||
auth_url=options.auth_url or os.getenv('OS_AUTH_URL'),
|
||||
strategy=options.auth_strategy or \
|
||||
os.getenv('OS_AUTH_STRATEGY', 'noauth'))
|
||||
|
||||
use_ssl = (options.use_ssl or (
|
||||
creds['auth_url'] is not None and
|
||||
@ -774,6 +775,21 @@ def create_options(parser):
|
||||
metavar="TOKEN", default=None,
|
||||
help="Authentication token to use to identify the "
|
||||
"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,
|
||||
type="int", help="Page size to use while "
|
||||
"requesting image metadata")
|
||||
|
@ -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_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
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -140,9 +140,19 @@ class KeystoneStrategy(BaseStrategy):
|
||||
|
||||
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):
|
||||
try:
|
||||
self.management_url = resp['x-server-management-url']
|
||||
self.management_url = _management_url(self, resp)
|
||||
self.auth_token = resp['x-auth-token']
|
||||
except KeyError:
|
||||
raise exception.AuthorizationFailure()
|
||||
|
@ -15,6 +15,9 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
import keystone.manage
|
||||
|
||||
DEFAULT_FIXTURE = [
|
||||
@ -85,7 +88,7 @@ DEFAULT_FIXTURE = [
|
||||
'http://nova.publicinternets.com/v1.1/', 'http://127.0.0.1:8774/v1.1',
|
||||
'http://localhost:8774/v1.1', '1', '0'),
|
||||
('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://127.0.0.1:9292/v1.1/%tenant_id%', '1', '0'),
|
||||
('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):
|
||||
substitutions = _get_subsitutions(sys.argv)
|
||||
|
||||
keystone.manage.parse_args(args)
|
||||
|
||||
for cmd in fixture:
|
||||
keystone.manage.process(*cmd)
|
||||
expanded = _expand(cmd, substitutions)
|
||||
keystone.manage.process(*expanded)
|
||||
|
||||
|
||||
def main():
|
||||
|
@ -66,6 +66,7 @@ log_file = %(log_file)s
|
||||
backends = keystone.backends.sqlalchemy
|
||||
service-header-mappings = {
|
||||
'nova' : 'X-Server-Management-Url',
|
||||
'glance' : 'X-Image-Management-Url',
|
||||
'swift' : 'X-Storage-Url',
|
||||
'cdn' : 'X-CDN-Management-Url'}
|
||||
service_host = 0.0.0.0
|
||||
@ -247,7 +248,10 @@ class KeystoneTests(functional.FunctionalTest):
|
||||
keystone_conf = self.auth_server.write_conf(**kwargs)
|
||||
datafile = os.path.join(os.path.dirname(__file__), 'data',
|
||||
'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
|
||||
exitcode, out, err = self.auth_server.start(**kwargs)
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
import httplib2
|
||||
import json
|
||||
import os
|
||||
|
||||
from glance.tests import functional
|
||||
from glance.tests.functional import keystone_utils
|
||||
@ -741,21 +742,25 @@ class TestPrivateImagesCli(keystone_utils.KeystoneTests):
|
||||
bin/glance.
|
||||
"""
|
||||
|
||||
@skip_if_disabled
|
||||
def test_glance_cli(self):
|
||||
def setUp(self):
|
||||
"""
|
||||
Test that we can upload an owned image; that we can manipulate
|
||||
its is_public setting; and that appropriate authorization
|
||||
checks are applied to other (non-admin) users.
|
||||
Clear environment to ensure that pre-existing $OS_* variables
|
||||
do not leak into test.
|
||||
"""
|
||||
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.start_servers()
|
||||
|
||||
# Add a non-public image
|
||||
cmd = ("echo testdata | bin/glance --port=%d --auth_token=%s add "
|
||||
"name=MyImage" %
|
||||
(self.api_port, keystone_utils.pattieblack_token))
|
||||
exitcode, out, err = execute(cmd)
|
||||
# Add a non-public image using the given glance command line
|
||||
exitcode, out, err = execute("echo testdata | %s" % cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
image_id = out.strip()[25:]
|
||||
@ -833,3 +838,44 @@ class TestPrivateImagesCli(keystone_utils.KeystoneTests):
|
||||
self.assertEqual(response['x-image-meta-owner'], '')
|
||||
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user