]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Switch to Oslo's config generator
authorDirk Mueller <dirk@dmllr.de>
Thu, 12 Dec 2013 13:22:49 +0000 (14:22 +0100)
committerDirk Mueller <dirk@dmllr.de>
Thu, 2 Jan 2014 14:35:16 +0000 (15:35 +0100)
This fixes the sample configuration to contain proper
config groups alongway.

Regenerate sample config with oslo's config generator.

DocImpact: Removes the deprecated memcached_server
option from DEFAULT (now in keystone_authtoken group)

Closes-Bug: #1206650
Closes-Bug: #1260322

Change-Id: I170715bfe6ec7dad9f7317e7bb56cbb68034c4ec

cinder/common/config.py
cinder/openstack/common/config/generator.py [new file with mode: 0755]
etc/cinder/cinder.conf.sample
openstack-common.conf
tools/conf/extract_opts.py [deleted file]
tools/conf/generate_sample.sh
tools/conf/oslo.config.generator.rc [new file with mode: 0644]

index d3ce0cb35f8b56934092a1b146d294dc692efc7b..4e9c6207df4fcb72285eb7972938c0005975b557 100644 (file)
@@ -167,9 +167,6 @@ global_opts = [
                     'If this is not set then we use the value from the '
                     'storage_availability_zone option as the default '
                     'availability_zone for new volumes.'),
-    cfg.ListOpt('memcached_servers',
-                default=None,
-                help='Memcached servers or None for in process cache.'),
     cfg.StrOpt('default_volume_type',
                default=None,
                help='default volume type to use'),
