diff --git a/bin/glance b/bin/glance index e11addd802..f651cd1a13 100755 --- a/bin/glance +++ b/bin/glance @@ -41,10 +41,10 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')): gettext.install('glance', unicode=1) -from glance import version from glance import client as glance_client from glance.common import exception from glance.common import utils +from glance import version SUCCESS = 0 @@ -784,43 +784,16 @@ def get_client(options): specified by the --host and --port options supplied to the CLI """ - - if options.auth_url or os.getenv('OS_AUTH_URL'): - force_strategy = 'keystone' - else: - force_strategy = None - - creds = dict(username=options.username or \ - os.getenv('OS_AUTH_USER', os.getenv('OS_USERNAME')), - password=options.password or \ - os.getenv('OS_AUTH_KEY', os.getenv('OS_PASSWORD')), - tenant=options.tenant or \ - os.getenv('OS_AUTH_TENANT', - os.getenv('OS_TENANT_NAME')), - auth_url=options.auth_url or os.getenv('OS_AUTH_URL'), - strategy=force_strategy or options.auth_strategy or \ - os.getenv('OS_AUTH_STRATEGY', 'noauth'), - region=options.region or os.getenv('OS_REGION_NAME'), - ) - - if creds['strategy'] == 'keystone' and not creds['auth_url']: - msg = ("--auth_url option or OS_AUTH_URL environment variable " - "required when keystone authentication strategy is enabled\n") - raise exception.ClientConfigurationError(msg) - - use_ssl = (options.use_ssl or ( - creds['auth_url'] is not None and - creds['auth_url'].find('https') != -1)) - - client = (glance_client.ProgressClient if not options.is_silent_upload - else glance_client.Client) - - return client(host=options.host, + return glance_client.get_client(host=options.host, port=options.port, - use_ssl=use_ssl, - auth_tok=options.auth_token or - os.getenv('OS_TOKEN'), - creds=creds, + username=options.username, + password=options.password, + tenant=options.tenant, + auth_url=options.auth_url, + auth_strategy=options.auth_strategy, + auth_token=options.auth_token, + region=options.region, + is_silent_upload=options.is_silent_upload, insecure=options.insecure) diff --git a/bin/glance-cache-manage b/bin/glance-cache-manage index 3ec3a21531..a0854eb2dd 100755 --- a/bin/glance-cache-manage +++ b/bin/glance-cache-manage @@ -38,9 +38,9 @@ if os.path.exists(os.path.join(possible_topdir, 'glance', '__init__.py')): gettext.install('glance', unicode=1) from glance import client as glance_client -from glance import version from glance.common import exception from glance.common import utils +from glance import version SUCCESS = 0 @@ -259,19 +259,16 @@ 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')) - - use_ssl = (options.host.find('https') != -1 or ( - creds['auth_url'] is not None and - creds['auth_url'].find('https') != -1)) - - return glance_client.Client(host=options.host, port=options.port, - use_ssl=use_ssl, auth_tok=options.auth_token, - creds=creds) + return glance_client.get_client(host=options.host, + port=options.port, + username=options.username, + password=options.password, + tenant=options.tenant, + auth_url=options.auth_url, + auth_strategy=options.auth_strategy, + auth_token=options.auth_token, + region=options.region, + insecure=options.insecure) def create_options(parser): @@ -296,6 +293,34 @@ 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('-R', '--region', dest="region", + metavar="REGION", default=None, + help="Region name. When using keystone authentication " + "version 2.0 or later this identifies the region " + "name to use when selecting the service endpoint. A " + "region name must be provided if more than one " + "region endpoint is available") + 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('-k', '--insecure', dest="insecure", + default=False, action="store_true", + help="Explicitly allow glance to perform \"insecure\" " + "SSL (https) requests. The server's certificate will " + "not be verified against any certificate authorities. " + "This option should be used with caution.") + parser.add_option('-S', '--auth_strategy', dest="auth_strategy", + metavar="STRATEGY", default=None, + help="Authentication strategy (keystone or noauth)") parser.add_option('-f', '--force', dest="force", metavar="FORCE", default=False, action="store_true", help="Prevent select actions from requesting " diff --git a/etc/glance-cache.conf b/etc/glance-cache.conf index 8985ea5c38..bbee69454c 100644 --- a/etc/glance-cache.conf +++ b/etc/glance-cache.conf @@ -36,5 +36,8 @@ registry_host = 0.0.0.0 # Port the registry server is listening on registry_port = 9191 -# Admin token to use if using Keystone -# admin_token = 123 +# Auth settings if using Keystone +# auth_url = http://127.0.0.1:5000/v2.0/ +# admin_tenant_name = %SERVICE_TENANT_NAME% +# admin_user = %SERVICE_USER% +# admin_password = %SERVICE_PASSWORD% diff --git a/glance/client.py b/glance/client.py index 45669989e1..3a38ac767b 100644 --- a/glance/client.py +++ b/glance/client.py @@ -399,3 +399,51 @@ class ProgressClient(V1Client): return transfer_info Client = V1Client + + +def get_client(host, port=None, username=None, + password=None, tenant=None, + auth_url=None, auth_strategy=None, + auth_token=None, region=None, + is_silent_upload=False, insecure=False): + """ + Returns a new client Glance client object based on common kwargs. + If an option isn't specified falls back to common environment variable + defaults. + """ + + if auth_url or os.getenv('OS_AUTH_URL'): + force_strategy = 'keystone' + else: + force_strategy = None + + creds = dict(username=username or + os.getenv('OS_AUTH_USER', os.getenv('OS_USERNAME')), + password=password or + os.getenv('OS_AUTH_KEY', os.getenv('OS_PASSWORD')), + tenant=tenant or + os.getenv('OS_AUTH_TENANT', + os.getenv('OS_TENANT_NAME')), + auth_url=auth_url or os.getenv('OS_AUTH_URL'), + strategy=force_strategy or auth_strategy or + os.getenv('OS_AUTH_STRATEGY', 'noauth'), + region=region or os.getenv('OS_REGION_NAME'), + ) + + if creds['strategy'] == 'keystone' and not creds['auth_url']: + msg = ("--auth_url option or OS_AUTH_URL environment variable " + "required when keystone authentication strategy is enabled\n") + raise exception.ClientConfigurationError(msg) + + use_ssl = (creds['auth_url'] is not None and + creds['auth_url'].find('https') != -1) + + client = (ProgressClient if not is_silent_upload else Client) + + return client(host=host, + port=port, + use_ssl=use_ssl, + auth_tok=auth_token or + os.getenv('OS_TOKEN'), + creds=creds, + insecure=insecure) diff --git a/glance/common/client.py b/glance/common/client.py index b9ab076c8d..d5c73b77ea 100644 --- a/glance/common/client.py +++ b/glance/common/client.py @@ -211,7 +211,8 @@ class BaseClient(object): def __init__(self, host, port=None, use_ssl=False, auth_tok=None, creds=None, doc_root=None, key_file=None, - cert_file=None, ca_file=None, insecure=False): + cert_file=None, ca_file=None, insecure=False, + configure_via_auth=True): """ Creates a new client to some service. @@ -247,6 +248,7 @@ class BaseClient(object): self.auth_tok = auth_tok self.creds = creds or {} self.connection = None + self.configure_via_auth = configure_via_auth # doc_root can be a nullstring, which is valid, and why we # cannot simply do doc_root or self.DEFAULT_DOC_ROOT below. self.doc_root = (doc_root if doc_root is not None @@ -365,7 +367,7 @@ class BaseClient(object): self.auth_tok = auth_plugin.auth_token management_url = auth_plugin.management_url - if management_url: + if management_url and self.configure_via_auth: self.configure_from_url(management_url) @handle_unauthorized @@ -385,7 +387,6 @@ class BaseClient(object): self._authenticate() url = self._construct_url(action, params) - return self._do_request(method=method, url=url, body=body, headers=headers) diff --git a/glance/image_cache/prefetcher.py b/glance/image_cache/prefetcher.py index 9e918d210e..258a275f06 100644 --- a/glance/image_cache/prefetcher.py +++ b/glance/image_cache/prefetcher.py @@ -26,6 +26,7 @@ import eventlet from glance.common import exception from glance.image_cache import ImageCache from glance import registry +from glance.registry import context import glance.store import glance.store.filesystem import glance.store.http @@ -45,10 +46,11 @@ class Prefetcher(object): glance.store.create_stores(conf) self.cache = ImageCache(conf) registry.configure_registry_client(conf) + registry.configure_registry_admin_creds(conf) def fetch_image_into_cache(self, image_id): - ctx = registry.get_client_context(self.conf, - is_admin=True, show_deleted=True) + ctx = context.RequestContext(is_admin=True, show_deleted=True) + try: image_meta = registry.get_image_metadata(ctx, image_id) if image_meta['status'] != 'active': diff --git a/glance/image_cache/queue_image.py b/glance/image_cache/queue_image.py index 2160351171..0101355d59 100644 --- a/glance/image_cache/queue_image.py +++ b/glance/image_cache/queue_image.py @@ -26,6 +26,7 @@ import eventlet from glance.common import exception from glance.image_cache import ImageCache from glance import registry +from glance.registry import context logger = logging.getLogger(__name__) @@ -37,10 +38,10 @@ class Queuer(object): self.conf = conf self.cache = ImageCache(conf) registry.configure_registry_client(conf) + registry.configure_registry_admin_creds(conf) def queue_image(self, image_id): - ctx = \ - registry.get_client_context(conf, is_admin=True, show_deleted=True) + ctx = context.RequestContext(is_admin=True, show_deleted=True) try: image_meta = registry.get_image_metadata(ctx, image_id) if image_meta['status'] != 'active': diff --git a/glance/registry/__init__.py b/glance/registry/__init__.py index 06db1db102..685d52f283 100644 --- a/glance/registry/__init__.py +++ b/glance/registry/__init__.py @@ -20,6 +20,7 @@ Registry API """ import logging +import os from glance.common import cfg from glance.common import exception @@ -27,6 +28,7 @@ from glance.registry import client logger = logging.getLogger('glance.registry') +_CLIENT_CREDS = None _CLIENT_HOST = None _CLIENT_PORT = None _CLIENT_KWARGS = {} @@ -45,7 +47,14 @@ registry_client_opts = [ cfg.StrOpt('registry_client_ca_file'), cfg.StrOpt('metadata_encryption_key'), ] -admin_token_opt = cfg.StrOpt('admin_token') +registry_client_ctx_opts = [ + cfg.StrOpt('admin_user'), + cfg.StrOpt('admin_password'), + cfg.StrOpt('admin_tenant_name'), + cfg.StrOpt('auth_url'), + cfg.StrOpt('auth_strategy', default='noauth'), + cfg.StrOpt('auth_region'), + ] def get_registry_addr(conf): @@ -84,16 +93,33 @@ def configure_registry_client(conf): } -def get_client_context(conf, **kwargs): - conf.register_opt(admin_token_opt) - from glance.common import context - return context.RequestContext(auth_tok=conf.admin_token, **kwargs) +def configure_registry_admin_creds(conf): + global _CLIENT_CREDS + conf.register_opts(registry_client_ctx_opts) + + if conf.auth_url or os.getenv('OS_AUTH_URL'): + strategy = 'keystone' + else: + strategy = conf.auth_strategy + + _CLIENT_CREDS = { + 'user': conf.admin_user, + 'password': conf.admin_password, + 'username': conf.admin_user, + 'tenant': conf.admin_tenant_name, + 'auth_url': conf.auth_url, + 'strategy': strategy, + 'region': conf.auth_region, + } def get_registry_client(cxt): - global _CLIENT_KWARGS, _CLIENT_HOST, _CLIENT_PORT, _METADATA_ENCRYPTION_KEY + global _CLIENT_CREDS, _CLIENT_KWARGS, _CLIENT_HOST, _CLIENT_PORT + global _METADATA_ENCRYPTION_KEY kwargs = _CLIENT_KWARGS.copy() kwargs['auth_tok'] = cxt.auth_tok + if _CLIENT_CREDS: + kwargs['creds'] = _CLIENT_CREDS return client.RegistryClient(_CLIENT_HOST, _CLIENT_PORT, _METADATA_ENCRYPTION_KEY, **kwargs) diff --git a/glance/registry/client.py b/glance/registry/client.py index 9828e0caa9..8cf54a82a6 100644 --- a/glance/registry/client.py +++ b/glance/registry/client.py @@ -40,7 +40,11 @@ class RegistryClient(BaseClient): :param metadata_encryption_key: Key used to encrypt 'location' metadata """ self.metadata_encryption_key = metadata_encryption_key - BaseClient.__init__(self, host, port, **kwargs) + # NOTE (dprince): by default base client overwrites host and port + # settings when using keystone. configure_via_auth=False disables + # this behaviour to ensure we still send requests to the Registry API + BaseClient.__init__(self, host, port, configure_via_auth=False, + **kwargs) def decrypt_metadata(self, image_metadata): if (self.metadata_encryption_key is not None