diff options
author | Rick Harris <rconradharris@gmail.com> | 2013-05-09 22:39:20 +0000 |
---|---|---|
committer | Rick Harris <rconradharris@gmail.com> | 2013-05-14 17:24:35 +0000 |
commit | 1b9489fb0d556a2661c299cf67ed3d26ffcb2dce (patch) | |
tree | 3a1f33a31e591daea039fb23380959db5ad8c400 | |
parent | da1d7390fea6ba8ac9eefd1a25e5c1412e624ee3 (diff) | |
download | nova-1b9489fb0d556a2661c299cf67ed3d26ffcb2dce.tar.gz nova-1b9489fb0d556a2661c299cf67ed3d26ffcb2dce.tar.xz nova-1b9489fb0d556a2661c299cf67ed3d26ffcb2dce.zip |
Use Oslo's `bool_from_string`
Oslo provides an equivalent implmentation of `bool_from_str` so we
should switch the code to use that instead.
Change-Id: I382f23af2468e276ae4342dff18cf06e1c24b755
-rw-r--r-- | nova/api/openstack/compute/contrib/disk_config.py | 4 | ||||
-rw-r--r-- | nova/api/openstack/compute/contrib/evacuate.py | 3 | ||||
-rw-r--r-- | nova/api/openstack/compute/contrib/volumes.py | 3 | ||||
-rw-r--r-- | nova/api/openstack/compute/flavors.py | 23 | ||||
-rw-r--r-- | nova/api/openstack/compute/servers.py | 10 | ||||
-rw-r--r-- | nova/compute/api.py | 3 | ||||
-rw-r--r-- | nova/compute/flavors.py | 3 | ||||
-rw-r--r-- | nova/network/manager.py | 10 | ||||
-rw-r--r-- | nova/openstack/common/strutils.py | 150 | ||||
-rw-r--r-- | nova/tests/api/openstack/compute/test_flavors.py | 34 | ||||
-rw-r--r-- | nova/tests/api/openstack/compute/test_servers.py | 4 | ||||
-rw-r--r-- | nova/tests/test_utils.py | 22 | ||||
-rw-r--r-- | nova/utils.py | 13 | ||||
-rw-r--r-- | nova/virt/xenapi/vm_utils.py | 6 | ||||
-rw-r--r-- | openstack-common.conf | 1 |
15 files changed, 223 insertions, 66 deletions
diff --git a/nova/api/openstack/compute/contrib/disk_config.py b/nova/api/openstack/compute/contrib/disk_config.py index 2c4d24332..f2b906144 100644 --- a/nova/api/openstack/compute/contrib/disk_config.py +++ b/nova/api/openstack/compute/contrib/disk_config.py @@ -21,7 +21,7 @@ from webob import exc from nova.api.openstack import extensions from nova.api.openstack import wsgi from nova.api.openstack import xmlutil -from nova import utils +from nova.openstack.common import strutils ALIAS = 'OS-DCF' XMLNS_DCF = "http://docs.openstack.org/compute/ext/disk_config/api/v1.1" @@ -65,7 +65,7 @@ class ImageDiskConfigController(wsgi.Controller): metadata = image['metadata'] if INTERNAL_DISK_CONFIG in metadata: raw_value = metadata[INTERNAL_DISK_CONFIG] - value = utils.bool_from_str(raw_value) + value = strutils.bool_from_string(raw_value) image[API_DISK_CONFIG] = disk_config_to_api(value) @wsgi.extends diff --git a/nova/api/openstack/compute/contrib/evacuate.py b/nova/api/openstack/compute/contrib/evacuate.py index 587e231d1..7eee99ed1 100644 --- a/nova/api/openstack/compute/contrib/evacuate.py +++ b/nova/api/openstack/compute/contrib/evacuate.py @@ -21,6 +21,7 @@ from nova.api.openstack import wsgi from nova import compute from nova import exception from nova.openstack.common import log as logging +from nova.openstack.common import strutils from nova import utils LOG = logging.getLogger(__name__) @@ -47,7 +48,7 @@ class Controller(wsgi.Controller): evacuate_body = body["evacuate"] host = evacuate_body["host"] - on_shared_storage = utils.bool_from_str( + on_shared_storage = strutils.bool_from_string( evacuate_body["onSharedStorage"]) password = None diff --git a/nova/api/openstack/compute/contrib/volumes.py b/nova/api/openstack/compute/contrib/volumes.py index 640ac0c76..5a8614f39 100644 --- a/nova/api/openstack/compute/contrib/volumes.py +++ b/nova/api/openstack/compute/contrib/volumes.py @@ -25,6 +25,7 @@ from nova.api.openstack import xmlutil from nova import compute from nova import exception from nova.openstack.common import log as logging +from nova.openstack.common import strutils from nova.openstack.common import uuidutils from nova import utils from nova import volume @@ -620,7 +621,7 @@ class SnapshotController(wsgi.Controller): msg = _("Invalid value '%s' for force.") % force raise exception.InvalidParameterValue(err=msg) - if utils.bool_from_str(force): + if strutils.bool_from_string(force): new_snapshot = self.volume_api.create_snapshot_force(context, vol, snapshot.get('display_name'), diff --git a/nova/api/openstack/compute/flavors.py b/nova/api/openstack/compute/flavors.py index 42b627cf4..744fe5e93 100644 --- a/nova/api/openstack/compute/flavors.py +++ b/nova/api/openstack/compute/flavors.py @@ -23,6 +23,7 @@ from nova.api.openstack import wsgi from nova.api.openstack import xmlutil from nova.compute import flavors from nova import exception +from nova.openstack.common import strutils def make_flavor(elem, detailed=False): @@ -91,25 +92,20 @@ class Controller(wsgi.Controller): return self._view_builder.show(req, flavor) - def _get_is_public(self, req): + def _parse_is_public(self, is_public): """Parse is_public into something usable.""" - is_public = req.params.get('is_public', None) if is_public is None: # preserve default value of showing only public flavors return True - elif is_public is True or \ - is_public.lower() in ['t', 'true', 'yes', '1']: - return True - elif is_public is False or \ - is_public.lower() in ['f', 'false', 'no', '0']: - return False - elif is_public.lower() == 'none': - # value to match all flavors, ignore is_public + elif is_public == 'none': return None else: - msg = _('Invalid is_public filter [%s]') % req.params['is_public'] - raise webob.exc.HTTPBadRequest(explanation=msg) + try: + return strutils.bool_from_string(is_public, strict=True) + except ValueError: + msg = _('Invalid is_public filter [%s]') % is_public + raise webob.exc.HTTPBadRequest(explanation=msg) def _get_flavors(self, req): """Helper function that returns a list of flavor dicts.""" @@ -118,7 +114,8 @@ class Controller(wsgi.Controller): context = req.environ['nova.context'] if context.is_admin: # Only admin has query access to all flavor types - filters['is_public'] = self._get_is_public(req) + filters['is_public'] = self._parse_is_public( + req.params.get('is_public', None)) else: filters['is_public'] = True filters['disabled'] = False diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 30f8e6fe8..cb3f7ad49 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -33,6 +33,7 @@ from nova import exception from nova.openstack.common import importutils from nova.openstack.common import log as logging from nova.openstack.common.rpc import common as rpc_common +from nova.openstack.common import strutils from nova.openstack.common import timeutils from nova.openstack.common import uuidutils from nova import utils @@ -185,7 +186,8 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer): res_id = server_node.getAttribute('return_reservation_id') if res_id: - server['return_reservation_id'] = utils.bool_from_str(res_id) + server['return_reservation_id'] = \ + strutils.bool_from_string(res_id) scheduler_hints = self._extract_scheduler_hints(server_node) if scheduler_hints: @@ -253,7 +255,7 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer): for attr in attributes: value = child.getAttribute(attr) if value: - mapping[attr] = utils.bool_from_str(value) + mapping[attr] = strutils.bool_from_string(value) block_device_mapping.append(mapping) return block_device_mapping else: @@ -826,7 +828,7 @@ class Controller(wsgi.Controller): for bdm in block_device_mapping: self._validate_device_name(bdm["device_name"]) if 'delete_on_termination' in bdm: - bdm['delete_on_termination'] = utils.bool_from_str( + bdm['delete_on_termination'] = strutils.bool_from_string( bdm['delete_on_termination']) ret_resv_id = False @@ -991,7 +993,7 @@ class Controller(wsgi.Controller): update_dict['access_ip_v6'] = access_ipv6.strip() if 'auto_disk_config' in body['server']: - auto_disk_config = utils.bool_from_str( + auto_disk_config = strutils.bool_from_string( body['server']['auto_disk_config']) update_dict['auto_disk_config'] = auto_disk_config diff --git a/nova/compute/api.py b/nova/compute/api.py index c56270cc3..111d87fc5 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -53,6 +53,7 @@ from nova import notifications from nova.openstack.common import excutils from nova.openstack.common import jsonutils from nova.openstack.common import log as logging +from nova.openstack.common import strutils from nova.openstack.common import timeutils from nova.openstack.common import uuidutils import nova.policy @@ -439,7 +440,7 @@ class API(base.Base): if value is not None: if prop_type == 'bool': - value = utils.bool_from_str(value) + value = strutils.bool_from_string(value) return value diff --git a/nova/compute/flavors.py b/nova/compute/flavors.py index c4ce550eb..95fac0278 100644 --- a/nova/compute/flavors.py +++ b/nova/compute/flavors.py @@ -30,6 +30,7 @@ from nova import db from nova import exception from nova.openstack.common.db import exception as db_exc from nova.openstack.common import log as logging +from nova.openstack.common import strutils from nova import utils instance_type_opts = [ @@ -130,7 +131,7 @@ def create(name, memory, vcpus, root_gb, ephemeral_gb=None, flavorid=None, if not utils.is_valid_boolstr(is_public): msg = _("is_public must be a boolean") raise exception.InvalidInput(reason=msg) - kwargs['is_public'] = utils.bool_from_str(is_public) + kwargs['is_public'] = strutils.bool_from_string(is_public) try: return db.instance_type_create(context.get_admin_context(), kwargs) diff --git a/nova/network/manager.py b/nova/network/manager.py index 54c079245..99eb619fe 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -70,6 +70,7 @@ from nova.openstack.common import lockutils from nova.openstack.common import log as logging from nova.openstack.common import periodic_task from nova.openstack.common.rpc import common as rpc_common +from nova.openstack.common import strutils from nova.openstack.common import timeutils from nova.openstack.common import uuidutils from nova import quota @@ -1030,10 +1031,11 @@ class NetworkManager(manager.Manager): else: kwargs["network_size"] = CONF.network_size - kwargs["multi_host"] = (CONF.multi_host - if kwargs["multi_host"] is None - else - utils.bool_from_str(kwargs["multi_host"])) + kwargs["multi_host"] = ( + CONF.multi_host + if kwargs["multi_host"] is None + else strutils.bool_from_string(kwargs["multi_host"])) + kwargs["vlan_start"] = kwargs.get("vlan_start") or CONF.vlan_start kwargs["vpn_start"] = kwargs.get("vpn_start") or CONF.vpn_start kwargs["dns1"] = kwargs["dns1"] or CONF.flat_network_dns diff --git a/nova/openstack/common/strutils.py b/nova/openstack/common/strutils.py new file mode 100644 index 000000000..cdf70cb20 --- /dev/null +++ b/nova/openstack/common/strutils.py @@ -0,0 +1,150 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# 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. + +""" +System-level utilities and helper functions. +""" + +import sys + +from nova.openstack.common.gettextutils import _ + + +TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes') +FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no') + + +def int_from_bool_as_string(subject): + """ + Interpret a string as a boolean and return either 1 or 0. + + Any string value in: + + ('True', 'true', 'On', 'on', '1') + + is interpreted as a boolean True. + + Useful for JSON-decoded stuff and config file parsing + """ + return bool_from_string(subject) and 1 or 0 + + +def bool_from_string(subject, strict=False): + """ + Interpret a string as a boolean. + + A case-insensitive match is performed such that strings matching 't', + 'true', 'on', 'y', 'yes', or '1' are considered True and, when + `strict=False`, anything else is considered False. + + Useful for JSON-decoded stuff and config file parsing. + + If `strict=True`, unrecognized values, including None, will raise a + ValueError which is useful when parsing values passed in from an API call. + Strings yielding False are 'f', 'false', 'off', 'n', 'no', or '0'. + """ + if not isinstance(subject, basestring): + subject = str(subject) + + lowered = subject.strip().lower() + + if lowered in TRUE_STRINGS: + return True + elif lowered in FALSE_STRINGS: + return False + elif strict: + acceptable = ', '.join( + "'%s'" % s for s in sorted(TRUE_STRINGS + FALSE_STRINGS)) + msg = _("Unrecognized value '%(val)s', acceptable values are:" + " %(acceptable)s") % {'val': subject, + 'acceptable': acceptable} + raise ValueError(msg) + else: + return False + + +def safe_decode(text, incoming=None, errors='strict'): + """ + Decodes incoming str using `incoming` if they're + not already unicode. + + :param incoming: Text's current encoding + :param errors: Errors handling policy. See here for valid + values http://docs.python.org/2/library/codecs.html + :returns: text or a unicode `incoming` encoded + representation of it. + :raises TypeError: If text is not an isntance of basestring + """ + if not isinstance(text, basestring): + raise TypeError("%s can't be decoded" % type(text)) + + if isinstance(text, unicode): + return text + + if not incoming: + incoming = (sys.stdin.encoding or + sys.getdefaultencoding()) + + try: + return text.decode(incoming, errors) + except UnicodeDecodeError: + # Note(flaper87) If we get here, it means that + # sys.stdin.encoding / sys.getdefaultencoding + # didn't return a suitable encoding to decode + # text. This happens mostly when global LANG + # var is not set correctly and there's no + # default encoding. In this case, most likely + # python will use ASCII or ANSI encoders as + # default encodings but they won't be capable + # of decoding non-ASCII characters. + # + # Also, UTF-8 is being used since it's an ASCII + # extension. + return text.decode('utf-8', errors) + + +def safe_encode(text, incoming=None, + encoding='utf-8', errors='strict'): + """ + Encodes incoming str/unicode using `encoding`. If + incoming is not specified, text is expected to + be encoded with current python's default encoding. + (`sys.getdefaultencoding`) + + :param incoming: Text's current encoding + :param encoding: Expected encoding for text (Default UTF-8) + :param errors: Errors handling policy. See here for valid + values http://docs.python.org/2/library/codecs.html + :returns: text or a bytestring `encoding` encoded + representation of it. + :raises TypeError: If text is not an isntance of basestring + """ + if not isinstance(text, basestring): + raise TypeError("%s can't be encoded" % type(text)) + + if not incoming: + incoming = (sys.stdin.encoding or + sys.getdefaultencoding()) + + if isinstance(text, unicode): + return text.encode(encoding, errors) + elif text and encoding != incoming: + # Decode text before encoding it with `encoding` + text = safe_decode(text, incoming, errors) + return text.encode(encoding, errors) + + return text diff --git a/nova/tests/api/openstack/compute/test_flavors.py b/nova/tests/api/openstack/compute/test_flavors.py index 45eeeb34b..13206b6f8 100644 --- a/nova/tests/api/openstack/compute/test_flavors.py +++ b/nova/tests/api/openstack/compute/test_flavors.py @@ -762,3 +762,37 @@ class DisabledFlavorsWithRealDBTest(test.TestCase): self.req, self.disabled_type['flavorid'])['flavor'] self.assertEqual(flavor['name'], self.disabled_type['name']) + + +class ParseIsPublicTest(test.TestCase): + def setUp(self): + super(ParseIsPublicTest, self).setUp() + self.controller = flavors.Controller() + + def assertPublic(self, expected, is_public): + self.assertIs(expected, self.controller._parse_is_public(is_public), + '%s did not return %s' % (is_public, expected)) + + def test_None(self): + self.assertPublic(True, None) + + def test_truthy(self): + self.assertPublic(True, True) + self.assertPublic(True, 't') + self.assertPublic(True, 'true') + self.assertPublic(True, 'yes') + self.assertPublic(True, '1') + + def test_falsey(self): + self.assertPublic(False, False) + self.assertPublic(False, 'f') + self.assertPublic(False, 'false') + self.assertPublic(False, 'no') + self.assertPublic(False, '0') + + def test_string_none(self): + self.assertPublic(None, 'none') + + def test_other(self): + self.assertRaises( + webob.exc.HTTPBadRequest, self.assertPublic, None, 'other') diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py index 2744d620f..5d2118564 100644 --- a/nova/tests/api/openstack/compute/test_servers.py +++ b/nova/tests/api/openstack/compute/test_servers.py @@ -2436,7 +2436,7 @@ class ServersControllerCreateTest(test.TestCase): {'device_name': 'foo3', 'delete_on_termination': 'invalid'}, {'device_name': 'foo4', 'delete_on_termination': 0}, {'device_name': 'foo5', 'delete_on_termination': False}] - expected_dbm = [ + expected_bdm = [ {'device_name': 'foo1', 'delete_on_termination': True}, {'device_name': 'foo2', 'delete_on_termination': True}, {'device_name': 'foo3', 'delete_on_termination': False}, @@ -2446,7 +2446,7 @@ class ServersControllerCreateTest(test.TestCase): old_create = compute_api.API.create def create(*args, **kwargs): - self.assertEqual(kwargs['block_device_mapping'], expected_dbm) + self.assertEqual(expected_bdm, kwargs['block_device_mapping']) return old_create(*args, **kwargs) self.stubs.Set(compute_api.API, 'create', create) diff --git a/nova/tests/test_utils.py b/nova/tests/test_utils.py index 6b7af48fc..39db03f3e 100644 --- a/nova/tests/test_utils.py +++ b/nova/tests/test_utils.py @@ -276,28 +276,6 @@ class GenericUtilsTestCase(test.TestCase): hostname = "<}\x1fh\x10e\x08l\x02l\x05o\x12!{>" self.assertEqual("hello", utils.sanitize_hostname(hostname)) - def test_bool_from_str(self): - self.assertTrue(utils.bool_from_str('1')) - self.assertTrue(utils.bool_from_str('2')) - self.assertTrue(utils.bool_from_str('-1')) - self.assertTrue(utils.bool_from_str('true')) - self.assertTrue(utils.bool_from_str('True')) - self.assertTrue(utils.bool_from_str('tRuE')) - self.assertTrue(utils.bool_from_str('yes')) - self.assertTrue(utils.bool_from_str('Yes')) - self.assertTrue(utils.bool_from_str('YeS')) - self.assertTrue(utils.bool_from_str('y')) - self.assertTrue(utils.bool_from_str('Y')) - self.assertFalse(utils.bool_from_str('False')) - self.assertFalse(utils.bool_from_str('false')) - self.assertFalse(utils.bool_from_str('no')) - self.assertFalse(utils.bool_from_str('No')) - self.assertFalse(utils.bool_from_str('n')) - self.assertFalse(utils.bool_from_str('N')) - self.assertFalse(utils.bool_from_str('0')) - self.assertFalse(utils.bool_from_str(None)) - self.assertFalse(utils.bool_from_str('junk')) - def test_read_cached_file(self): self.mox.StubOutWithMock(os.path, "getmtime") os.path.getmtime(mox.IgnoreArg()).AndReturn(1) diff --git a/nova/utils.py b/nova/utils.py index 64606f4f8..25158322d 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -655,19 +655,6 @@ def parse_server_string(server_str): return ('', '') -def bool_from_str(val): - """Convert a string representation of a bool into a bool value.""" - - if not val: - return False - try: - return True if int(val) else False - except ValueError: - return val.lower() == 'true' or \ - val.lower() == 'yes' or \ - val.lower() == 'y' - - def is_int_like(val): """Check if a value looks like an int.""" try: diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 30cee234a..4cd2b2ab5 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -45,6 +45,7 @@ from nova.image import glance from nova.openstack.common import excutils from nova.openstack.common import log as logging from nova.openstack.common import processutils +from nova.openstack.common import strutils from nova import utils from nova.virt import configdrive from nova.virt.disk import api as disk @@ -998,7 +999,7 @@ def _create_image(context, session, instance, name_label, image_id, elif cache_images == 'some': sys_meta = utils.metadata_to_dict(instance['system_metadata']) try: - cache = utils.bool_from_str(sys_meta['image_cache_in_nova']) + cache = strutils.bool_from_string(sys_meta['image_cache_in_nova']) except KeyError: cache = False elif cache_images == 'none': @@ -1091,7 +1092,8 @@ def _image_uses_bittorrent(context, instance): elif xenapi_torrent_images == 'some': sys_meta = utils.metadata_to_dict(instance['system_metadata']) try: - bittorrent = utils.bool_from_str(sys_meta['image_bittorrent']) + bittorrent = strutils.bool_from_string( + sys_meta['image_bittorrent']) except KeyError: pass elif xenapi_torrent_images == 'none': diff --git a/openstack-common.conf b/openstack-common.conf index 4412c09ac..ad48a188a 100644 --- a/openstack-common.conf +++ b/openstack-common.conf @@ -25,6 +25,7 @@ module=policy module=processutils module=rootwrap module=rpc +module=strutils module=timeutils module=uuidutils module=version |