diff --git a/cinder/openstack/common/config/generator.py b/cinder/openstack/common/config/generator.py
new file mode 100755 (executable)
index 0000000..f72baab
--- /dev/null
@@ -0,0 +1,268 @@
+# Copyright 2012 SINA Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+#
+
+"""Extracts OpenStack config option info from module(s)."""
+
+from __future__ import print_function
+
+import imp
+import os
+import re
+import socket
+import sys
+import textwrap
+
+from oslo.config import cfg
+import six
+
+from cinder.openstack.common import gettextutils
+from cinder.openstack.common import importutils
+
+gettextutils.install('cinder')
+
+STROPT = "StrOpt"
+BOOLOPT = "BoolOpt"
+INTOPT = "IntOpt"
+FLOATOPT = "FloatOpt"
+LISTOPT = "ListOpt"
+MULTISTROPT = "MultiStrOpt"
+
+OPT_TYPES = {
+    STROPT: 'string value',
+    BOOLOPT: 'boolean value',
+    INTOPT: 'integer value',
+    FLOATOPT: 'floating point value',
+    LISTOPT: 'list value',
+    MULTISTROPT: 'multi valued',
+}
+
+OPTION_REGEX = re.compile(r"(%s)" % "|".join([STROPT, BOOLOPT, INTOPT,
+                                              FLOATOPT, LISTOPT,
+                                              MULTISTROPT]))
+
+PY_EXT = ".py"
+BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
+                                       "../../../../"))
+WORDWRAP_WIDTH = 60
+
+
+def generate(srcfiles):
+    mods_by_pkg = dict()
+    for filepath in srcfiles:
+        pkg_name = filepath.split(os.sep)[1]
+        mod_str = '.'.join(['.'.join(filepath.split(os.sep)[:-1]),
+                            os.path.basename(filepath).split('.')[0]])
+        mods_by_pkg.setdefault(pkg_name, list()).append(mod_str)
+    # NOTE(lzyeval): place top level modules before packages
+    pkg_names = filter(lambda x: x.endswith(PY_EXT), mods_by_pkg.keys())
+    pkg_names.sort()
+    ext_names = filter(lambda x: x not in pkg_names, mods_by_pkg.keys())
+    ext_names.sort()
+    pkg_names.extend(ext_names)
+
+    # opts_by_group is a mapping of group name to an options list
+    # The options list is a list of (module, options) tuples
+    opts_by_group = {'DEFAULT': []}
+
+    extra_modules = os.getenv("OSLO_CONFIG_GENERATOR_EXTRA_MODULES", "")
+    if extra_modules:
+        for module_name in extra_modules.split(','):
+            module_name = module_name.strip()
+            module = _import_module(module_name)
+            if module:
+                for group, opts in _list_opts(module):
+                    opts_by_group.setdefault(group, []).append((module_name,
+                                                                opts))
+
+    for pkg_name in pkg_names:
+        mods = mods_by_pkg.get(pkg_name)
+        mods.sort()
+        for mod_str in mods:
+            if mod_str.endswith('.__init__'):
+                mod_str = mod_str[:mod_str.rfind(".")]
+
+            mod_obj = _import_module(mod_str)
+            if not mod_obj:
+                raise RuntimeError("Unable to import module %s" % mod_str)
+
+            for group, opts in _list_opts(mod_obj):
+                opts_by_group.setdefault(group, []).append((mod_str, opts))
+
+    print_group_opts('DEFAULT', opts_by_group.pop('DEFAULT', []))
+    for group, opts in opts_by_group.items():
+        print_group_opts(group, opts)
+
+
+def _import_module(mod_str):
+    try:
+        if mod_str.startswith('bin.'):
+            imp.load_source(mod_str[4:], os.path.join('bin', mod_str[4:]))
+            return sys.modules[mod_str[4:]]
+        else:
+            return importutils.import_module(mod_str)
+    except Exception as e:
+        sys.stderr.write("Error importing module %s: %s\n" % (mod_str, str(e)))
+        return None
+
+
+def _is_in_group(opt, group):
+    "Check if opt is in group."
+    for key, value in group._opts.items():
+        if value['opt'] == opt:
+            return True
+    return False
+
+
+def _guess_groups(opt, mod_obj):
+    # is it in the DEFAULT group?
+    if _is_in_group(opt, cfg.CONF):
+        return 'DEFAULT'
+
+    # what other groups is it in?
+    for key, value in cfg.CONF.items():
+        if isinstance(value, cfg.CONF.GroupAttr):
+            if _is_in_group(opt, value._group):
+                return value._group.name
+
+    raise RuntimeError(
+        "Unable to find group for option %s, "
+        "maybe it's defined twice in the same group?"
+        % opt.name
+    )
+
+
+def _list_opts(obj):
+    def is_opt(o):
+        return (isinstance(o, cfg.Opt) and
+                not isinstance(o, cfg.SubCommandOpt))
+
+    opts = list()
+    for attr_str in dir(obj):
+        attr_obj = getattr(obj, attr_str)
+        if is_opt(attr_obj):
+            opts.append(attr_obj)
+        elif (isinstance(attr_obj, list) and
+              all(map(lambda x: is_opt(x), attr_obj))):
+            opts.extend(attr_obj)
+
+    ret = {}
+    for opt in opts:
+        ret.setdefault(_guess_groups(opt, obj), []).append(opt)
+    return ret.items()
+
+
+def print_group_opts(group, opts_by_module):
+    print("[%s]" % group)
+    print('')
+    for mod, opts in opts_by_module:
+        print('#')
+        print('# Options defined in %s' % mod)
+        print('#')
+        print('')
+        for opt in opts:
+            _print_opt(opt)
+        print('')
+
+
+def _get_my_ip():
+    try:
+        csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+        csock.connect(('8.8.8.8', 80))
+        (addr, port) = csock.getsockname()
+        csock.close()
+        return addr
+    except socket.error:
+        return None
+
+
+def _sanitize_default(name, value):
+    """Set up a reasonably sensible default for pybasedir, my_ip and host."""
+    if value.startswith(sys.prefix):
+        # NOTE(jd) Don't use os.path.join, because it is likely to think the
+        # second part is an absolute pathname and therefore drop the first
+        # part.
+        value = os.path.normpath("/usr/" + value[len(sys.prefix):])
+    elif value.startswith(BASEDIR):
+        return value.replace(BASEDIR, '/usr/lib/python/site-packages')
+    elif BASEDIR in value:
+        return value.replace(BASEDIR, '')
+    elif value == _get_my_ip():
+        return '10.0.0.1'
+    elif value == socket.gethostname() and 'host' in name:
+        return 'cinder'
+    elif value.strip() != value:
+        return '"%s"' % value
+    return value
+
+
+def _print_opt(opt):
+    opt_name, opt_default, opt_help = opt.dest, opt.default, opt.help
+    if not opt_help:
+        sys.stderr.write('WARNING: "%s" is missing help string.\n' % opt_name)
+        opt_help = ""
+    opt_type = None
+    try:
+        opt_type = OPTION_REGEX.search(str(type(opt))).group(0)
+    except (ValueError, AttributeError) as err:
+        sys.stderr.write("%s\n" % str(err))
+        sys.exit(1)
+    opt_help += ' (' + OPT_TYPES[opt_type] + ')'
+    print('#', "\n# ".join(textwrap.wrap(opt_help, WORDWRAP_WIDTH)))
+    if opt.deprecated_opts:
+        for deprecated_opt in opt.deprecated_opts:
+            if deprecated_opt.name:
+                deprecated_group = (deprecated_opt.group if
+                                    deprecated_opt.group else "DEFAULT")
+                print('# Deprecated group/name - [%s]/%s' %
+                      (deprecated_group,
+                       deprecated_opt.name))
+    try:
+        if opt_default is None:
+            print('#%s=<None>' % opt_name)
+        elif opt_type == STROPT:
+            assert(isinstance(opt_default, six.string_types))
+            print('#%s=%s' % (opt_name, _sanitize_default(opt_name,
+                                                          opt_default)))
+        elif opt_type == BOOLOPT:
+            assert(isinstance(opt_default, bool))
+            print('#%s=%s' % (opt_name, str(opt_default).lower()))
+        elif opt_type == INTOPT:
+            assert(isinstance(opt_default, int) and
+                   not isinstance(opt_default, bool))
+            print('#%s=%s' % (opt_name, opt_default))
+        elif opt_type == FLOATOPT:
+            assert(isinstance(opt_default, float))
+            print('#%s=%s' % (opt_name, opt_default))
+        elif opt_type == LISTOPT:
+            assert(isinstance(opt_default, list))
+            print('#%s=%s' % (opt_name, ','.join(opt_default)))
+        elif opt_type == MULTISTROPT:
+            assert(isinstance(opt_default, list))
+            if not opt_default:
+                opt_default = ['']
+            for default in opt_default:
+                print('#%s=%s' % (opt_name, default))
+        print('')
+    except Exception:
+        sys.stderr.write('Error in option "%s"\n' % opt_name)
+        sys.exit(1)
+
+
+def main():
+    generate(sys.argv[1:])
+
+if __name__ == '__main__':
+    main()
index 2b206cee377a5da5d401b4e7ad8e00abbadf2c4e..415640ba5d65976f177ca0aeb67339061a00f60a 100644 (file)
@@ -1,7 +1,3 @@
-####################
-# cinder.conf sample #
-####################
-
 [DEFAULT]
 
 #
 
 # Base URL that will be presented to users in links to the
 # OpenStack Volume API (string value)
