summaryrefslogtreecommitdiffstats
path: root/openstack
diff options
context:
space:
mode:
Diffstat (limited to 'openstack')
-rwxr-xr-xopenstack/common/config/generator.py5
-rw-r--r--openstack/common/funcutils.py76
-rw-r--r--openstack/common/rootwrap/filters.py35
-rw-r--r--openstack/common/strutils.py44
4 files changed, 124 insertions, 36 deletions
diff --git a/openstack/common/config/generator.py b/openstack/common/config/generator.py
index 3f66f74..09649e7 100755
--- a/openstack/common/config/generator.py
+++ b/openstack/common/config/generator.py
@@ -56,7 +56,8 @@ OPTION_REGEX = re.compile(r"(%s)" % "|".join([STROPT, BOOLOPT, INTOPT,
MULTISTROPT]))
PY_EXT = ".py"
-BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
+BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
+ "../../../../"))
WORDWRAP_WIDTH = 60
@@ -193,7 +194,7 @@ def _sanitize_default(s):
return s.replace(BASEDIR, '')
elif s == _get_my_ip():
return '10.0.0.1'
- elif s == socket.getfqdn():
+ elif s == socket.gethostname():
return 'oslo'
elif s.strip() != s:
return '"%s"' % s
diff --git a/openstack/common/funcutils.py b/openstack/common/funcutils.py
new file mode 100644
index 0000000..b04d58f
--- /dev/null
+++ b/openstack/common/funcutils.py
@@ -0,0 +1,76 @@
+# 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.
+
+"""Utility methods for working with functions/decorators."""
+
+import inspect
+
+
+def get_wrapped_function(function):
+ """Get the method at the bottom of a stack of decorators."""
+
+ if not hasattr(function, 'func_closure') or not function.func_closure:
+ return function
+
+ def _get_wrapped_function(function):
+ if not hasattr(function, 'func_closure') or not function.func_closure:
+ return None
+
+ for closure in function.func_closure:
+ func = closure.cell_contents
+
+ deeper_func = _get_wrapped_function(func)
+ if deeper_func:
+ return deeper_func
+ elif hasattr(closure.cell_contents, '__call__'):
+ return closure.cell_contents
+
+ return _get_wrapped_function(function)
+
+
+def getcallargs(function, *args, **kwargs):
+ """This is a simplified inspect.getcallargs (2.7+).
+
+ It should be replaced when python >= 2.7 is standard.
+ """
+
+ keyed_args = {}
+ argnames, varargs, keywords, defaults = inspect.getargspec(function)
+
+ keyed_args.update(kwargs)
+
+ # NOTE(alaski) the implicit 'self' or 'cls' argument shows up in
+ # argnames but not in args or kwargs. Uses 'in' rather than '==' because
+ # some tests use 'self2'.
+ if 'self' in argnames[0] or 'cls' == argnames[0]:
+ # The function may not actually be a method or have im_self.
+ # Typically seen when it's stubbed with mox.
+ if inspect.ismethod(function) and hasattr(function, 'im_self'):
+ keyed_args[argnames[0]] = function.im_self
+ else:
+ keyed_args[argnames[0]] = None
+
+ remaining_argnames = filter(lambda x: x not in keyed_args, argnames)
+ keyed_args.update(dict(zip(remaining_argnames, args)))
+
+ if defaults:
+ num_defaults = len(defaults)
+ for argname, value in zip(argnames[-num_defaults:], defaults):
+ if argname not in keyed_args:
+ keyed_args[argname] = value
+
+ return keyed_args
diff --git a/openstack/common/rootwrap/filters.py b/openstack/common/rootwrap/filters.py
index ae7c62c..0cc55ce 100644
--- a/openstack/common/rootwrap/filters.py
+++ b/openstack/common/rootwrap/filters.py
@@ -34,7 +34,7 @@ class CommandFilter(object):
if self.real_exec is not None:
return self.real_exec
self.real_exec = ""
- if self.exec_path.startswith('/'):
+ if os.path.isabs(self.exec_path):
if os.access(self.exec_path, os.X_OK):
self.real_exec = self.exec_path
else:
@@ -164,8 +164,10 @@ class DeprecatedDnsmasqFilter(DnsmasqFilter):
class KillFilter(CommandFilter):
"""Specific filter for the kill calls.
+
1st argument is the user to run /bin/kill under
2nd argument is the location of the affected executable
+ if the argument is not absolute, it is checked against $PATH
Subsequent arguments list the accepted signals (if any)
This filter relies on /proc to accurately determine affected
@@ -194,21 +196,28 @@ class KillFilter(CommandFilter):
return False
try:
command = os.readlink("/proc/%d/exe" % int(args[1]))
- # NOTE(yufang521247): /proc/PID/exe may have '\0' on the
- # end, because python doen't stop at '\0' when read the
- # target path.
- command = command.split('\0')[0]
- # NOTE(dprince): /proc/PID/exe may have ' (deleted)' on
- # the end if an executable is updated or deleted
- if command.endswith(" (deleted)"):
- command = command[:command.rindex(" ")]
- if command != self.args[0]:
- # Affected executable does not match
- return False
except (ValueError, OSError):
# Incorrect PID
return False
- return True
+
+ # NOTE(yufang521247): /proc/PID/exe may have '\0' on the
+ # end, because python doen't stop at '\0' when read the
+ # target path.
+ command = command.partition('\0')[0]
+
+ # NOTE(dprince): /proc/PID/exe may have ' (deleted)' on
+ # the end if an executable is updated or deleted
+ if command.endswith(" (deleted)"):
+ command = command[:-len(" (deleted)")]
+
+ kill_command = self.args[0]
+
+ if os.path.isabs(kill_command):
+ return kill_command == command
+
+ return (os.path.isabs(command) and
+ kill_command == os.path.basename(command) and
+ os.path.dirname(command) in os.environ['PATH'].split(':'))
class ReadFileFilter(CommandFilter):
diff --git a/openstack/common/strutils.py b/openstack/common/strutils.py
index 05c178c..a3fb53a 100644
--- a/openstack/common/strutils.py
+++ b/openstack/common/strutils.py
@@ -35,7 +35,7 @@ BYTE_MULTIPLIERS = {
'm': 1024 ** 2,
'k': 1024,
}
-
+BYTE_REGEX = re.compile(r'(^-?\d+)(\D*)')
TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes')
FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no')
@@ -162,31 +162,33 @@ def safe_encode(text, incoming=None,
def to_bytes(text, default=0):
- """Try to turn a string into a number of bytes. Looks at the last
- characters of the text to determine what conversion is needed to
- turn the input text into a byte number.
+ """Converts a string into an integer of bytes.
+
+ Looks at the last characters of the text to determine
+ what conversion is needed to turn the input text into a byte number.
+ Supports "B, K(B), M(B), G(B), and T(B)". (case insensitive)
- Supports: B/b, K/k, M/m, G/g, T/t (or the same with b/B on the end)
+ :param text: String input for bytes size conversion.
+ :param default: Default return value when text is blank.
"""
- # Take off everything not number 'like' (which should leave
- # only the byte 'identifier' left)
- mult_key_org = text.lstrip('-1234567890')
- mult_key = mult_key_org.lower()
- mult_key_len = len(mult_key)
- if mult_key.endswith("b"):
- mult_key = mult_key[0:-1]
- try:
- multiplier = BYTE_MULTIPLIERS[mult_key]
- if mult_key_len:
- # Empty cases shouldn't cause text[0:-0]
- text = text[0:-mult_key_len]
- return int(text) * multiplier
- except KeyError:
- msg = _('Unknown byte multiplier: %s') % mult_key_org
+ match = BYTE_REGEX.search(text)
+ if match:
+ magnitude = int(match.group(1))
+ mult_key_org = match.group(2)
+ if not mult_key_org:
+ return magnitude
+ elif text:
+ msg = _('Invalid string format: %s') % text
raise TypeError(msg)
- except ValueError:
+ else:
return default
+ mult_key = mult_key_org.lower().replace('b', '', 1)
+ multiplier = BYTE_MULTIPLIERS.get(mult_key)
+ if multiplier is None:
+ msg = _('Unknown byte multiplier: %s') % mult_key_org
+ raise TypeError(msg)
+ return magnitude * multiplier
def to_slug(value, incoming=None, errors="strict"):