
Use openstack-common's update.py script to pull in some recent changes: * Add the Mapping interface to cfg.ConfigOpts * Add support to cfg for disabling interspersed args Make use of both of these in nova/flags.py. Add some dire warnings to HACKING about directly modifying the copy of openstack-common code. I'm confident they won't be ignored :-) Change-Id: I7ef75d18922c0bbb8844453b48cad0418034bc11
546 lines
20 KiB
Python
546 lines
20 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright 2010 United States Government as represented by the
|
|
# Administrator of the National Aeronautics and Space Administration.
|
|
# All Rights Reserved.
|
|
# Copyright 2011 Red Hat, Inc.
|
|
#
|
|
# 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.
|
|
|
|
"""Command-line flag library.
|
|
|
|
Emulates gflags by wrapping cfg.ConfigOpts.
|
|
|
|
The idea is to move fully to cfg eventually, and this wrapper is a
|
|
stepping stone.
|
|
|
|
"""
|
|
|
|
import os
|
|
import socket
|
|
import sys
|
|
|
|
import gflags
|
|
|
|
from nova.openstack.common import cfg
|
|
|
|
|
|
class FlagValues(object):
|
|
class Flag:
|
|
def __init__(self, name, value, update_default=None):
|
|
self.name = name
|
|
self.value = value
|
|
self._update_default = update_default
|
|
|
|
def SetDefault(self, default):
|
|
if self._update_default:
|
|
self._update_default(self.name, default)
|
|
|
|
class ErrorCatcher:
|
|
def __init__(self, orig_error):
|
|
self.orig_error = orig_error
|
|
self.reset()
|
|
|
|
def reset(self):
|
|
self._error_msg = None
|
|
|
|
def catch(self, msg):
|
|
if ": --" in msg:
|
|
self._error_msg = msg
|
|
else:
|
|
self.orig_error(msg)
|
|
|
|
def get_unknown_arg(self, args):
|
|
if not self._error_msg:
|
|
return None
|
|
# Error message is e.g. "no such option: --runtime_answer"
|
|
a = self._error_msg[self._error_msg.rindex(": --") + 2:]
|
|
return filter(lambda i: i == a or i.startswith(a + "="), args)[0]
|
|
|
|
def __init__(self):
|
|
self._conf = cfg.ConfigOpts()
|
|
self._conf.disable_interspersed_args()
|
|
self._opts = {}
|
|
self.Reset()
|
|
|
|
def _parse(self):
|
|
if self._extra is not None:
|
|
return
|
|
|
|
args = gflags.FlagValues().ReadFlagsFromFiles(self._args)
|
|
|
|
extra = None
|
|
|
|
#
|
|
# This horrendous hack allows us to stop optparse
|
|
# exiting when it encounters an unknown option
|
|
#
|
|
error_catcher = self.ErrorCatcher(self._conf._oparser.error)
|
|
self._conf._oparser.error = error_catcher.catch
|
|
try:
|
|
while True:
|
|
error_catcher.reset()
|
|
|
|
extra = self._conf(args)
|
|
|
|
unknown = error_catcher.get_unknown_arg(args)
|
|
if not unknown:
|
|
break
|
|
|
|
args.remove(unknown)
|
|
finally:
|
|
self._conf._oparser.error = error_catcher.orig_error
|
|
|
|
self._extra = extra
|
|
|
|
def __call__(self, argv):
|
|
self.Reset()
|
|
self._args = argv[1:]
|
|
self._parse()
|
|
return [argv[0]] + self._extra
|
|
|
|
def __getattr__(self, name):
|
|
self._parse()
|
|
return getattr(self._conf, name)
|
|
|
|
def get(self, name, default):
|
|
value = getattr(self, name)
|
|
if value is not None: # value might be '0' or ""
|
|
return value
|
|
else:
|
|
return default
|
|
|
|
def __contains__(self, name):
|
|
self._parse()
|
|
return hasattr(self._conf, name)
|
|
|
|
def _update_default(self, name, default):
|
|
self._conf.set_default(name, default)
|
|
|
|
def __iter__(self):
|
|
return self._conf.iterkeys()
|
|
|
|
def __getitem__(self, name):
|
|
self._parse()
|
|
if not self.__contains__(name):
|
|
return None
|
|
return self.Flag(name, getattr(self, name), self._update_default)
|
|
|
|
def Reset(self):
|
|
self._conf.reset()
|
|
self._args = []
|
|
self._extra = None
|
|
|
|
def ParseNewFlags(self):
|
|
pass
|
|
|
|
def FlagValuesDict(self):
|
|
self._parse()
|
|
ret = {}
|
|
for name in self._conf:
|
|
ret[name] = getattr(self, name)
|
|
return ret
|
|
|
|
def add_option(self, opt):
|
|
if opt.dest in self._conf:
|
|
return
|
|
|
|
self._opts[opt.dest] = opt
|
|
|
|
try:
|
|
self._conf.register_cli_opts(self._opts.values())
|
|
except cfg.ArgsAlreadyParsedError:
|
|
self._conf.reset()
|
|
self._conf.register_cli_opts(self._opts.values())
|
|
self._extra = None
|
|
|
|
def add_options(self, opts):
|
|
for opt in opts:
|
|
self.add_option(opt)
|
|
|
|
|
|
FLAGS = FlagValues()
|
|
|
|
|
|
class UnrecognizedFlag(Exception):
|
|
pass
|
|
|
|
|
|
def DECLARE(name, module_string, flag_values=FLAGS):
|
|
if module_string not in sys.modules:
|
|
__import__(module_string, globals(), locals())
|
|
if name not in flag_values:
|
|
raise UnrecognizedFlag('%s not defined by %s' % (name, module_string))
|
|
|
|
|
|
def _get_my_ip():
|
|
"""Returns the actual ip of the local machine."""
|
|
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 as ex:
|
|
return "127.0.0.1"
|
|
|
|
|
|
global_opts = [
|
|
cfg.StrOpt('my_ip',
|
|
default=_get_my_ip(),
|
|
help='host ip address'),
|
|
cfg.ListOpt('region_list',
|
|
default=[],
|
|
help='list of region=fqdn pairs separated by commas'),
|
|
cfg.StrOpt('connection_type',
|
|
default=None,
|
|
help='libvirt, xenapi or fake'),
|
|
cfg.StrOpt('aws_access_key_id',
|
|
default='admin',
|
|
help='AWS Access ID'),
|
|
cfg.StrOpt('aws_secret_access_key',
|
|
default='admin',
|
|
help='AWS Access Key'),
|
|
cfg.StrOpt('glance_host',
|
|
default='$my_ip',
|
|
help='default glance host'),
|
|
cfg.IntOpt('glance_port',
|
|
default=9292,
|
|
help='default glance port'),
|
|
cfg.ListOpt('glance_api_servers',
|
|
default=['$glance_host:$glance_port'],
|
|
help='glance api servers available to nova (host:port)'),
|
|
cfg.IntOpt('glance_num_retries',
|
|
default=0,
|
|
help='Number retries when downloading an image from glance'),
|
|
cfg.IntOpt('s3_port',
|
|
default=3333,
|
|
help='s3 port'),
|
|
cfg.StrOpt('s3_host',
|
|
default='$my_ip',
|
|
help='s3 host (for infrastructure)'),
|
|
cfg.StrOpt('s3_dmz',
|
|
default='$my_ip',
|
|
help='s3 dmz ip (for instances)'),
|
|
cfg.StrOpt('cert_topic',
|
|
default='cert',
|
|
help='the topic cert nodes listen on'),
|
|
cfg.StrOpt('compute_topic',
|
|
default='compute',
|
|
help='the topic compute nodes listen on'),
|
|
cfg.StrOpt('console_topic',
|
|
default='console',
|
|
help='the topic console proxy nodes listen on'),
|
|
cfg.StrOpt('scheduler_topic',
|
|
default='scheduler',
|
|
help='the topic scheduler nodes listen on'),
|
|
cfg.StrOpt('volume_topic',
|
|
default='volume',
|
|
help='the topic volume nodes listen on'),
|
|
cfg.StrOpt('network_topic',
|
|
default='network',
|
|
help='the topic network nodes listen on'),
|
|
cfg.StrOpt('ajax_console_proxy_topic',
|
|
default='ajax_proxy',
|
|
help='the topic ajax proxy nodes listen on'),
|
|
cfg.StrOpt('ajax_console_proxy_url',
|
|
default='http://127.0.0.1:8000',
|
|
help='URL of ajax console proxy, in the form http://host:port'),
|
|
cfg.IntOpt('ajax_console_proxy_port',
|
|
default=8000,
|
|
help='port that ajax_console_proxy binds'),
|
|
cfg.StrOpt('vsa_topic',
|
|
default='vsa',
|
|
help='the topic that nova-vsa service listens on'),
|
|
cfg.BoolOpt('verbose',
|
|
default=False,
|
|
help='show debug output'),
|
|
cfg.BoolOpt('fake_rabbit',
|
|
default=False,
|
|
help='use a fake rabbit'),
|
|
cfg.BoolOpt('fake_network',
|
|
default=False,
|
|
help='should we use fake network devices and addresses'),
|
|
cfg.StrOpt('rabbit_host',
|
|
default='localhost',
|
|
help='rabbit host'),
|
|
cfg.IntOpt('rabbit_port',
|
|
default=5672,
|
|
help='rabbit port'),
|
|
cfg.BoolOpt('rabbit_use_ssl',
|
|
default=False,
|
|
help='connect over SSL'),
|
|
cfg.StrOpt('rabbit_userid',
|
|
default='guest',
|
|
help='rabbit userid'),
|
|
cfg.StrOpt('rabbit_password',
|
|
default='guest',
|
|
help='rabbit password'),
|
|
cfg.StrOpt('rabbit_virtual_host',
|
|
default='/',
|
|
help='rabbit virtual host'),
|
|
cfg.IntOpt('rabbit_retry_interval',
|
|
default=1,
|
|
help='rabbit connection retry interval to start'),
|
|
cfg.IntOpt('rabbit_retry_backoff',
|
|
default=2,
|
|
help='rabbit connection retry backoff in seconds'),
|
|
cfg.IntOpt('rabbit_max_retries',
|
|
default=0,
|
|
help='maximum rabbit connection attempts (0=try forever)'),
|
|
cfg.StrOpt('control_exchange',
|
|
default='nova',
|
|
help='the main exchange to connect to'),
|
|
cfg.BoolOpt('rabbit_durable_queues',
|
|
default=False,
|
|
help='use durable queues'),
|
|
cfg.ListOpt('enabled_apis',
|
|
default=['ec2', 'osapi_compute', 'osapi_volume', 'metadata'],
|
|
help='list of APIs to enable by default'),
|
|
cfg.StrOpt('ec2_host',
|
|
default='$my_ip',
|
|
help='ip of api server'),
|
|
cfg.StrOpt('ec2_dmz_host',
|
|
default='$my_ip',
|
|
help='internal ip of api server'),
|
|
cfg.IntOpt('ec2_port',
|
|
default=8773,
|
|
help='cloud controller port'),
|
|
cfg.StrOpt('ec2_scheme',
|
|
default='http',
|
|
help='prefix for ec2'),
|
|
cfg.StrOpt('ec2_path',
|
|
default='/services/Cloud',
|
|
help='suffix for ec2'),
|
|
cfg.MultiStrOpt('osapi_compute_extension',
|
|
default=[
|
|
'nova.api.openstack.compute.contrib.standard_extensions'
|
|
],
|
|
help='osapi compute extension to load'),
|
|
cfg.MultiStrOpt('osapi_volume_extension',
|
|
default=[
|
|
'nova.api.openstack.volume.contrib.standard_extensions'
|
|
],
|
|
help='osapi volume extension to load'),
|
|
cfg.StrOpt('osapi_scheme',
|
|
default='http',
|
|
help='prefix for openstack'),
|
|
cfg.StrOpt('osapi_path',
|
|
default='/v1.1/',
|
|
help='suffix for openstack'),
|
|
cfg.StrOpt('osapi_compute_link_prefix',
|
|
default=None,
|
|
help='Base URL that will be presented to users in links '
|
|
'to the Openstack Compute API'),
|
|
cfg.StrOpt('osapi_glance_link_prefix',
|
|
default=None,
|
|
help='Base URL that will be presented to users in links '
|
|
'to glance resources'),
|
|
cfg.IntOpt('osapi_max_limit',
|
|
default=1000,
|
|
help='max number of items returned in a collection response'),
|
|
cfg.StrOpt('metadata_host',
|
|
default='$my_ip',
|
|
help='ip of metadata server'),
|
|
cfg.IntOpt('metadata_port',
|
|
default=8775,
|
|
help='Metadata API port'),
|
|
cfg.StrOpt('default_project',
|
|
default='openstack',
|
|
help='default project for openstack'),
|
|
cfg.StrOpt('default_image',
|
|
default='ami-11111',
|
|
help='default image to use, testing only'),
|
|
cfg.StrOpt('default_instance_type',
|
|
default='m1.small',
|
|
help='default instance type to use, testing only'),
|
|
cfg.StrOpt('null_kernel',
|
|
default='nokernel',
|
|
help='kernel image that indicates not to use a kernel, but to '
|
|
'use a raw disk image instead'),
|
|
cfg.StrOpt('vpn_image_id',
|
|
default='0',
|
|
help='image id for cloudpipe vpn server'),
|
|
cfg.StrOpt('vpn_key_suffix',
|
|
default='-vpn',
|
|
help='Suffix to add to project name for vpn key and secgroups'),
|
|
cfg.IntOpt('auth_token_ttl',
|
|
default=3600,
|
|
help='Seconds for auth tokens to linger'),
|
|
cfg.StrOpt('state_path',
|
|
default=os.path.join(os.path.dirname(__file__), '../'),
|
|
help="Top-level directory for maintaining nova's state"),
|
|
cfg.StrOpt('lock_path',
|
|
default=os.path.join(os.path.dirname(__file__), '../'),
|
|
help='Directory for lock files'),
|
|
cfg.StrOpt('logdir',
|
|
default=None,
|
|
help='output to a per-service log file in named directory'),
|
|
cfg.StrOpt('logfile_mode',
|
|
default='0644',
|
|
help='Default file mode of the logs.'),
|
|
cfg.StrOpt('sqlite_db',
|
|
default='nova.sqlite',
|
|
help='file name for sqlite'),
|
|
cfg.BoolOpt('sqlite_synchronous',
|
|
default=True,
|
|
help='Synchronous mode for sqlite'),
|
|
cfg.StrOpt('sql_connection',
|
|
default='sqlite:///$state_path/$sqlite_db',
|
|
help='connection string for sql database'),
|
|
cfg.IntOpt('sql_idle_timeout',
|
|
default=3600,
|
|
help='timeout for idle sql database connections'),
|
|
cfg.IntOpt('sql_max_retries',
|
|
default=12,
|
|
help='sql connection attempts'),
|
|
cfg.IntOpt('sql_retry_interval',
|
|
default=10,
|
|
help='sql connection retry interval'),
|
|
cfg.StrOpt('compute_manager',
|
|
default='nova.compute.manager.ComputeManager',
|
|
help='Manager for compute'),
|
|
cfg.StrOpt('console_manager',
|
|
default='nova.console.manager.ConsoleProxyManager',
|
|
help='Manager for console proxy'),
|
|
cfg.StrOpt('cert_manager',
|
|
default='nova.cert.manager.CertManager',
|
|
help='Manager for cert'),
|
|
cfg.StrOpt('instance_dns_manager',
|
|
default='nova.network.dns_driver.DNSDriver',
|
|
help='DNS Manager for instance IPs'),
|
|
cfg.StrOpt('instance_dns_domain',
|
|
default='',
|
|
help='DNS Zone for instance IPs'),
|
|
cfg.StrOpt('floating_ip_dns_manager',
|
|
default='nova.network.dns_driver.DNSDriver',
|
|
help='DNS Manager for floating IPs'),
|
|
cfg.StrOpt('network_manager',
|
|
default='nova.network.manager.VlanManager',
|
|
help='Manager for network'),
|
|
cfg.StrOpt('volume_manager',
|
|
default='nova.volume.manager.VolumeManager',
|
|
help='Manager for volume'),
|
|
cfg.StrOpt('scheduler_manager',
|
|
default='nova.scheduler.manager.SchedulerManager',
|
|
help='Manager for scheduler'),
|
|
cfg.StrOpt('vsa_manager',
|
|
default='nova.vsa.manager.VsaManager',
|
|
help='Manager for vsa'),
|
|
cfg.StrOpt('vc_image_name',
|
|
default='vc_image',
|
|
help='the VC image ID (for a VC image that exists in Glance)'),
|
|
cfg.StrOpt('default_vsa_instance_type',
|
|
default='m1.small',
|
|
help='default instance type for VSA instances'),
|
|
cfg.IntOpt('max_vcs_in_vsa',
|
|
default=32,
|
|
help='maxinum VCs in a VSA'),
|
|
cfg.IntOpt('vsa_part_size_gb',
|
|
default=100,
|
|
help='default partition size for shared capacity'),
|
|
cfg.StrOpt('firewall_driver',
|
|
default='nova.virt.firewall.IptablesFirewallDriver',
|
|
help='Firewall driver (defaults to iptables)'),
|
|
cfg.StrOpt('image_service',
|
|
default='nova.image.glance.GlanceImageService',
|
|
help='The service to use for retrieving and searching images.'),
|
|
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.'),
|
|
cfg.StrOpt('node_availability_zone',
|
|
default='nova',
|
|
help='availability zone of this node'),
|
|
cfg.StrOpt('notification_driver',
|
|
default='nova.notifier.no_op_notifier',
|
|
help='Default driver for sending notifications'),
|
|
cfg.ListOpt('memcached_servers',
|
|
default=None,
|
|
help='Memcached servers or None for in process cache.'),
|
|
cfg.StrOpt('zone_name',
|
|
default='nova',
|
|
help='name of this zone'),
|
|
cfg.ListOpt('zone_capabilities',
|
|
default=['hypervisor=xenserver;kvm', 'os=linux;windows'],
|
|
help='Key/Multi-value list with the capabilities of the zone'),
|
|
cfg.StrOpt('build_plan_encryption_key',
|
|
default=None,
|
|
help='128bit (hex) encryption key for scheduler build plans.'),
|
|
cfg.StrOpt('instance_usage_audit_period',
|
|
default='month',
|
|
help='time period to generate instance usages for.'),
|
|
cfg.IntOpt('bandwith_poll_interval',
|
|
default=600,
|
|
help='interval to pull bandwidth usage info'),
|
|
cfg.BoolOpt('start_guests_on_host_boot',
|
|
default=False,
|
|
help='Whether to restart guests when the host reboots'),
|
|
cfg.BoolOpt('resume_guests_state_on_host_boot',
|
|
default=False,
|
|
help='Whether to start guests that were running before the '
|
|
'host rebooted'),
|
|
cfg.StrOpt('default_ephemeral_format',
|
|
default=None,
|
|
help='The default format a ephemeral_volume will be '
|
|
'formatted with on creation.'),
|
|
cfg.StrOpt('root_helper',
|
|
default='sudo',
|
|
help='Command prefix to use for running commands as root'),
|
|
cfg.StrOpt('network_driver',
|
|
default='nova.network.linux_net',
|
|
help='Driver to use for network creation'),
|
|
cfg.BoolOpt('use_ipv6',
|
|
default=False,
|
|
help='use ipv6'),
|
|
cfg.IntOpt('password_length',
|
|
default=12,
|
|
help='Length of generated instance admin passwords'),
|
|
cfg.BoolOpt('monkey_patch',
|
|
default=False,
|
|
help='Whether to log monkey patching'),
|
|
cfg.ListOpt('monkey_patch_modules',
|
|
default=[
|
|
'nova.api.ec2.cloud:nova.notifier.api.notify_decorator',
|
|
'nova.compute.api:nova.notifier.api.notify_decorator'
|
|
],
|
|
help='List of modules/decorators to monkey patch'),
|
|
cfg.BoolOpt('allow_resize_to_same_host',
|
|
default=False,
|
|
help='Allow destination machine to match source for resize. '
|
|
'Useful when testing in single-host environments.'),
|
|
cfg.StrOpt('stub_network',
|
|
default=False,
|
|
help='Stub network related code'),
|
|
cfg.IntOpt('reclaim_instance_interval',
|
|
default=0,
|
|
help='Interval in seconds for reclaiming deleted instances'),
|
|
cfg.IntOpt('zombie_instance_updated_at_window',
|
|
default=172800,
|
|
help='Number of seconds zombie instances are cleaned up.'),
|
|
cfg.IntOpt('service_down_time',
|
|
default=60,
|
|
help='maximum time since last check-in for up service'),
|
|
cfg.StrOpt('default_schedule_zone',
|
|
default=None,
|
|
help='zone to use when user doesnt specify one'),
|
|
cfg.ListOpt('isolated_images',
|
|
default=[],
|
|
help='Images to run on isolated host'),
|
|
cfg.ListOpt('isolated_hosts',
|
|
default=[],
|
|
help='Host reserved for specific images'),
|
|
]
|
|
|
|
FLAGS.add_options(global_opts)
|