+# Deprecated group/name - [DEFAULT]/osapi_compute_link_prefix
 #osapi_volume_base_URL=<None>
 
 
 #
 
 # Driver to use for backups. (string value)
+# Deprecated group/name - [DEFAULT]/backup_service
 #backup_driver=cinder.backup.drivers.swift
 
 
 # availability_zone for new volumes. (string value)
 #default_availability_zone=<None>
 
-# Memcached servers or None for in process cache. (list value)
-#memcached_servers=<None>
-
 # default volume type to use (string value)
 #default_volume_type=<None>
 
 #image_conversion_dir=$state_path/conversion
 
 
-#
-# Options defined in cinder.keymgr
-#
-
-# The full class name of the key manager API class (string
-# value)
-#api_class=cinder.keymgr.conf_key_mgr.ConfKeyManager
-
-
-#
-# Options defined in cinder.keymgr.conf_key_mgr
-#
-
-# Fixed key returned by key manager, specified in hex (string
-# value)
-#fixed_key=<None>
-
-
-#
-# Options defined in cinder.openstack.common.db.api
-#
-
-# The backend to use for db (string value)
-#backend=sqlalchemy
-
-# Enable the experimental use of thread pooling for all DB API
-# calls (boolean value)
-#use_tpool=false
-
-
 #
 # Options defined in cinder.openstack.common.db.sqlalchemy.session
 #
 
