Reworking configuration options
Use config tools from Oslo-incubator : * generate a consistant config file sample: etc/climate/climate.conf.sample * Add a new check in tox env 'pep8' to check out-dated config file sample. Move specifics options for admin credential in group config 'physical:host' Factorize by declaring config options in each plugins with available values and centralizing RESOURCE_TYPE value in plugin's module (one dir per plugin) Use socket.gethostname() in place of socket.getfqdn() to have predictable default value for 'host' config in climate.config, since it's ugly forced in openstack.common.config.generator#L232 Fixes: bug #1271875 Change-Id: Ie54fc98b58b49400360c4fd2ce7d8bb3b75915e2
This commit is contained in:
parent
9daf3d8c97
commit
e9d03ee1ea
|
@ -21,7 +21,7 @@ cli_opts = [
|
|||
cfg.BoolOpt('log-exchange', default=False,
|
||||
help='Log request/response exchange details: environ, '
|
||||
'headers and bodies'),
|
||||
cfg.StrOpt('host', default=socket.getfqdn(),
|
||||
cfg.StrOpt('host', default=socket.gethostname(),
|
||||
help='Name of this node. This can be an opaque identifier. '
|
||||
'It is not necessarily a hostname, FQDN, or IP address. '
|
||||
'However, the node name must be valid within '
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
# 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 argparse
|
||||
import imp
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
from oslo.config import cfg
|
||||
import six
|
||||
import stevedore.named
|
||||
|
||||
from climate.openstack.common import gettextutils
|
||||
from climate.openstack.common import importutils
|
||||
|
||||
gettextutils.install('climate')
|
||||
|
||||
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(argv):
|
||||
parser = argparse.ArgumentParser(
|
||||
description='generate sample configuration file',
|
||||
)
|
||||
parser.add_argument('-m', dest='modules', action='append')
|
||||
parser.add_argument('-l', dest='libraries', action='append')
|
||||
parser.add_argument('srcfiles', nargs='*')
|
||||
parsed_args = parser.parse_args(argv)
|
||||
|
||||
mods_by_pkg = dict()
|
||||
for filepath in parsed_args.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 = sorted(pkg for pkg in mods_by_pkg if pkg.endswith(PY_EXT))
|
||||
ext_names = sorted(pkg for pkg in mods_by_pkg if pkg not in pkg_names)
|
||||
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': []}
|
||||
|
||||
if parsed_args.modules:
|
||||
for module_name in parsed_args.modules:
|
||||
module = _import_module(module_name)
|
||||
if module:
|
||||
for group, opts in _list_opts(module):
|
||||
opts_by_group.setdefault(group, []).append((module_name,
|
||||
opts))
|
||||
|
||||
# Look for entry points defined in libraries (or applications) for
|
||||
# option discovery, and include their return values in the output.
|
||||
#
|
||||
# Each entry point should be a function returning an iterable
|
||||
# of pairs with the group name (or None for the default group)
|
||||
# and the list of Opt instances for that group.
|
||||
if parsed_args.libraries:
|
||||
loader = stevedore.named.NamedExtensionManager(
|
||||
'oslo.config.opts',
|
||||
names=list(set(parsed_args.libraries)),
|
||||
invoke_on_load=False,
|
||||
)
|
||||
for ext in loader:
|
||||
for group, opts in ext.plugin():
|
||||
opt_list = opts_by_group.setdefault(group or 'DEFAULT', [])
|
||||
opt_list.append((ext.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 in sorted(opts_by_group.keys()):
|
||||
print_group_opts(group, opts_by_group[group])
|
||||
|
||||
|
||||
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 value in group._opts.values():
|
||||
# NOTE(llu): Temporary workaround for bug #1262148, wait until
|
||||
# newly released oslo.config support '==' operator.
|
||||
if not(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 value in cfg.CONF.values():
|
||||
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 'climate'
|
||||
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()
|
|
@ -0,0 +1 @@
|
|||
RESOURCE_TYPE = u'virtual:instance'
|
|
@ -19,24 +19,27 @@ from oslo.config import cfg
|
|||
from climate import exceptions as climate_exceptions
|
||||
from climate.openstack.common import log as logging
|
||||
from climate.plugins import base
|
||||
from climate.plugins import instances as plugin
|
||||
from climate.utils.openstack import nova
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
plugin_opts = [
|
||||
cfg.StrOpt('on_end',
|
||||
default='create_image, delete',
|
||||
help='Actions which we will use in the end of the lease')
|
||||
help='Actions which we will use in the end of the lease'),
|
||||
cfg.StrOpt('on_start',
|
||||
default='on_start',
|
||||
help='Actions which we will use at the start of the lease'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(plugin_opts, 'virtual:instance')
|
||||
CONF.register_opts(plugin_opts, group=plugin.RESOURCE_TYPE)
|
||||
|
||||
|
||||
class VMPlugin(base.BasePlugin):
|
||||
"""Base plugin for VM reservation."""
|
||||
resource_type = 'virtual:instance'
|
||||
resource_type = plugin.RESOURCE_TYPE
|
||||
title = "Basic VM Plugin"
|
||||
description = ("This is basic plugin for VM management. "
|
||||
"It can start, snapshot and suspend VMs")
|
||||
|
@ -50,7 +53,7 @@ class VMPlugin(base.BasePlugin):
|
|||
|
||||
def on_end(self, resource_id):
|
||||
nova_client = nova.ClimateNovaClient()
|
||||
actions = self._split_actions(CONF['virtual:instance'].on_end)
|
||||
actions = self._split_actions(CONF[plugin.RESOURCE_TYPE].on_end)
|
||||
|
||||
# actions will be processed in following order:
|
||||
# - create image from VM
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
from oslo.config import cfg
|
||||
|
||||
RESOURCE_TYPE = u'physical:host'
|
||||
|
||||
admin_opts = [
|
||||
cfg.StrOpt('climate_username',
|
||||
|
@ -28,4 +29,4 @@ admin_opts = [
|
|||
help='Tenant of the user for write operations'),
|
||||
]
|
||||
|
||||
cfg.CONF.register_opts(admin_opts)
|
||||
cfg.CONF.register_opts(admin_opts, group=RESOURCE_TYPE)
|
||||
|
|
|
@ -27,30 +27,45 @@ from climate.db import utils as db_utils
|
|||
from climate.manager import exceptions as manager_ex
|
||||
from climate.openstack.common import uuidutils
|
||||
from climate.plugins import base
|
||||
from climate.plugins import oshosts as plugin
|
||||
from climate.plugins.oshosts import nova_inventory
|
||||
from climate.plugins.oshosts import reservation_pool as rp
|
||||
|
||||
plugin_opts = [
|
||||
cfg.StrOpt('on_end',
|
||||
default='on_end',
|
||||
help='Actions which we will use in the end of the lease'),
|
||||
cfg.StrOpt('on_start',
|
||||
default='on_start',
|
||||
help='Actions which we will use at the start of the lease'),
|
||||
]
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(plugin_opts, group=plugin.RESOURCE_TYPE)
|
||||
|
||||
|
||||
class PhysicalHostPlugin(base.BasePlugin):
|
||||
"""Plugin for physical host resource."""
|
||||
resource_type = 'physical:host'
|
||||
resource_type = plugin.RESOURCE_TYPE
|
||||
title = 'Physical Host Plugin'
|
||||
description = 'This plugin starts and shutdowns the hosts.'
|
||||
freepool_name = cfg.CONF[resource_type].aggregate_freepool_name
|
||||
freepool_name = CONF[resource_type].aggregate_freepool_name
|
||||
pool = None
|
||||
inventory = None
|
||||
|
||||
def __init__(self):
|
||||
#TODO(sbauza): use catalog to find the url
|
||||
auth_url = "%s://%s:%s/v2.0" % (cfg.CONF.os_auth_protocol,
|
||||
cfg.CONF.os_auth_host,
|
||||
cfg.CONF.os_auth_port)
|
||||
auth_url = "%s://%s:%s/v2.0" % (CONF.os_auth_protocol,
|
||||
CONF.os_auth_host,
|
||||
CONF.os_auth_port)
|
||||
config = CONF[plugin.RESOURCE_TYPE]
|
||||
#TODO(scroiset): use client wrapped by climate and use trust
|
||||
self.nova = client.Client('2',
|
||||
username=cfg.CONF.climate_username,
|
||||
api_key=cfg.CONF.climate_password,
|
||||
username=config.climate_username,
|
||||
api_key=config.climate_password,
|
||||
auth_url=auth_url,
|
||||
project_id=cfg.CONF.climate_tenant_name)
|
||||
project_id=config.climate_tenant_name)
|
||||
|
||||
def create_reservation(self, values):
|
||||
"""Create reservation."""
|
||||
|
|
|
@ -19,6 +19,7 @@ from oslo.config import cfg
|
|||
|
||||
from climate import context
|
||||
from climate.manager import exceptions as manager_exceptions
|
||||
from climate.plugins import oshosts as plugin
|
||||
|
||||
|
||||
class NovaInventory(object):
|
||||
|
@ -29,11 +30,12 @@ class NovaInventory(object):
|
|||
auth_url = "%s://%s:%s/v2.0" % (cfg.CONF.os_auth_protocol,
|
||||
cfg.CONF.os_auth_host,
|
||||
cfg.CONF.os_auth_port)
|
||||
config = cfg.CONF[plugin.RESOURCE_TYPE]
|
||||
self.nova = client.Client('2',
|
||||
username=cfg.CONF.climate_username,
|
||||
api_key=cfg.CONF.climate_password,
|
||||
username=config.climate_username,
|
||||
api_key=config.climate_password,
|
||||
auth_url=auth_url,
|
||||
project_id=cfg.CONF.climate_tenant_name)
|
||||
project_id=config.climate_tenant_name)
|
||||
|
||||
def get_host_details(self, host):
|
||||
"""Get Nova capabilities of a single host
|
||||
|
|
|
@ -23,11 +23,12 @@ from oslo.config import cfg
|
|||
from climate import context
|
||||
from climate.manager import exceptions as manager_exceptions
|
||||
from climate.openstack.common import log as logging
|
||||
from climate.plugins import oshosts as plugin
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
opts = [
|
||||
OPTS = [
|
||||
cfg.StrOpt('aggregate_freepool_name',
|
||||
default='freepool',
|
||||
help='Name of the special aggregate where all hosts '
|
||||
|
@ -43,23 +44,25 @@ opts = [
|
|||
help='Prefix for Availability Zones created by Climate'),
|
||||
]
|
||||
|
||||
cfg.CONF.register_opts(opts, 'physical:host')
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(OPTS, group=plugin.RESOURCE_TYPE)
|
||||
|
||||
|
||||
class ReservationPool(object):
|
||||
def __init__(self):
|
||||
self.ctx = context.current()
|
||||
self.freepool_name = cfg.CONF['physical:host'].aggregate_freepool_name
|
||||
|
||||
self.config = CONF[plugin.RESOURCE_TYPE]
|
||||
self.freepool_name = self.config.aggregate_freepool_name
|
||||
#TODO(scroiset): use catalog to find the url
|
||||
auth_url = "%s://%s:%s/v2.0" % (cfg.CONF.os_auth_protocol,
|
||||
cfg.CONF.os_auth_host,
|
||||
cfg.CONF.os_auth_port)
|
||||
auth_url = "%s://%s:%s/v2.0" % (CONF.os_auth_protocol,
|
||||
CONF.os_auth_host,
|
||||
CONF.os_auth_port)
|
||||
#TODO(scroiset): use client wrapped by climate and use trust
|
||||
self.nova = client.Client('2',
|
||||
username=cfg.CONF.climate_username,
|
||||
api_key=cfg.CONF.climate_password,
|
||||
username=self.config.climate_username,
|
||||
api_key=self.config.climate_password,
|
||||
auth_url=auth_url,
|
||||
project_id=cfg.CONF.climate_tenant_name)
|
||||
project_id=self.config.climate_tenant_name)
|
||||
|
||||
def get_aggregate_from_name_or_id(self, aggregate_obj):
|
||||
"""Return an aggregate by name or an id."""
|
||||
|
@ -105,7 +108,7 @@ class ReservationPool(object):
|
|||
name = name or self._generate_aggregate_name()
|
||||
|
||||
if az:
|
||||
az_name = "%s%s" % (cfg.CONF['physical:host'].climate_az_prefix,
|
||||
az_name = "%s%s" % (self.config.climate_az_prefix,
|
||||
name)
|
||||
LOG.debug('Creating pool aggregate: %s'
|
||||
'with Availability Zone %s' % (name, az_name))
|
||||
|
@ -115,7 +118,7 @@ class ReservationPool(object):
|
|||
'without Availability Zone' % name)
|
||||
agg = self.nova.aggregates.create(name, None)
|
||||
|
||||
meta = {cfg.CONF['physical:host'].climate_owner: self.ctx.tenant_id}
|
||||
meta = {self.config.climate_owner: self.ctx.tenant_id}
|
||||
self.nova.aggregates.set_metadata(agg, meta)
|
||||
|
||||
return agg
|
||||
|
@ -262,7 +265,7 @@ class ReservationPool(object):
|
|||
def add_project(self, pool, project_id):
|
||||
"""Add a project to an aggregate."""
|
||||
|
||||
metadata = {project_id: cfg.CONF['physical:host'].tenant_id_key}
|
||||
metadata = {project_id: self.config.tenant_id_key}
|
||||
|
||||
agg = self.get_aggregate_from_name_or_id(pool)
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@ from climate.db.sqlalchemy import models
|
|||
from climate.openstack.common import uuidutils
|
||||
from climate import tests
|
||||
|
||||
from climate.plugins import instances as vm_plugin
|
||||
from climate.plugins import oshosts as host_plugin
|
||||
|
||||
|
||||
def _get_fake_random_uuid():
|
||||
return unicode(uuidutils.generate_uuid())
|
||||
|
@ -35,14 +38,14 @@ def _get_fake_phys_reservation_values(lease_id=_get_fake_lease_uuid(),
|
|||
resource_id=None):
|
||||
return {'lease_id': lease_id,
|
||||
'resource_id': '1234' if not resource_id else resource_id,
|
||||
'resource_type': 'physical:host'}
|
||||
'resource_type': host_plugin.RESOURCE_TYPE}
|
||||
|
||||
|
||||
def _get_fake_virt_reservation_values(lease_id=_get_fake_lease_uuid(),
|
||||
resource_id=None):
|
||||
return {'lease_id': lease_id,
|
||||
'resource_id': '5678' if not resource_id else resource_id,
|
||||
'resource_type': 'virtual:instance'}
|
||||
'resource_type': vm_plugin.RESOURCE_TYPE}
|
||||
|
||||
|
||||
def _get_fake_event_values(id=_get_fake_random_uuid(),
|
||||
|
@ -295,7 +298,7 @@ class SQLAlchemyDBApiTestCase(tests.DBTestCase):
|
|||
self.assertEqual(1, len(db_api.reservation_get_all_by_values(
|
||||
resource_id='5678')))
|
||||
self.assertEqual(1, len(db_api.reservation_get_all_by_values(
|
||||
resource_type='physical:host')))
|
||||
resource_type=host_plugin.RESOURCE_TYPE)))
|
||||
|
||||
def test_reservation_update(self):
|
||||
result = db_api.reservation_create(_get_fake_phys_reservation_values())
|
||||
|
|
|
@ -20,6 +20,7 @@ from oslo.config import cfg
|
|||
from climate import config
|
||||
from climate import context
|
||||
from climate.manager import exceptions as manager_exceptions
|
||||
from climate.plugins import oshosts as host_plugin
|
||||
from climate.plugins.oshosts import reservation_pool as rp
|
||||
from climate import tests
|
||||
from novaclient import client as nova_client
|
||||
|
@ -44,10 +45,11 @@ class ReservationPoolTestCase(tests.TestCase):
|
|||
self.fake_aggregate = AggregateFake(i=123,
|
||||
name='fooname',
|
||||
hosts=['host1', 'host2'])
|
||||
self.freepool_name = cfg.CONF['physical:host'].aggregate_freepool_name
|
||||
self.tenant_id_key = cfg.CONF['physical:host'].tenant_id_key
|
||||
self.climate_owner = cfg.CONF['physical:host'].climate_owner
|
||||
self.climate_az_prefix = cfg.CONF['physical:host'].climate_az_prefix
|
||||
conf = cfg.CONF[host_plugin.RESOURCE_TYPE]
|
||||
self.freepool_name = conf.aggregate_freepool_name
|
||||
self.tenant_id_key = conf.tenant_id_key
|
||||
self.climate_owner = conf.climate_owner
|
||||
self.climate_az_prefix = conf.climate_az_prefix
|
||||
|
||||
self.fake_freepool = AggregateFake(i=456,
|
||||
name=self.freepool_name,
|
||||
|
|
|
@ -23,6 +23,7 @@ from climate.db import utils as db_utils
|
|||
from climate.manager import exceptions as manager_exceptions
|
||||
from climate.manager import service
|
||||
from climate.openstack.common import uuidutils
|
||||
from climate.plugins import oshosts as plugin
|
||||
from climate.plugins.oshosts import host_plugin
|
||||
from climate.plugins.oshosts import nova_inventory
|
||||
from climate.plugins.oshosts import reservation_pool as rp
|
||||
|
@ -312,13 +313,13 @@ class PhysicalHostPluginTestCase(tests.TestCase):
|
|||
'resource_properties': '',
|
||||
'start_date': datetime.datetime(2013, 12, 19, 20, 00),
|
||||
'end_date': datetime.datetime(2013, 12, 19, 21, 00),
|
||||
'resource_type': u'physical:host',
|
||||
'resource_type': plugin.RESOURCE_TYPE,
|
||||
}
|
||||
reservation_values = {
|
||||
'id': u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||
'lease_id': u'018c1b43-e69e-4aef-a543-09681539cf4c',
|
||||
'resource_id': '1',
|
||||
'resource_type': u'physical:host',
|
||||
'resource_type': plugin.RESOURCE_TYPE,
|
||||
'status': 'pending',
|
||||
}
|
||||
generate_uuid = self.patch(uuidutils, 'generate_uuid')
|
||||
|
@ -353,13 +354,13 @@ class PhysicalHostPluginTestCase(tests.TestCase):
|
|||
'resource_properties': '',
|
||||
'start_date': datetime.datetime(2013, 12, 19, 20, 00),
|
||||
'end_date': datetime.datetime(2013, 12, 19, 21, 00),
|
||||
'resource_type': u'physical:host',
|
||||
'resource_type': plugin.RESOURCE_TYPE,
|
||||
}
|
||||
reservation_values = {
|
||||
'id': u'441c1476-9f8f-4700-9f30-cd9b6fef3509',
|
||||
'lease_id': u'018c1b43-e69e-4aef-a543-09681539cf4c',
|
||||
'resource_id': '1',
|
||||
'resource_type': u'physical:host',
|
||||
'resource_type': plugin.RESOURCE_TYPE,
|
||||
'status': 'pending',
|
||||
}
|
||||
generate_uuid = self.patch(uuidutils, 'generate_uuid')
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
[DEFAULT]
|
||||
|
||||
os_auth_host=<auth_host>
|
||||
os_auth_port=<auth_port>
|
||||
os_auth_protocol=<http, for example>
|
||||
os_admin_username=<username>
|
||||
os_admin_password=<password>
|
||||
os_admin_tenant_name=<tenant_name>
|
||||
climate_username=<username>
|
||||
climate_password=<password>
|
||||
climate_tenant_name=<tenant_name>
|
||||
|
||||
[manager]
|
||||
plugins=basic.vm.plugin,physical.host.plugin
|
||||
|
||||
[virtual:instance]
|
||||
on_end = create_image, delete
|
||||
|
||||
[physical:host]
|
||||
on_start = wake_up
|
||||
on_end = delete
|
|
@ -0,0 +1,777 @@
|
|||
[DEFAULT]
|
||||
|
||||
#
|
||||
# Options defined in oslo.messaging
|
||||
#
|
||||
|
||||
# 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)
|
||||
#amqp_auto_delete=false
|
||||
|
||||
# Size of RPC connection pool (integer value)
|
||||
#rpc_conn_pool_size=30
|
||||
|
||||
# Modules of exceptions that are permitted to be recreatedupon
|
||||
# receiving exception data from an rpc call. (list value)
|
||||
#allowed_rpc_exception_modules=oslo.messaging.exceptions,nova.exception,cinder.exception,exceptions
|
||||
|
||||
# Qpid broker hostname (string value)
|
||||
#qpid_hostname=localhost
|
||||
|
||||
# Qpid broker port (integer value)
|
||||
#qpid_port=5672
|
||||
|
||||
# Qpid HA cluster host:port pairs (list value)
|
||||
#qpid_hosts=$qpid_hostname:$qpid_port
|
||||
|
||||
# Username for Qpid connection (string value)
|
||||
#qpid_username=
|
||||
|
||||
# Password for Qpid connection (string value)
|
||||
#qpid_password=
|
||||
|
||||
# Space separated list of SASL mechanisms to use for auth
|
||||
# (string value)
|
||||
#qpid_sasl_mechanisms=
|
||||
|
||||
# Seconds between connection keepalive heartbeats (integer
|
||||
# value)
|
||||
#qpid_heartbeat=60
|
||||
|
||||
# Transport to use, either 'tcp' or 'ssl' (string value)
|
||||
#qpid_protocol=tcp
|
||||
|
||||
# Disable Nagle algorithm (boolean value)
|
||||
#qpid_tcp_nodelay=true
|
||||
|
||||
# The qpid topology version to use. Version 1 is what was
|
||||
# originally used by impl_qpid. Version 2 includes some
|
||||
# backwards-incompatible changes that allow broker federation
|
||||
# to work. Users should update to version 2 when they are
|
||||
# able to take everything down, as it requires a clean break.
|
||||
# (integer value)
|
||||
#qpid_topology_version=1
|
||||
|
||||
# SSL version to use (valid only if SSL enabled). valid values
|
||||
# are TLSv1, SSLv23 and SSLv3. SSLv2 may be available on some
|
||||
# distributions (string value)
|
||||
#kombu_ssl_version=
|
||||
|
||||
# SSL key file (valid only if SSL enabled) (string value)
|
||||
#kombu_ssl_keyfile=
|
||||
|
||||
# SSL cert file (valid only if SSL enabled) (string value)
|
||||
#kombu_ssl_certfile=
|
||||
|
||||
# SSL certification authority file (valid only if SSL enabled)
|
||||
# (string value)
|
||||
#kombu_ssl_ca_certs=
|
||||
|
||||
# The RabbitMQ broker address where a single node is used
|
||||
# (string value)
|
||||
#rabbit_host=localhost
|
||||
|
||||
# The RabbitMQ broker port where a single node is used
|
||||
# (integer value)
|
||||
#rabbit_port=5672
|
||||
|
||||
# RabbitMQ HA cluster host:port pairs (list value)
|
||||
#rabbit_hosts=$rabbit_host:$rabbit_port
|
||||
|
||||
# Connect over SSL for RabbitMQ (boolean value)
|
||||
#rabbit_use_ssl=false
|
||||
|
||||
# The RabbitMQ userid (string value)
|
||||
#rabbit_userid=guest
|
||||
|
||||
# The RabbitMQ password (string value)
|
||||
#rabbit_password=guest
|
||||
|
||||
# The RabbitMQ virtual host (string value)
|
||||
#rabbit_virtual_host=/
|
||||
|
||||
# How frequently to retry connecting with RabbitMQ (integer
|
||||
# value)
|
||||
#rabbit_retry_interval=1
|
||||
|
||||
# How long to backoff for between retries when connecting to
|
||||
# RabbitMQ (integer value)
|
||||
#rabbit_retry_backoff=2
|
||||
|
||||
# Maximum number of RabbitMQ connection retries. Default is 0
|
||||
# (infinite retry count) (integer value)
|
||||
#rabbit_max_retries=0
|
||||
|
||||
# Use HA queues in RabbitMQ (x-ha-policy: all). If you change
|
||||
# this option, you must wipe the RabbitMQ database. (boolean
|
||||
# value)
|
||||
#rabbit_ha_queues=false
|
||||
|
||||
# If passed, use a fake RabbitMQ provider (boolean value)
|
||||
#fake_rabbit=false
|
||||
|
||||
# ZeroMQ bind address. Should be a wildcard (*), an ethernet
|
||||
# interface, or IP. The "host" option should point or resolve
|
||||
# to this address. (string value)
|
||||
#rpc_zmq_bind_address=*
|
||||
|
||||
# MatchMaker driver (string value)
|
||||
#rpc_zmq_matchmaker=oslo.messaging._drivers.matchmaker.MatchMakerLocalhost
|
||||
|
||||
# ZeroMQ receiver listening port (integer value)
|
||||
#rpc_zmq_port=9501
|
||||
|
||||
# Number of ZeroMQ contexts, defaults to 1 (integer value)
|
||||
#rpc_zmq_contexts=1
|
||||
|
||||
# Maximum number of ingress messages to locally buffer per
|
||||
# topic. Default is unlimited. (integer value)
|
||||
#rpc_zmq_topic_backlog=<None>
|
||||
|
||||
# Directory for holding IPC sockets (string value)
|
||||
#rpc_zmq_ipc_dir=/var/run/openstack
|
||||
|
||||
# Name of this node. Must be a valid hostname, FQDN, or IP
|
||||
# address. Must match "host" option, if running Nova. (string
|
||||
# value)
|
||||
#rpc_zmq_host=climate
|
||||
|
||||
# Seconds to wait before a cast expires (TTL). Only supported
|
||||
# by impl_zmq. (integer value)
|
||||
#rpc_cast_timeout=30
|
||||
|
||||
# Heartbeat frequency (integer value)
|
||||
#matchmaker_heartbeat_freq=300
|
||||
|
||||
# Heartbeat time-to-live. (integer value)
|
||||
#matchmaker_heartbeat_ttl=600
|
||||
|
||||
# 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>
|
||||
|
||||
# Size of RPC greenthread pool (integer value)
|
||||
#rpc_thread_pool_size=64
|
||||
|
||||
# Driver or drivers to handle sending notifications (multi
|
||||
# valued)
|
||||
#notification_driver=
|
||||
|
||||
# AMQP topic used for OpenStack notifications (list value)
|
||||
# Deprecated group/name - [rpc_notifier2]/topics
|
||||
#notification_topics=notifications
|
||||
|
||||
# Seconds to wait for a response from a call (integer value)
|
||||
#rpc_response_timeout=60
|
||||
|
||||
# A URL representing the messaging driver to use and its full
|
||||
# configuration. If not set, we fall back to the rpc_backend
|
||||
# option and driver specific configuration. (string value)
|
||||
#transport_url=<None>
|
||||
|
||||
# The messaging driver to use, defaults to rabbit. Other
|
||||
# drivers include qpid and zmq. (string value)
|
||||
#rpc_backend=rabbit
|
||||
|
||||
# The default exchange under which topics are scoped. May be
|
||||
# overridden by an exchange name specified in the
|
||||
# transport_url option. (string value)
|
||||
#control_exchange=openstack
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.config
|
||||
#
|
||||
|
||||
# Log request/response exchange details: environ, headers and
|
||||
# bodies (boolean value)
|
||||
#log_exchange=false
|
||||
|
||||
# Name of this node. This can be an opaque identifier. It is
|
||||
# not necessarily a hostname, FQDN, or IP address. However,
|
||||
# the node name must be valid within an AMQP key, and if using
|
||||
# ZeroMQ, a valid hostname, FQDN, or IP address (string value)
|
||||
#host=climate
|
||||
|
||||
# Protocol used to access OpenStack Identity service (string
|
||||
# value)
|
||||
#os_auth_protocol=http
|
||||
|
||||
# IP or hostname of machine on which OpenStack Identity
|
||||
# service is located (string value)
|
||||
#os_auth_host=127.0.0.1
|
||||
|
||||
# Port of OpenStack Identity service (string value)
|
||||
#os_auth_port=35357
|
||||
|
||||
# This OpenStack user is used to verify provided tokens. The
|
||||
# user must have admin role in <os_admin_tenant_name> tenant
|
||||
# (string value)
|
||||
#os_admin_username=admin
|
||||
|
||||
# Password of the admin user (string value)
|
||||
#os_admin_password=climate
|
||||
|
||||
# Name of tenant where the user is admin (string value)
|
||||
#os_admin_tenant_name=admin
|
||||
|
||||
# We use API v3 to allow trusts using. (string value)
|
||||
#os_auth_version=v2.0
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.cmd.api
|
||||
#
|
||||
|
||||
# Port that will be used to listen on (integer value)
|
||||
#port=1234
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.db.base
|
||||
#
|
||||
|
||||
# Driver to use for database access (string value)
|
||||
#db_driver=climate.db
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.openstack.common.db.sqlalchemy.session
|
||||
#
|
||||
|
||||
# the filename to use with sqlite (string value)
|
||||
#sqlite_db=climate.sqlite
|
||||
|
||||
# If true, use synchronous mode for sqlite (boolean value)
|
||||
#sqlite_synchronous=true
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.openstack.common.deprecated.wsgi
|
||||
#
|
||||
|
||||
# Number of backlog requests to configure the socket with
|
||||
# (integer value)
|
||||
#backlog=4096
|
||||
|
||||
# Sets the value of TCP_KEEPIDLE in seconds for each server
|
||||
# socket. Not supported on OS X. (integer value)
|
||||
#tcp_keepidle=600
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.openstack.common.eventlet_backdoor
|
||||
#
|
||||
|
||||
# Enable eventlet backdoor. Acceptable values are 0, <port>,
|
||||
# and <start>:<end>, where 0 results in listening on a random
|
||||
# tcp port number; <port> results in listening on the
|
||||
# specified port number (and not enabling backdoor if that
|
||||
# port is in use); and <start>:<end> results in listening on
|
||||
# the smallest unused port number within the specified range
|
||||
# of port numbers. The chosen port is displayed in the
|
||||
# service's log file. (string value)
|
||||
#backdoor_port=<None>
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.openstack.common.lockutils
|
||||
#
|
||||
|
||||
# Whether to disable inter-process locks (boolean value)
|
||||
#disable_process_locking=false
|
||||
|
||||
# Directory to use for lock files. (string value)
|
||||
#lock_path=<None>
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.openstack.common.log
|
||||
#
|
||||
|
||||
# Print debugging output (set logging level to DEBUG instead
|
||||
# of default WARNING level). (boolean value)
|
||||
#debug=false
|
||||
|
||||
# Print more verbose output (set logging level to INFO instead
|
||||
# of default WARNING level). (boolean value)
|
||||
#verbose=false
|
||||
|
||||
# Log output to standard error (boolean value)
|
||||
#use_stderr=true
|
||||
|
||||
# format string to use for log messages with context (string
|
||||
# value)
|
||||
#logging_context_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user)s %(tenant)s] %(instance)s%(message)s
|
||||
|
||||
# format string to use for log messages without context
|
||||
# (string value)
|
||||
#logging_default_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s
|
||||
|
||||
# data to append to log format when level is DEBUG (string
|
||||
# value)
|
||||
#logging_debug_format_suffix=%(funcName)s %(pathname)s:%(lineno)d
|
||||
|
||||
# prefix each line of exception output with this format
|
||||
# (string value)
|
||||
#logging_exception_prefix=%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s
|
||||
|
||||
# list of logger=LEVEL pairs (list value)
|
||||
#default_log_levels=amqplib=WARN,sqlalchemy=WARN,boto=WARN,suds=INFO,keystone=INFO,eventlet.wsgi.server=WARN
|
||||
|
||||
# publish error events (boolean value)
|
||||
#publish_errors=false
|
||||
|
||||
# make deprecations fatal (boolean value)
|
||||
#fatal_deprecations=false
|
||||
|
||||
# If an instance is passed with the log message, format it
|
||||
# like this (string value)
|
||||
#instance_format="[instance: %(uuid)s] "
|
||||
|
||||
# If an instance UUID is passed with the log message, format
|
||||
# it like this (string value)
|
||||
#instance_uuid_format="[instance: %(uuid)s] "
|
||||
|
||||
# If this option is specified, the logging configuration file
|
||||
# specified is used and overrides any other logging options
|
||||
# specified. Please see the Python logging module
|
||||
# documentation for details on logging configuration files.
|
||||
# (string value)
|
||||
#log_config=<None>
|
||||
|
||||
# DEPRECATED. A logging.Formatter log message format string
|
||||
# which may use any of the available logging.LogRecord
|
||||
# attributes. This option is deprecated. Please use
|
||||
# logging_context_format_string and
|
||||
# logging_default_format_string instead. (string value)
|
||||
#log_format=<None>
|
||||
|
||||
# Format string for %%(asctime)s in log records. Default:
|
||||
# %(default)s (string value)
|
||||
#log_date_format=%Y-%m-%d %H:%M:%S
|
||||
|
||||
# (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)
|
||||
#use_syslog=false
|
||||
|
||||
# syslog facility to receive log lines (string value)
|
||||
#syslog_log_facility=LOG_USER
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.openstack.common.middleware.sizelimit
|
||||
#
|
||||
|
||||
# the maximum body size per each request(bytes) (integer
|
||||
# value)
|
||||
# Deprecated group/name - [DEFAULT]/osapi_max_request_body_size
|
||||
#max_request_body_size=114688
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.openstack.common.notifier.api
|
||||
#
|
||||
|
||||
# Driver or drivers to handle sending notifications (multi
|
||||
# valued)
|
||||
#notification_driver=
|
||||
|
||||
# Default notification level for outgoing notifications
|
||||
# (string value)
|
||||
#default_notification_level=INFO
|
||||
|
||||
# Default publisher_id for outgoing notifications (string
|
||||
# value)
|
||||
#default_publisher_id=<None>
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.openstack.common.policy
|
||||
#
|
||||
|
||||
# JSON file containing policy (string value)
|
||||
#policy_file=policy.json
|
||||
|
||||
# Rule enforced when requested rule is not found (string
|
||||
# value)
|
||||
#policy_default_rule=default
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.utils.openstack.keystone
|
||||
#
|
||||
|
||||
# Keystoneclient version (string value)
|
||||
#keystone_client_version=3
|
||||
|
||||
# Identity service to use. (string value)
|
||||
#identity_service=identityv3
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.utils.openstack.nova
|
||||
#
|
||||
|
||||
# Novaclient version (string value)
|
||||
#nova_client_version=2
|
||||
|
||||
# Nova name in keystone (string value)
|
||||
#compute_service=compute
|
||||
|
||||
# Prefix for VM images if you want to create snapshots (string
|
||||
# value)
|
||||
#image_prefix=reserved_
|
||||
|
||||
|
||||
[database]
|
||||
|
||||
#
|
||||
# Options defined in climate.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 climate.openstack.common.db.sqlalchemy.session
|
||||
#
|
||||
|
||||
# The SQLAlchemy connection string used to connect to the
|
||||
# database (string value)
|
||||
# Deprecated group/name - [DEFAULT]/sql_connection
|
||||
# Deprecated group/name - [DATABASE]/sql_connection
|
||||
# Deprecated group/name - [sql]/connection
|
||||
#connection=sqlite:////climate/openstack/common/db/$sqlite_db
|
||||
|
||||
# The SQLAlchemy connection string used to connect to the
|
||||
# slave database (string value)
|
||||
#slave_connection=
|
||||
|
||||
# timeout before idle sql connections are reaped (integer
|
||||
# value)
|
||||
# Deprecated group/name - [DEFAULT]/sql_idle_timeout
|
||||
# Deprecated group/name - [DATABASE]/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
|
||||
# Deprecated group/name - [DATABASE]/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
|
||||
# Deprecated group/name - [DATABASE]/sql_max_pool_size
|
||||
#max_pool_size=<None>
|
||||
|
||||
# maximum db connection retries during startup. (setting -1
|
||||
# implies an infinite retry count) (integer value)
|
||||
# Deprecated group/name - [DEFAULT]/sql_max_retries
|
||||
# Deprecated group/name - [DATABASE]/sql_max_retries
|
||||
#max_retries=10
|
||||
|
||||
# interval between retries of opening a sql connection
|
||||
# (integer value)
|
||||
# Deprecated group/name - [DEFAULT]/sql_retry_interval
|
||||
# Deprecated group/name - [DATABASE]/reconnect_interval
|
||||
#retry_interval=10
|
||||
|
||||
# If set, use this value for max_overflow with sqlalchemy
|
||||
# (integer value)
|
||||
# Deprecated group/name - [DEFAULT]/sql_max_overflow
|
||||
# Deprecated group/name - [DATABASE]/sqlalchemy_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
|
||||
|
||||
# If set, use this value for pool_timeout with sqlalchemy
|
||||
# (integer value)
|
||||
# Deprecated group/name - [DATABASE]/sqlalchemy_pool_timeout
|
||||
#pool_timeout=<None>
|
||||
|
||||
|
||||
[keystone_authtoken]
|
||||
|
||||
#
|
||||
# Options defined in keystoneclient.middleware.auth_token
|
||||
#
|
||||
|
||||
# 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
|
||||
|
||||
# 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>
|
||||
|
||||
# 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
|
||||
# (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>
|
||||
|
||||
# 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>
|
||||
|
||||
# (optional) indicate whether to set the X-Service-Catalog
|
||||
# header. If False, middleware will not ask for service
|
||||
# catalog on token validation and will not set the X-Service-
|
||||
# Catalog header. (boolean value)
|
||||
#include_service_catalog=true
|
||||
|
||||
# Used to control the use and type of token binding. Can be
|
||||
# set to: "disabled" to not check token binding. "permissive"
|
||||
# (default) to validate binding information if the bind type
|
||||
# is of a form known to the server and ignore it if not.
|
||||
# "strict" like "permissive" but if the bind type is unknown
|
||||
# the token will be rejected. "required" any form of token
|
||||
# binding is needed to be allowed. Finally the name of a
|
||||
# binding method that must be present in tokens. (string
|
||||
# value)
|
||||
#enforce_token_bind=permissive
|
||||
|
||||
|
||||
[manager]
|
||||
|
||||
#
|
||||
# Options defined in climate.manager
|
||||
#
|
||||
|
||||
# The topic Climate uses for climate-manager messages. (string
|
||||
# value)
|
||||
#rpc_topic=climate.manager
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.manager.service
|
||||
#
|
||||
|
||||
# All plugins to use (one for every resource type to support.)
|
||||
# (list value)
|
||||
#plugins=dummy.vm.plugin
|
||||
|
||||
|
||||
[matchmaker_ring]
|
||||
|
||||
#
|
||||
# Options defined in oslo.messaging
|
||||
#
|
||||
|
||||
# Matchmaker ring file (JSON) (string value)
|
||||
# Deprecated group/name - [DEFAULT]/matchmaker_ringfile
|
||||
#ringfile=/etc/oslo/matchmaker_ring.json
|
||||
|
||||
|
||||
[physical:host]
|
||||
|
||||
#
|
||||
# Options defined in climate.plugins.oshosts
|
||||
#
|
||||
|
||||
# Name of the user for write operations (string value)
|
||||
#climate_username=climate_admin
|
||||
|
||||
# Password of the user for write operations (string value)
|
||||
#climate_password=climate_password
|
||||
|
||||
# Tenant of the user for write operations (string value)
|
||||
#climate_tenant_name=admin
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.plugins.oshosts.host_plugin
|
||||
#
|
||||
|
||||
# Actions which we will use in the end of the lease (string
|
||||
# value)
|
||||
#on_end=on_end
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.plugins.oshosts.reservation_pool
|
||||
#
|
||||
|
||||
# Name of the special aggregate where all hosts are candidate
|
||||
# for physical host reservation (string value)
|
||||
#aggregate_freepool_name=freepool
|
||||
|
||||
# Aggregate metadata value for key matching tenant_id (string
|
||||
# value)
|
||||
#tenant_id_key=climate:tenant
|
||||
|
||||
# Aggregate metadata key for knowing owner tenant_id (string
|
||||
# value)
|
||||
#climate_owner=climate:owner
|
||||
|
||||
# Prefix for Availability Zones created by Climate (string
|
||||
# value)
|
||||
#climate_az_prefix=climate:
|
||||
|
||||
|
||||
[ssl]
|
||||
|
||||
#
|
||||
# Options defined in climate.openstack.common.sslutils
|
||||
#
|
||||
|
||||
# CA certificate file to use to verify connecting clients
|
||||
# (string value)
|
||||
#ca_file=<None>
|
||||
|
||||
# Certificate file to use when starting the server securely
|
||||
# (string value)
|
||||
#cert_file=<None>
|
||||
|
||||
# Private key file to use when starting the server securely
|
||||
# (string value)
|
||||
#key_file=<None>
|
||||
|
||||
|
||||
[virtual:instance]
|
||||
|
||||
#
|
||||
# Options defined in climate.plugins.instances.vm_plugin
|
||||
#
|
||||
|
||||
# Actions which we will use in the end of the lease (string
|
||||
# value)
|
||||
#on_end=create_image, delete
|
||||
|
||||
# Actions which we will use at the start of the lease (string
|
||||
# value)
|
||||
#on_start=on_start
|
||||
|
||||
|
||||
#
|
||||
# Options defined in climate.plugins.oshosts.host_plugin
|
||||
#
|
||||
|
||||
# Actions which we will use at the start of the lease (string
|
||||
# value)
|
||||
#on_start=on_start
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
[DEFAULT]
|
||||
|
||||
# The list of modules to copy from oslo-incubator
|
||||
module=config
|
||||
module=db
|
||||
module=db.sqlalchemy
|
||||
module=eventlet_backdoor
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
PROJECT_NAME=${PROJECT_NAME:-climate}
|
||||
CFGFILE_NAME=${PROJECT_NAME}.conf.sample
|
||||
|
||||
if [ -e etc/${PROJECT_NAME}/${CFGFILE_NAME} ]; then
|
||||
CFGFILE=etc/${PROJECT_NAME}/${CFGFILE_NAME}
|
||||
elif [ -e etc/${CFGFILE_NAME} ]; then
|
||||
CFGFILE=etc/${CFGFILE_NAME}
|
||||
else
|
||||
echo "${0##*/}: can not find config file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TEMPDIR=`mktemp -d /tmp/${PROJECT_NAME}.XXXXXX`
|
||||
trap "rm -rf $TEMPDIR" EXIT
|
||||
|
||||
tools/config/generate_sample.sh -b ./ -p ${PROJECT_NAME} -o ${TEMPDIR}
|
||||
|
||||
if ! diff -u ${TEMPDIR}/${CFGFILE_NAME} ${CFGFILE}
|
||||
then
|
||||
echo "${0##*/}: ${PROJECT_NAME}.conf.sample is not up to date."
|
||||
echo "${0##*/}: Please run ${0%%${0##*/}}generate_sample.sh."
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,119 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
print_hint() {
|
||||
echo "Try \`${0##*/} --help' for more information." >&2
|
||||
}
|
||||
|
||||
PARSED_OPTIONS=$(getopt -n "${0##*/}" -o hb:p:m:l:o: \
|
||||
--long help,base-dir:,package-name:,output-dir:,module:,library: -- "$@")
|
||||
|
||||
if [ $? != 0 ] ; then print_hint ; exit 1 ; fi
|
||||
|
||||
eval set -- "$PARSED_OPTIONS"
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
echo "${0##*/} [options]"
|
||||
echo ""
|
||||
echo "options:"
|
||||
echo "-h, --help show brief help"
|
||||
echo "-b, --base-dir=DIR project base directory"
|
||||
echo "-p, --package-name=NAME project package name"
|
||||
echo "-o, --output-dir=DIR file output directory"
|
||||
echo "-m, --module=MOD extra python module to interrogate for options"
|
||||
echo "-l, --library=LIB extra library that registers options for discovery"
|
||||
exit 0
|
||||
;;
|
||||
-b|--base-dir)
|
||||
shift
|
||||
BASEDIR=`echo $1 | sed -e 's/\/*$//g'`
|
||||
shift
|
||||
;;
|
||||
-p|--package-name)
|
||||
shift
|
||||
PACKAGENAME=`echo $1`
|
||||
shift
|
||||
;;
|
||||
-o|--output-dir)
|
||||
shift
|
||||
OUTPUTDIR=`echo $1 | sed -e 's/\/*$//g'`
|
||||
shift
|
||||
;;
|
||||
-m|--module)
|
||||
shift
|
||||
MODULES="$MODULES -m $1"
|
||||
shift
|
||||
;;
|
||||
-l|--library)
|
||||
shift
|
||||
LIBRARIES="$LIBRARIES -l $1"
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
BASEDIR=${BASEDIR:-`pwd`}
|
||||
if ! [ -d $BASEDIR ]
|
||||
then
|
||||
echo "${0##*/}: missing project base directory" >&2 ; print_hint ; exit 1
|
||||
elif [[ $BASEDIR != /* ]]
|
||||
then
|
||||
BASEDIR=$(cd "$BASEDIR" && pwd)
|
||||
fi
|
||||
|
||||
PACKAGENAME=${PACKAGENAME:-${BASEDIR##*/}}
|
||||
TARGETDIR=$BASEDIR/$PACKAGENAME
|
||||
if ! [ -d $TARGETDIR ]
|
||||
then
|
||||
echo "${0##*/}: invalid project package name" >&2 ; print_hint ; exit 1
|
||||
fi
|
||||
|
||||
OUTPUTDIR=${OUTPUTDIR:-$BASEDIR/etc}
|
||||
# NOTE(bnemec): Some projects put their sample config in etc/,
|
||||
# some in etc/$PACKAGENAME/
|
||||
if [ -d $OUTPUTDIR/$PACKAGENAME ]
|
||||
then
|
||||
OUTPUTDIR=$OUTPUTDIR/$PACKAGENAME
|
||||
elif ! [ -d $OUTPUTDIR ]
|
||||
then
|
||||
echo "${0##*/}: cannot access \`$OUTPUTDIR': No such file or directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BASEDIRESC=`echo $BASEDIR | sed -e 's/\//\\\\\//g'`
|
||||
find $TARGETDIR -type f -name "*.pyc" -delete
|
||||
FILES=$(find $TARGETDIR -type f -name "*.py" ! -path "*/tests/*" \
|
||||
-exec grep -l "Opt(" {} + | sed -e "s/^$BASEDIRESC\///g" | sort -u)
|
||||
|
||||
RC_FILE="`dirname $0`/oslo.config.generator.rc"
|
||||
if test -r "$RC_FILE"
|
||||
then
|
||||
source "$RC_FILE"
|
||||
fi
|
||||
|
||||
for mod in ${CLIMATE_CONFIG_GENERATOR_EXTRA_MODULES}; do
|
||||
MODULES="$MODULES -m $mod"
|
||||
done
|
||||
|
||||
for lib in ${CLIMATE_CONFIG_GENERATOR_EXTRA_LIBRARIES}; do
|
||||
LIBRARIES="$LIBRARIES -l $lib"
|
||||
done
|
||||
|
||||
export EVENTLET_NO_GREENDNS=yes
|
||||
|
||||
OS_VARS=$(set | sed -n '/^OS_/s/=[^=]*$//gp' | xargs)
|
||||
[ "$OS_VARS" ] && eval "unset \$OS_VARS"
|
||||
DEFAULT_MODULEPATH=climate.openstack.common.config.generator
|
||||
MODULEPATH=${MODULEPATH:-$DEFAULT_MODULEPATH}
|
||||
OUTPUTFILE=$OUTPUTDIR/$PACKAGENAME.conf.sample
|
||||
python -m $MODULEPATH $MODULES $LIBRARIES $FILES > $OUTPUTFILE
|
||||
|
||||
# Hook to allow projects to append custom config file snippets
|
||||
CONCAT_FILES=$(ls $BASEDIR/tools/config/*.conf.sample 2>/dev/null)
|
||||
for CONCAT_FILE in $CONCAT_FILES; do
|
||||
cat $CONCAT_FILE >> $OUTPUTFILE
|
||||
done
|
|
@ -0,0 +1,2 @@
|
|||
export CLIMATE_CONFIG_GENERATOR_EXTRA_MODULES="keystoneclient.middleware.auth_token"
|
||||
export CLIMATE_CONFIG_GENERATOR_EXTRA_LIBRARIES="oslo.messaging"
|
2
tox.ini
2
tox.ini
|
@ -12,6 +12,7 @@ setenv = VIRTUAL_ENV={envdir}
|
|||
DISCOVER_DIRECTORY=climate/tests
|
||||
commands =
|
||||
python -m climate.openstack.common.lockutils python setup.py testr --slowest --testr-args="{posargs}"
|
||||
|
||||
sitepackages = False
|
||||
|
||||
[testenv:cover]
|
||||
|
@ -21,6 +22,7 @@ commands =
|
|||
|
||||
[testenv:pep8]
|
||||
commands = flake8 {posargs}
|
||||
{toxinidir}/tools/config/check_uptodate.sh
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
|
Loading…
Reference in New Issue