summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/compat/__init__.py15
-rw-r--r--nova/compat/flagfile.py182
-rw-r--r--nova/flags.py142
-rw-r--r--nova/log.py9
-rw-r--r--nova/service.py3
-rw-r--r--nova/tests/test_compat_flagfile.py174
-rw-r--r--nova/tests/test_flags.py80
7 files changed, 464 insertions, 141 deletions
diff --git a/nova/compat/__init__.py b/nova/compat/__init__.py
new file mode 100644
index 000000000..8f085d939
--- /dev/null
+++ b/nova/compat/__init__.py
@@ -0,0 +1,15 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2012 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.
diff --git a/nova/compat/flagfile.py b/nova/compat/flagfile.py
new file mode 100644
index 000000000..8721d3485
--- /dev/null
+++ b/nova/compat/flagfile.py
@@ -0,0 +1,182 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2012 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.
+
+import contextlib
+import os
+import shutil
+import tempfile
+
+'''
+Compatibility code for handling the deprecated --flagfile option.
+
+gflags style configuration files are deprecated and will be removed in future.
+
+The code in this module transles --flagfile options into --config-file and can
+be removed when support for --flagfile is removed.
+'''
+
+
+def _get_flagfile(argp):
+ '''Parse the filename from a --flagfile argument.
+
+ The current and next arguments are passed as a 2 item list. If the
+ flagfile filename is in the next argument, the two arguments are
+ joined into the first item while the second item is set to None.
+ '''
+ i = argp[0].find('-flagfile')
+ if i < 0:
+ return None
+
+ # Accept -flagfile or -flagfile
+ if i != 0 and (i != 1 or argp[0][i] != '-'):
+ return None
+
+ i += len('-flagfile')
+ if i == len(argp[0]): # Accept [-]-flagfile foo
+ argp[0] += '=' + argp[1]
+ argp[1] = None
+
+ if argp[0][i] != '=': # Accept [-]-flagfile=foo
+ return None
+
+ return argp[0][i + 1:]
+
+
+def _open_file_for_reading(path):
+ '''Helper method which test code may stub out.'''
+ return open(path, 'r')
+
+
+def _open_fd_for_writing(fd, _path):
+ '''Helper method which test code may stub out.'''
+ return os.fdopen(fd, 'w')
+
+
+def _read_lines(flagfile):
+ '''Read a flag file, returning all lines with comments stripped.'''
+ with _open_file_for_reading(flagfile) as f:
+ lines = f.readlines()
+ ret = []
+ for l in lines:
+ if l.isspace() or l.startswith('#') or l.startswith('//'):
+ continue
+ ret.append(l.strip())
+ return ret
+
+
+def _read_flagfile(arg, next_arg, tempdir=None):
+ '''Convert a --flagfile argument to --config-file.
+
+ If the supplied argument is a --flagfile argument, read the contents
+ of the file and convert it to a .ini format config file. Return a
+ --config-file argument with the converted file.
+
+ If the flag file contains more --flagfile arguments, multiple
+ --config-file arguments will be returned.
+
+ The returned argument list may also contain None values which should
+ be filtered out later.
+ '''
+ argp = [arg, next_arg]
+ flagfile = _get_flagfile(argp)
+ if not flagfile:
+ return argp
+
+ args = _read_lines(flagfile)
+
+ #
+ # We're recursing here to convert any --flagfile arguments
+ # read from this flagfile into --config-file arguments
+ #
+ # We don't actually include those --config-file arguments
+ # in the generated config file; instead we include all those
+ # --config-file args in the final command line
+ #
+ args = _iterate_args(args, _read_flagfile, tempdir=tempdir)
+
+ config_file_args = []
+
+ (fd, tmpconf) = tempfile.mkstemp(suffix='.conf', dir=tempdir)
+
+ with _open_fd_for_writing(fd, tmpconf) as f:
+ f.write('[DEFAULT]\n')
+ for arg in args:
+ if arg.startswith('--config-file='):
+ config_file_args.append(arg)
+ continue
+ if '=' in arg:
+ f.write(arg[2:] + '\n')
+ elif arg[2:].startswith('no'):
+ f.write(arg[4:] + '=false\n')
+ else:
+ f.write(arg[2:] + '=true\n')
+
+ return ['--config-file=' + tmpconf] + argp[1:] + config_file_args
+
+
+def _iterate_args(args, iterator, **kwargs):
+ '''Run an iterator function on the supplied args list.
+
+ The iterator is passed the current arg and next arg and returns a
+ list of args. The returned args replace the suppied args in the
+ resulting args list.
+
+ The iterator will be passed None for the next arg when processing
+ the last arg.
+ '''
+ args.append(None)
+
+ ret = []
+ for i in range(len(args)):
+ if args[i] is None: # last item, or consumed file name
+ continue
+
+ modified = iterator(args[i], args[i + 1], **kwargs)
+ args[i], args[i + 1] = modified[:2]
+
+ ret.extend(modified[:1] + modified[2:]) # don't append next arg
+
+ return filter(None, ret)
+
+
+def handle_flagfiles(args, tempdir=None):
+ '''Replace --flagfile arguments with --config-file arguments.
+
+ Replace any --flagfile argument in the supplied list with a --config-file
+ argument containing a temporary config file with the contents of the flag
+ file translated to .ini format.
+
+ The tempdir argument is a directory which will be used to create temporary
+ files.
+ '''
+ return _iterate_args(args[:], _read_flagfile, tempdir=tempdir)
+
+
+@contextlib.contextmanager
+def handle_flagfiles_managed(args):
+ '''A context manager for handle_flagfiles() which removes temp files.
+
+ For use with the 'with' statement, i.e.
+
+ with handle_flagfiles_managed(args) as args:
+ # Do stuff
+ # Any temporary fils have been removed
+ '''
+ tempdir = tempfile.mkdtemp(prefix='nova-conf-')
+ try:
+ yield handle_flagfiles(args, tempdir=tempdir)
+ finally:
+ shutil.rmtree(tempdir)
diff --git a/nova/flags.py b/nova/flags.py
index 85e031d45..749bf5c5f 100644
--- a/nova/flags.py
+++ b/nova/flags.py
@@ -32,6 +32,7 @@ import sys
import gflags
+from nova.compat import flagfile
from nova.openstack.common import cfg
@@ -46,62 +47,17 @@ class FlagValues(object):
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
+ with flagfile.handle_flagfiles_managed(self._args) as args:
+ self._extra = self._conf(args)
def __call__(self, argv):
self.Reset()
@@ -152,21 +108,16 @@ class FlagValues(object):
return ret
def add_option(self, opt):
- if opt.dest in self._conf:
- return
+ self._conf.register_opt(opt)
- self._opts[opt.dest] = opt
+ def add_options(self, opts):
+ self._conf.register_opts(opts)
- 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_cli_option(self, opt):
+ self._conf.register_cli_opt(opt)
- def add_options(self, opts):
- for opt in opts:
- self.add_option(opt)
+ def add_cli_options(self, opts):
+ self._conf.register_cli_opts(opts)
FLAGS = FlagValues()
@@ -195,6 +146,55 @@ def _get_my_ip():
return "127.0.0.1"
+log_opts = [
+ cfg.BoolOpt('verbose',
+ default=False,
+ help='show debug output'),
+ cfg.StrOpt('logdir',
+ default=None,
+ help='output to a per-service log file in named directory'),
+ cfg.StrOpt('logfile',
+ default=None,
+ help='output to named file'),
+ cfg.BoolOpt('use_syslog',
+ default=False,
+ help='output to syslog'),
+ cfg.BoolOpt('use_stderr',
+ default=True,
+ help='log to standard error'),
+ ]
+
+core_opts = [
+ cfg.StrOpt('connection_type',
+ default=None,
+ help='libvirt, xenapi or fake'),
+ cfg.StrOpt('sql_connection',
+ default='sqlite:///$state_path/$sqlite_db',
+ help='connection string for sql database'),
+ cfg.StrOpt('api_paste_config',
+ default="api-paste.ini",
+ help='File name for the paste.deploy config for nova-api'),
+ 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'),
+ ]
+
+debug_opts = [
+ cfg.BoolOpt('fake_network',
+ default=False,
+ help='should we use fake network devices and addresses'),
+ cfg.BoolOpt('fake_rabbit',
+ default=False,
+ help='use a fake rabbit'),
+]
+
+FLAGS.add_cli_options(log_opts)
+FLAGS.add_cli_options(core_opts)
+FLAGS.add_cli_options(debug_opts)
+
global_opts = [
cfg.StrOpt('my_ip',
default=_get_my_ip(),
@@ -202,9 +202,6 @@ global_opts = [
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'),
@@ -253,15 +250,6 @@ global_opts = [
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'),
@@ -378,15 +366,6 @@ global_opts = [
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.'),
@@ -396,9 +375,6 @@ global_opts = [
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'),
diff --git a/nova/log.py b/nova/log.py
index 2d9ba9d62..bd3162b6c 100644
--- a/nova/log.py
+++ b/nova/log.py
@@ -76,18 +76,9 @@ log_opts = [
'eventlet.wsgi.server=WARN'
],
help='list of logger=LEVEL pairs'),
- cfg.BoolOpt('use_syslog',
- default=False,
- help='output to syslog'),
cfg.BoolOpt('publish_errors',
default=False,
help='publish error events'),
- cfg.StrOpt('logfile',
- default=None,
- help='output to named file'),
- cfg.BoolOpt('use_stderr',
- default=True,
- help='log to standard error'),
]
FLAGS = flags.FLAGS
diff --git a/nova/service.py b/nova/service.py
index 2a7625af0..5dcaf21bd 100644
--- a/nova/service.py
+++ b/nova/service.py
@@ -67,9 +67,6 @@ service_opts = [
cfg.IntOpt('metadata_listen_port',
default=8775,
help='port for metadata api to listen'),
- cfg.StrOpt('api_paste_config',
- default="api-paste.ini",
- help='File name for the paste.deploy config for nova-api'),
cfg.StrOpt('osapi_volume_listen',
default="0.0.0.0",
help='IP address for OpenStack Volume API to listen'),
diff --git a/nova/tests/test_compat_flagfile.py b/nova/tests/test_compat_flagfile.py
new file mode 100644
index 000000000..1635e8322
--- /dev/null
+++ b/nova/tests/test_compat_flagfile.py
@@ -0,0 +1,174 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2012 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.
+
+import contextlib
+import os
+import shutil
+import StringIO
+import stubout
+import textwrap
+import tempfile
+import unittest
+import uuid
+
+from nova.compat import flagfile
+
+
+class ThatLastTwoPercentCoverageTestCase(unittest.TestCase):
+
+ def test_open_file_for_reading(self):
+ with flagfile._open_file_for_reading(__file__):
+ pass
+
+ def test_open_fd_for_writing(self):
+ (fd, path) = tempfile.mkstemp()
+ try:
+ with flagfile._open_fd_for_writing(fd, None):
+ pass
+ finally:
+ os.remove(path)
+
+
+class CompatFlagfileTestCase(unittest.TestCase):
+
+ def setUp(self):
+ self.stubs = stubout.StubOutForTesting()
+ self.files = {}
+ self.tempdir = str(uuid.uuid4())
+ self.tempfiles = []
+
+ self.stubs.Set(flagfile, '_open_file_for_reading', self._fake_open)
+ self.stubs.Set(flagfile, '_open_fd_for_writing', self._fake_open)
+ self.stubs.Set(tempfile, 'mkdtemp', self._fake_mkdtemp)
+ self.stubs.Set(tempfile, 'mkstemp', self._fake_mkstemp)
+ self.stubs.Set(shutil, 'rmtree', self._fake_rmtree)
+
+ def tearDown(self):
+ self.stubs.UnsetAll()
+
+ def _fake_open(self, *args):
+ @contextlib.contextmanager
+ def managed_stringio(path):
+ if not path in self.files:
+ self.files[path] = ""
+ sio = StringIO.StringIO(textwrap.dedent(self.files[path]))
+ try:
+ yield sio
+ finally:
+ self.files[path] = sio.getvalue()
+ sio.close()
+ if len(args) == 2:
+ args = args[1:] # remove the fd arg for fdopen() case
+ return managed_stringio(args[0])
+
+ def _fake_mkstemp(self, *args, **kwargs):
+ self.assertTrue('dir' in kwargs)
+ self.assertEquals(kwargs['dir'], self.tempdir)
+ self.tempfiles.append(str(uuid.uuid4()))
+ return (None, self.tempfiles[-1])
+
+ def _fake_mkdtemp(self, *args, **kwargs):
+ return self.tempdir
+
+ def _fake_rmtree(self, path):
+ self.assertEquals(self.tempdir, path)
+ self.tempdir = None
+
+ def test_no_args(self):
+ before = []
+ after = flagfile.handle_flagfiles(before, tempdir=self.tempdir)
+ self.assertEquals(after, before)
+
+ def _do_test_empty_flagfile(self, before):
+ self.files['foo.flags'] = ''
+ after = flagfile.handle_flagfiles(before, tempdir=self.tempdir)
+ self.assertEquals(after, ['--config-file=' + self.tempfiles[-1]])
+ self.assertEquals(self.files[self.tempfiles[-1]], '[DEFAULT]\n')
+
+ def test_empty_flagfile(self):
+ self._do_test_empty_flagfile(['--flagfile=foo.flags'])
+
+ def test_empty_flagfile_separated(self):
+ self._do_test_empty_flagfile(['--flagfile', 'foo.flags'])
+
+ def test_empty_flagfile_single_hyphen(self):
+ self._do_test_empty_flagfile(['-flagfile=foo.flags'])
+
+ def test_empty_flagfile_single_hyphen_separated_separated(self):
+ self._do_test_empty_flagfile(['-flagfile', 'foo.flags'])
+
+ def test_empty_flagfile_with_other_args(self):
+ self.files['foo.flags'] = ''
+
+ before = [
+ '--foo', 'bar',
+ '--flagfile=foo.flags',
+ '--blaa=foo',
+ '--foo-flagfile',
+ '--flagfile-foo'
+ ]
+
+ after = flagfile.handle_flagfiles(before, tempdir=self.tempdir)
+
+ self.assertEquals(after, [
+ '--foo', 'bar',
+ '--config-file=' + self.tempfiles[-1],
+ '--blaa=foo',
+ '--foo-flagfile',
+ '--flagfile-foo'])
+ self.assertEquals(self.files[self.tempfiles[-1]], '[DEFAULT]\n')
+
+ def _do_test_flagfile(self, flags, conf):
+ self.files['foo.flags'] = flags
+
+ before = ['--flagfile=foo.flags']
+
+ after = flagfile.handle_flagfiles(before, tempdir=self.tempdir)
+
+ self.assertEquals(after,
+ ['--config-file=' + t
+ for t in reversed(self.tempfiles)])
+ self.assertEquals(self.files[self.tempfiles[-1]],
+ '[DEFAULT]\n' + conf)
+
+ def test_flagfile(self):
+ self._do_test_flagfile('--bar=foo', 'bar=foo\n')
+
+ def test_boolean_flag(self):
+ self._do_test_flagfile('--verbose', 'verbose=true\n')
+
+ def test_boolean_inverted_flag(self):
+ self._do_test_flagfile('--noverbose', 'verbose=false\n')
+
+ def test_flagfile_comments(self):
+ self._do_test_flagfile('--bar=foo\n#foo\n--foo=bar\n//bar',
+ 'bar=foo\nfoo=bar\n')
+
+ def test_flagfile_nested(self):
+ self.files['bar.flags'] = '--foo=bar'
+
+ self._do_test_flagfile('--flagfile=bar.flags', '')
+
+ self.assertEquals(self.files[self.tempfiles[-2]],
+ '[DEFAULT]\nfoo=bar\n')
+
+ def test_flagfile_managed(self):
+ self.files['foo.flags'] = ''
+ before = ['--flagfile=foo.flags']
+ with flagfile.handle_flagfiles_managed(before) as after:
+ self.assertEquals(after, ['--config-file=' + self.tempfiles[-1]])
+ self.assertEquals(self.files[self.tempfiles[-1]], '[DEFAULT]\n')
+ self.assertTrue(self.tempdir is None)
diff --git a/nova/tests/test_flags.py b/nova/tests/test_flags.py
index bea34007a..48aa965a9 100644
--- a/nova/tests/test_flags.py
+++ b/nova/tests/test_flags.py
@@ -30,6 +30,17 @@ FLAGS.add_option(cfg.StrOpt('flags_unittest',
default='foo',
help='for testing purposes only'))
+test_opts = [
+ cfg.StrOpt('string', default='default', help='desc'),
+ cfg.IntOpt('int', default=1, help='desc'),
+ cfg.BoolOpt('false', default=False, help='desc'),
+ cfg.BoolOpt('true', default=True, help='desc'),
+ ]
+
+float_opt = cfg.FloatOpt('float', default=6.66, help='desc')
+multistr_opt = cfg.MultiStrOpt('multi', default=['blaa'], help='desc')
+list_opt = cfg.ListOpt('list', default=['foo'], help='desc')
+
class FlagsTestCase(test.TestCase):
@@ -39,16 +50,7 @@ class FlagsTestCase(test.TestCase):
self.global_FLAGS = flags.FLAGS
def test_define(self):
- self.assert_('string' not in self.FLAGS)
- self.assert_('int' not in self.FLAGS)
- self.assert_('false' not in self.FLAGS)
- self.assert_('true' not in self.FLAGS)
-
- self.FLAGS.add_option(cfg.StrOpt('string',
- default='default', help='desc'))
- self.FLAGS.add_option(cfg.IntOpt('int', default=1, help='desc'))
- self.FLAGS.add_option(cfg.BoolOpt('false', default=False, help='desc'))
- self.FLAGS.add_option(cfg.BoolOpt('true', default=True, help='desc'))
+ self.FLAGS.add_cli_options(test_opts)
self.assert_(self.FLAGS['string'])
self.assert_(self.FLAGS['int'])
@@ -72,12 +74,12 @@ class FlagsTestCase(test.TestCase):
self.assertEqual(self.FLAGS.true, False)
def test_define_float(self):
- self.FLAGS.add_option(cfg.FloatOpt('float', default=6.66, help='desc'))
+ self.FLAGS.add_cli_options(test_opts)
+ self.FLAGS.add_option(float_opt)
self.assertEqual(self.FLAGS.float, 6.66)
def test_define_multistring(self):
- self.FLAGS.add_option(cfg.MultiStrOpt('multi',
- default=['blaa'], help='desc'))
+ self.FLAGS.add_cli_option(multistr_opt)
self.assert_(self.FLAGS['multi'])
self.assertEqual(self.FLAGS.multi, ['blaa'])
@@ -87,13 +89,8 @@ class FlagsTestCase(test.TestCase):
self.assertEqual(self.FLAGS.multi, ['foo', 'bar'])
- # Re-parse to test multistring isn't append multiple times
- self.FLAGS(argv + ['--unknown1', '--unknown2'])
- self.assertEqual(self.FLAGS.multi, ['foo', 'bar'])
-
def test_define_list(self):
- self.FLAGS.add_option(cfg.ListOpt('list',
- default=['foo'], help='desc'))
+ self.FLAGS.add_cli_option(list_opt)
self.assert_(self.FLAGS['list'])
self.assertEqual(self.FLAGS.list, ['foo'])
@@ -104,11 +101,11 @@ class FlagsTestCase(test.TestCase):
self.assertEqual(self.FLAGS.list, ['a', 'b', 'c', 'd'])
def test_error(self):
- self.FLAGS.add_option(cfg.IntOpt('error', default=1, help='desc'))
+ self.FLAGS.add_cli_option(float_opt)
- self.assertEqual(self.FLAGS.error, 1)
+ self.assertEqual(self.FLAGS.float, 6.66)
- argv = ['flags_test', '--error=foo']
+ argv = ['flags_test', '--float=foo']
self.assertRaises(exceptions.SystemExit, self.FLAGS, argv)
def test_declare(self):
@@ -133,30 +130,26 @@ class FlagsTestCase(test.TestCase):
def test_runtime_and_unknown_flags(self):
self.assert_('runtime_answer' not in self.global_FLAGS)
-
- argv = ['flags_test', '--runtime_answer=60', 'extra_arg']
- args = self.global_FLAGS(argv)
- self.assertEqual(len(args), 2)
- self.assertEqual(args[1], 'extra_arg')
-
- self.assert_('runtime_answer' not in self.global_FLAGS)
-
import nova.tests.runtime_flags
-
self.assert_('runtime_answer' in self.global_FLAGS)
- self.assertEqual(self.global_FLAGS.runtime_answer, 60)
+ self.assertEqual(self.global_FLAGS.runtime_answer, 54)
def test_long_vs_short_flags(self):
- self.global_FLAGS.add_option(cfg.StrOpt('duplicate_answer_long',
- default='val', help='desc'))
+ self.global_FLAGS.Reset()
+ self.global_FLAGS.add_cli_option(cfg.StrOpt('duplicate_answer_long',
+ default='val',
+ help='desc'))
argv = ['flags_test', '--duplicate_answer=60', 'extra_arg']
args = self.global_FLAGS(argv)
self.assert_('duplicate_answer' not in self.global_FLAGS)
self.assert_(self.global_FLAGS.duplicate_answer_long, 60)
- self.global_FLAGS.add_option(cfg.IntOpt('duplicate_answer',
- default=60, help='desc'))
+ self.global_FLAGS.Reset()
+ self.global_FLAGS.add_cli_option(cfg.IntOpt('duplicate_answer',
+ default=60,
+ help='desc'))
+ args = self.global_FLAGS(argv)
self.assertEqual(self.global_FLAGS.duplicate_answer, 60)
self.assertEqual(self.global_FLAGS.duplicate_answer_long, 'val')
@@ -182,19 +175,14 @@ class FlagsTestCase(test.TestCase):
self.assertEqual(FLAGS.FlagValuesDict()['flags_unittest'], 'foo')
def test_flagfile(self):
- self.FLAGS.add_option(cfg.StrOpt('string',
- default='default', help='desc'))
- self.FLAGS.add_option(cfg.IntOpt('int', default=1, help='desc'))
- self.FLAGS.add_option(cfg.BoolOpt('false', default=False, help='desc'))
- self.FLAGS.add_option(cfg.BoolOpt('true', default=True, help='desc'))
- self.FLAGS.add_option(cfg.MultiStrOpt('multi',
- default=['blaa'], help='desc'))
+ self.FLAGS.add_options(test_opts)
+ self.FLAGS.add_option(multistr_opt)
(fd, path) = tempfile.mkstemp(prefix='nova', suffix='.flags')
try:
os.write(fd, '--string=foo\n--int=2\n--false\n--notrue\n')
- os.write(fd, '--multi=foo\n--multi=bar\n')
+ os.write(fd, '--multi=foo\n') # FIXME(markmc): --multi=bar\n')
os.close(fd)
self.FLAGS(['flags_test', '--flagfile=' + path])
@@ -203,11 +191,11 @@ class FlagsTestCase(test.TestCase):
self.assertEqual(self.FLAGS.int, 2)
self.assertEqual(self.FLAGS.false, True)
self.assertEqual(self.FLAGS.true, False)
- self.assertEqual(self.FLAGS.multi, ['foo', 'bar'])
+ self.assertEqual(self.FLAGS.multi, ['foo']) # FIXME(markmc): 'bar'
# Re-parse to test multistring isn't append multiple times
self.FLAGS(['flags_test', '--flagfile=' + path])
- self.assertEqual(self.FLAGS.multi, ['foo', 'bar'])
+ self.assertEqual(self.FLAGS.multi, ['foo']) # FIXME(markmc): 'bar'
finally:
os.remove(path)