-# The SQLAlchemy connection string used to connect to the
-# database (string value)
-#connection=sqlite:////cinder/openstack/common/db/$sqlite_db
-
-# timeout before idle sql connections are reaped (integer
-# value)
-#idle_timeout=3600
-
-# Minimum number of SQL connections to keep open in a pool
-# (integer value)
-#min_pool_size=1
-
-# Maximum number of SQL connections to keep open in a pool
-# (integer value)
-#max_pool_size=5
-
-# maximum db connection retries during startup. (setting -1
-# implies an infinite retry count) (integer value)
-#max_retries=10
-
-# interval between retries of opening a sql connection
-# (integer value)
-#retry_interval=10
-
-# If set, use this value for max_overflow with sqlalchemy
-# (integer value)
-#max_overflow=<None>
-
-# Verbosity of SQL debugging information. 0=None,
-# 100=Everything (integer value)
-#connection_debug=0
-
-# Add python stack traces to SQL as comment strings (boolean
-# value)
-#connection_trace=false
-
 # the filename to use with sqlite (string value)
 #sqlite_db=cinder.sqlite
 
 # configuration to any other existing logging options. Please
 # see the Python logging module documentation for details on
 # logging configuration files. (string value)
+# Deprecated group/name - [DEFAULT]/log_config
 #log_config_append=<None>
 
 # DEPRECATED. A logging.Formatter log message format string
 
 # (Optional) Name of log file to output to. If no default is
 # set, logging will go to stdout. (string value)
+# Deprecated group/name - [DEFAULT]/logfile
 #log_file=<None>
 
 # (Optional) The base directory used for relative --log-file
 # paths (string value)
+# Deprecated group/name - [DEFAULT]/logdir
 #log_dir=<None>
 
 # Use syslog for logging. (boolean value)
 #notification_topics=notifications
 
 
-#
-# Options defined in cinder.openstack.common.notifier.rpc_notifier2
-#
-
-# AMQP topic(s) used for OpenStack notifications (list value)
-#topics=notifications
-
-
 #
 # Options defined in cinder.openstack.common.periodic_task
 #
 #amqp_rpc_single_reply_queue=false
 
 # Use durable queues in amqp. (boolean value)
+# Deprecated group/name - [DEFAULT]/rabbit_durable_queues
 #amqp_durable_queues=false
 
 # Auto-delete queues in amqp. (boolean value)
 #matchmaker_heartbeat_ttl=600
 
 
-#
-# Options defined in cinder.openstack.common.rpc.matchmaker_redis
-#
-
-# Host to locate redis (string value)
-#host=127.0.0.1
-
-# Use this port to connect to redis host. (integer value)
-#port=6379
-
-# Password for Redis server. (optional) (string value)
-#password=<None>
-
-
-#
-# Options defined in cinder.openstack.common.rpc.matchmaker_ring
-#
-
-# Matchmaker ring file (JSON) (string value)
-#ringfile=/etc/oslo/matchmaker_ring.json
-
-
 #
 # Options defined in cinder.scheduler.driver
 #
 
 # The maximum number of times to rescan targets to find volume
 # (integer value)
+# Deprecated group/name - [DEFAULT]/num_iscsi_scan_tries
 #num_volume_device_scan_tries=3
 
 # The backend name for a given driver implementation (string
 #volume_service_inithost_offload=false
 
 
+[database]
+
+#
+# Options defined in cinder.openstack.common.db.api
+#
+
+# The backend to use for db (string value)
+# Deprecated group/name - [DEFAULT]/db_backend
+#backend=sqlalchemy
+
+# Enable the experimental use of thread pooling for all DB API
+# calls (boolean value)
+# Deprecated group/name - [DEFAULT]/dbapi_use_tpool
+#use_tpool=false
+
+
+#
+# Options defined in cinder.openstack.common.db.sqlalchemy.session
+#
+
+# The SQLAlchemy connection string used to connect to the
+# database (string value)
+# Deprecated group/name - [DEFAULT]/sql_connection
+#connection=sqlite:///$state_path/$sqlite_db
+
+# timeout before idle sql connections are reaped (integer
+# value)
+# Deprecated group/name - [DEFAULT]/sql_idle_timeout
+#idle_timeout=3600
+
+# Minimum number of SQL connections to keep open in a pool
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_min_pool_size
+#min_pool_size=1
+
+# Maximum number of SQL connections to keep open in a pool
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_max_pool_size
+#max_pool_size=5
+
+# maximum db connection retries during startup. (setting -1
+# implies an infinite retry count) (integer value)
+# Deprecated group/name - [DEFAULT]/sql_max_retries
+#max_retries=10
+
+# interval between retries of opening a sql connection
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_retry_interval
+#retry_interval=10
+
+# If set, use this value for max_overflow with sqlalchemy
+# (integer value)
+# Deprecated group/name - [DEFAULT]/sql_max_overflow
+#max_overflow=<None>
+
+# Verbosity of SQL debugging information. 0=None,
+# 100=Everything (integer value)
+# Deprecated group/name - [DEFAULT]/sql_connection_debug
+#connection_debug=0
+
+# Add python stack traces to SQL as comment strings (boolean
+# value)
+# Deprecated group/name - [DEFAULT]/sql_connection_trace
+#connection_trace=false
+
+
+[keymgr]
+
+#
+# Options defined in cinder.keymgr
+#
+
+# The full class name of the key manager API class (string
+# value)
+#api_class=cinder.keymgr.conf_key_mgr.ConfKeyManager
+
+
+#
+# Options defined in cinder.keymgr.conf_key_mgr
+#
+
+# Fixed key returned by key manager, specified in hex (string
+# value)
+#fixed_key=<None>
+
+
+[rpc_notifier2]
+
+#
+# Options defined in cinder.openstack.common.notifier.rpc_notifier2
+#
+
+# AMQP topic(s) used for OpenStack notifications (list value)
+#topics=notifications
+
+
+[matchmaker_redis]
+
+#
+# Options defined in cinder.openstack.common.rpc.matchmaker_redis
+#
+
+# Host to locate redis (string value)
+#host=127.0.0.1
+
+# Use this port to connect to redis host. (integer value)
+#port=6379
+
+# Password for Redis server. (optional) (string value)
+#password=<None>
+
+
 [keystone_authtoken]
 
 #
-# Options defined in keystoneclient's authtoken middleware
+# Options defined in keystoneclient.middleware.auth_token
 #
 
-# Host providing the admin Identity API endpoint
-auth_host = 127.0.0.1
+# Prefix to prepend at the beginning of the path (string
+# value)
+#auth_admin_prefix=
+
+# Host providing the admin Identity API endpoint (string
+# value)
+#auth_host=127.0.0.1
+
+# Port of the admin Identity API endpoint (integer value)
+#auth_port=35357
+
+# Protocol of the admin Identity API endpoint(http or https)
+# (string value)
+#auth_protocol=https
+
+# Complete public Identity API endpoint (string value)
+#auth_uri=<None>
+
+# API version of the admin Identity API endpoint (string
+# value)
+#auth_version=<None>
+
+# Do not handle authorization requests within the middleware,
+# but delegate the authorization decision to downstream WSGI
+# components (boolean value)
+#delay_auth_decision=false
+
+# Request timeout value for communicating with Identity API
+# server. (boolean value)
+#http_connect_timeout=<None>
+
+# How many times are we trying to reconnect when communicating
+# with Identity API Server. (integer value)
+#http_request_max_retries=3
 
-# Port of the admin Identity API endpoint
-auth_port = 35357
+# Allows to pass in the name of a fake http_handler callback
+# function used instead of httplib.HTTPConnection or
+# httplib.HTTPSConnection. Useful for unit testing where
+# network is not available. (string value)
+#http_handler=<None>
 
-# Protocol of the admin Identity API endpoint
-auth_protocol = http
+# Single shared secret with the Keystone configuration used
+# for bootstrapping a Keystone installation, or otherwise
+# bypassing the normal authentication process. (string value)
+#admin_token=<None>
+
+# Keystone account username (string value)
+#admin_user=<None>
+
+# Keystone account password (string value)
+#admin_password=<None>
 
 # Keystone service account tenant name to validate user tokens
-admin_tenant_name = %SERVICE_TENANT_NAME%
+# (string value)
+#admin_tenant_name=admin
+
+# Env key for the swift cache (string value)
+#cache=<None>
+
+# Required if Keystone server requires client certificate
+# (string value)
+#certfile=<None>
+
+# Required if Keystone server requires client certificate
+# (string value)
+#keyfile=<None>
+
+# A PEM encoded Certificate Authority to use when verifying
+# HTTPs connections. Defaults to system CAs. (string value)
+#cafile=<None>
+
+# Verify HTTPS connections. (boolean value)
+#insecure=false
+
+# Directory used to cache files related to PKI tokens (string
+# value)
+#signing_dir=<None>
+
+# If defined, the memcache server(s) to use for caching (list
+# value)
+# Deprecated group/name - [DEFAULT]/memcache_servers
+#memcached_servers=<None>
 
-# Keystone account username
-admin_user = %SERVICE_USER%
+# In order to prevent excessive requests and validations, the
+# middleware uses an in-memory cache for the tokens the
+# Keystone API returns. This is only valid if memcache_servers
+# is defined. Set to -1 to disable caching completely.
+# (integer value)
+#token_cache_time=300
+
+# Value only used for unit testing (integer value)
+#revocation_cache_time=1
+
+# (optional) if defined, indicate whether token data should be
+# authenticated or authenticated and encrypted. Acceptable
+# values are MAC or ENCRYPT.  If MAC, token data is
+# authenticated (with HMAC) in the cache. If ENCRYPT, token
+# data is encrypted and authenticated in the cache. If the
+# value is not one of these options or empty, auth_token will
+# raise an exception on initialization. (string value)
+#memcache_security_strategy=<None>
+
+# (optional, mandatory if memcache_security_strategy is
+# defined) this string is used for key derivation. (string
+# value)
+#memcache_secret_key=<None>
+
+
+[matchmaker_ring]
+
+#
+# Options defined in cinder.openstack.common.rpc.matchmaker_ring
+#
+
+# Matchmaker ring file (JSON) (string value)
+# Deprecated group/name - [DEFAULT]/matchmaker_ringfile
+#ringfile=/etc/oslo/matchmaker_ring.json
 
-# Keystone account password
-admin_password = %SERVICE_PASSWORD%
 
-# Directory used to cache files related to PKI tokens
-# signing_dir is configurable, but the default behavior of the authtoken
-# middleware should be sufficient.  It will create a temporary directory
-# in the home directory for the user the cinder process is running as.
-#signing_dir = /var/lib/cinder/keystone-signing
index da7ed46c6844d8dfc75cb11aa2a8be070c22f67e..555cd1efecca5eef484576b6554f8170ee32e2de 100644 (file)
@@ -2,6 +2,7 @@
 
 # The list of modules to copy from openstack-common
 module=context
+module=config.generator
 module=db
 module=db.sqlalchemy
 module=excutils
diff --git a/tools/conf/extract_opts.py b/tools/conf/extract_opts.py
deleted file mode 100644 (file)
index 5ff5776..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-# Copyright 2012 SINA Corporation
-# All Rights Reserved.
-# Author: Zhongyue Luo <lzyeval@gmail.com>
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-"""Extracts OpenStack config option info from module(s)."""
-
-from __future__ import print_function
-
-import __builtin__
-setattr(__builtin__, '_', lambda x: x)
-import os
-import re
-import socket
-import sys
-import textwrap
-
-from oslo.config import cfg
-
-from cinder.openstack.common import importutils
-
-STROPT = "StrOpt"
-BOOLOPT = "BoolOpt"
-INTOPT = "IntOpt"
-FLOATOPT = "FloatOpt"
-LISTOPT = "ListOpt"
-MULTISTROPT = "MultiStrOpt"
-
-OPTION_REGEX = re.compile(r"(%s)" % "|".join([STROPT, BOOLOPT, INTOPT,
-                                              FLOATOPT, LISTOPT,
-                                              MULTISTROPT]))
-OPTION_HELP_INDENT = "####"
-
-PY_EXT = ".py"
-BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
-WORDWRAP_WIDTH = 60
-
-
-def main(srcfiles):
-    print('\n'.join(['#' * 20, '# cinder.conf sample #', '#' * 20,
-                     '', '[DEFAULT]', '']))
-    _list_opts(cfg.ConfigOpts,
-               cfg.__name__ + ':' + cfg.ConfigOpts.__name__)
-    mods_by_pkg = dict()
-    for filepath in srcfiles:
-        pkg_name = filepath.split(os.sep)[1]
-        mod_str = '.'.join(['.'.join(filepath.split(os.sep)[:-1]),
-                            os.path.basename(filepath).split('.')[0]])
-        mods_by_pkg.setdefault(pkg_name, list()).append(mod_str)
-    # NOTE(lzyeval): place top level modules before packages
-    pkg_names = filter(lambda x: x.endswith(PY_EXT), mods_by_pkg.keys())
-    pkg_names.sort()
-    ext_names = filter(lambda x: x not in pkg_names, mods_by_pkg.keys())
-    ext_names.sort()
-    pkg_names.extend(ext_names)
-    for pkg_name in pkg_names:
-        mods = mods_by_pkg.get(pkg_name)
-        mods.sort()
-        for mod_str in mods:
-            _print_module(mod_str)
-
-
-def _print_module(mod_str):
-    mod_obj = None
-    if mod_str.endswith('.__init__'):
-        mod_str = mod_str[:mod_str.rfind(".")]
-    try:
-        mod_obj = importutils.import_module(mod_str)
-    except Exception as e:
-        sys.stderr.write("Failed to collect options from module %s: %s\n" % (
-            mod_str, str(e)))
-        return
-    _list_opts(mod_obj, mod_str)
-
-
-def _list_opts(obj, name):
-    opts = list()
-    for attr_str in dir(obj):
-        attr_obj = getattr(obj, attr_str)
-        if isinstance(attr_obj, cfg.Opt):
-            opts.append(attr_obj)
-        elif (isinstance(attr_obj, list) and
-              all(map(lambda x: isinstance(x, cfg.Opt), attr_obj))):
-            opts.extend(attr_obj)
-    if not opts:
-        return
-    print('#')
-    print('# Options defined in %s' % name)
-    print('#')
-    print()
-    for opt in opts:
-        _print_opt(opt)
-    print()
-
-
-def _get_my_ip():
-    try:
-        csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-        csock.connect(('8.8.8.8', 80))
-        (addr, port) = csock.getsockname()
-        csock.close()
-        return addr
-    except socket.error:
-        return None
-
-
-MY_IP = _get_my_ip()
-HOST = socket.gethostname()
-
-
-def _sanitize_default(s):
-    """Set up a reasonably sensible default for pybasedir, my_ip and host."""
-    if s.startswith(BASEDIR):
-        return s.replace(BASEDIR, '/usr/lib/python/site-packages')
-    elif s == MY_IP:
-        return '10.0.0.1'
-    elif s == HOST:
-        return 'cinder'
-    elif s.strip() != s:
-        return '"%s"' % s
-    return s
-
-
-OPT_TYPES = {
-    'StrOpt': 'string value',
-    'BoolOpt': 'boolean value',
-    'IntOpt': 'integer value',
-    'FloatOpt': 'floating point value',
-    'ListOpt': 'list value',
-    'MultiStrOpt': 'multi valued',
-}
-
-
-def _print_opt(opt):
-    opt_name, opt_default, opt_help = opt.dest, opt.default, opt.help
-    if not opt_help:
-        sys.stderr.write('WARNING: "%s" is missing help string.\n' % opt_name)
-    opt_type = None
-    try:
-        opt_type = OPTION_REGEX.search(str(type(opt))).group(0)
-    except (ValueError, AttributeError) as err:
-        sys.stderr.write("%s\n" % str(err))
-        sys.exit(1)
-    opt_help += ' (' + OPT_TYPES[opt_type] + ')'
-    print('#', "\n# ".join(textwrap.wrap(opt_help, WORDWRAP_WIDTH)))
-    try:
-        if opt_default is None:
-            print('#%s=<None>' % opt_name)
-        elif opt_type == STROPT:
-            assert(isinstance(opt_default, basestring))
-            print('#%s=%s' % (opt_name, _sanitize_default(opt_default)))
-        elif opt_type == BOOLOPT:
-            assert(isinstance(opt_default, bool))
-            print('#%s=%s' % (opt_name, str(opt_default).lower()))
-        elif opt_type == INTOPT:
-            assert(isinstance(opt_default, int) and
-                   not isinstance(opt_default, bool))
-            print('#%s=%s' % (opt_name, opt_default))
-        elif opt_type == FLOATOPT:
-            assert(isinstance(opt_default, float))
-            print('#%s=%s' % (opt_name, opt_default))
-        elif opt_type == LISTOPT:
-            assert(isinstance(opt_default, list))
-            print('#%s=%s' % (opt_name, ','.join(opt_default)))
-        elif opt_type == MULTISTROPT:
-            assert(isinstance(opt_default, list))
-            if opt_default:
-                for default in opt_default:
-                    print('#%s=%s' % (opt_name, default))
-            else:
-                print('#%s=' % (opt_name))
-        print()
-    except Exception:
-        sys.stderr.write('Error in option "%s"\n' % opt_name)
-        sys.exit(1)
-
-
-if __name__ == '__main__':
-    if len(sys.argv) < 2:
-        print("usage: python %s [srcfile]...\n" % sys.argv[0])
-        sys.exit(0)
-    main(sys.argv[1:])
index e0f9542100be34a7d500d0b8342519f2ba74800f..92730798b74dcadc03d13474cc7a9230f6322c18 100755 (executable)
@@ -43,41 +43,14 @@ OUTPUTFILE=$OUTPUTDIR/cinder.conf.sample
 FILES=$(find cinder -type f -name "*.py" ! -path "cinder/tests/*" -exec \
     grep -l "Opt(" {} \; | sort -u)
 
-PYTHONPATH=./:${PYTHONPATH} \
-    python $(dirname "$0")/extract_opts.py ${FILES} > \
-    $OUTPUTFILE
-
-# When we use openstack.common.config.generate we won't need this any more
-sed -i 's/^#connection=sqlite.*/#connection=sqlite:\/\/\/\/cinder\/openstack\/common\/db\/$sqlite_db/' $OUTPUTFILE
-
-cat >> $OUTPUTFILE <<-EOF_CAT
-[keystone_authtoken]
-
-#
-# Options defined in keystoneclient's authtoken middleware
-#
-
-# Host providing the admin Identity API endpoint
-auth_host = 127.0.0.1
-
-# Port of the admin Identity API endpoint
-auth_port = 35357
-
-# Protocol of the admin Identity API endpoint
-auth_protocol = http
-
-# Keystone service account tenant name to validate user tokens
-admin_tenant_name = %SERVICE_TENANT_NAME%
-
-# Keystone account username
-admin_user = %SERVICE_USER%
+EXTRA_MODULES_FILE="`dirname $0`/oslo.config.generator.rc"
+if test -r "$EXTRA_MODULES_FILE"
+then
+    source "$EXTRA_MODULES_FILE"
+fi
 
-# Keystone account password
-admin_password = %SERVICE_PASSWORD%
+export EVENTLET_NO_GREENDNS=yes
 
-# Directory used to cache files related to PKI tokens
-# signing_dir is configurable, but the default behavior of the authtoken
-# middleware should be sufficient.  It will create a temporary directory
-# in the home directory for the user the cinder process is running as.
-#signing_dir = /var/lib/cinder/keystone-signing
-EOF_CAT
+PYTHONPATH=./:${PYTHONPATH} \
+    python $(dirname "$0")/../../cinder/openstack/common/config/generator.py ${FILES} > \
+    $OUTPUTFILE
diff --git a/tools/conf/oslo.config.generator.rc b/tools/conf/oslo.config.generator.rc
new file mode 100644 (file)
index 0000000..a5ee3e6
--- /dev/null
@@ -0,0 +1 @@
+export OSLO_CONFIG_GENERATOR_EXTRA_MODULES=keystoneclient.middleware.auth_token
\ No newline at end of file