Merge "Deprecate the sysinv.openstack.common utils files"
This commit is contained in:
commit
fbfb03fbf9
@ -1,32 +1,23 @@
|
|||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
module=cliutils
|
|
||||||
module=config.generator
|
module=config.generator
|
||||||
module=context
|
module=context
|
||||||
module=db
|
module=db
|
||||||
module=db.sqlalchemy
|
module=db.sqlalchemy
|
||||||
module=eventlet_backdoor
|
module=eventlet_backdoor
|
||||||
module=excutils
|
|
||||||
module=fileutils
|
|
||||||
module=fixture
|
module=fixture
|
||||||
module=flakes
|
module=flakes
|
||||||
module=importutils
|
|
||||||
module=install_venv_common
|
module=install_venv_common
|
||||||
module=jsonutils
|
|
||||||
module=local
|
module=local
|
||||||
module=lockutils
|
module=lockutils
|
||||||
module=loopingcall
|
module=loopingcall
|
||||||
module=network_utils
|
|
||||||
module=notifier
|
module=notifier
|
||||||
module=patch_tox_venv
|
module=patch_tox_venv
|
||||||
module=periodic_task
|
module=periodic_task
|
||||||
module=policy
|
module=policy
|
||||||
module=processutils
|
|
||||||
module=redhat-eventlet.patch
|
module=redhat-eventlet.patch
|
||||||
module=rootwrap
|
module=rootwrap
|
||||||
module=rpc
|
module=rpc
|
||||||
module=setup
|
module=setup
|
||||||
module=strutils
|
|
||||||
module=timeutils
|
|
||||||
module=uuidutils
|
module=uuidutils
|
||||||
module=version
|
module=version
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
pbr>=0.5
|
pbr>=0.5
|
||||||
SQLAlchemy
|
SQLAlchemy
|
||||||
amqplib>=0.6.1
|
amqplib>=0.6.1
|
||||||
anyjson>=0.3.3
|
|
||||||
argparse
|
argparse
|
||||||
boto3
|
boto3
|
||||||
botocore>=1.11.0
|
botocore>=1.11.0
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import excutils
|
||||||
|
|
||||||
from sysinv.agent.lldp import manager
|
from sysinv.agent.lldp import manager
|
||||||
from sysinv.common import exception
|
from sysinv.common import exception
|
||||||
from sysinv.common import constants
|
from sysinv.common import constants
|
||||||
from sysinv.openstack.common import excutils
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import wsmeext.pecan as wsme_pecan
|
|||||||
from wsme import types as wtypes
|
from wsme import types as wtypes
|
||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
from oslo_utils import excutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv import objects
|
from sysinv import objects
|
||||||
from sysinv.api.controllers.v1 import base
|
from sysinv.api.controllers.v1 import base
|
||||||
@ -23,7 +24,6 @@ from sysinv.common import constants
|
|||||||
from sysinv.common import exception
|
from sysinv.common import exception
|
||||||
from sysinv.common import utils as cutils
|
from sysinv.common import utils as cutils
|
||||||
from sysinv.helm import common
|
from sysinv.helm import common
|
||||||
from sysinv.openstack.common import excutils
|
|
||||||
from sysinv.openstack.common.rpc import common as rpc_common
|
from sysinv.openstack.common.rpc import common as rpc_common
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
@ -26,6 +26,7 @@ from wsme import types as wtypes
|
|||||||
import wsmeext.pecan as wsme_pecan
|
import wsmeext.pecan as wsme_pecan
|
||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
from oslo_utils import excutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.api.controllers.v1 import base
|
from sysinv.api.controllers.v1 import base
|
||||||
from sysinv.api.controllers.v1 import collection
|
from sysinv.api.controllers.v1 import collection
|
||||||
@ -36,7 +37,6 @@ from sysinv.common import constants
|
|||||||
from sysinv.common import exception
|
from sysinv.common import exception
|
||||||
from sysinv.common import utils as cutils
|
from sysinv.common import utils as cutils
|
||||||
from sysinv import objects
|
from sysinv import objects
|
||||||
from sysinv.openstack.common import excutils
|
|
||||||
|
|
||||||
from fm_api import constants as fm_constants
|
from fm_api import constants as fm_constants
|
||||||
from fm_api import fm_api
|
from fm_api import fm_api
|
||||||
|
@ -19,6 +19,7 @@ from fm_api import constants as fm_constants
|
|||||||
from fm_api import fm_api
|
from fm_api import fm_api
|
||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
from oslo_utils import excutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.api.controllers.v1 import base
|
from sysinv.api.controllers.v1 import base
|
||||||
from sysinv.api.controllers.v1 import collection
|
from sysinv.api.controllers.v1 import collection
|
||||||
@ -31,7 +32,6 @@ from sysinv.common import constants
|
|||||||
from sysinv.common import service_parameter
|
from sysinv.common import service_parameter
|
||||||
from sysinv.common import exception
|
from sysinv.common import exception
|
||||||
from sysinv.common import utils as cutils
|
from sysinv.common import utils as cutils
|
||||||
from sysinv.openstack.common import excutils
|
|
||||||
from sysinv.openstack.common.rpc import common as rpc_common
|
from sysinv.openstack.common.rpc import common as rpc_common
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
@ -18,6 +18,7 @@ from wsme import types as wtypes
|
|||||||
import wsmeext.pecan as wsme_pecan
|
import wsmeext.pecan as wsme_pecan
|
||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
from oslo_utils import excutils
|
||||||
from sysinv.api.controllers.v1 import base
|
from sysinv.api.controllers.v1 import base
|
||||||
from sysinv.api.controllers.v1 import collection
|
from sysinv.api.controllers.v1 import collection
|
||||||
from sysinv.api.controllers.v1 import link
|
from sysinv.api.controllers.v1 import link
|
||||||
@ -26,7 +27,6 @@ from sysinv.api.controllers.v1 import utils as api_utils
|
|||||||
from sysinv.common import exception
|
from sysinv.common import exception
|
||||||
from sysinv.common import utils as cutils
|
from sysinv.common import utils as cutils
|
||||||
from sysinv import objects
|
from sysinv import objects
|
||||||
from sysinv.openstack.common import excutils
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -15,10 +15,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
from sysinv.openstack.common import importutils
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_utils import importutils
|
||||||
|
|
||||||
|
|
||||||
glance_opts = [
|
glance_opts = [
|
||||||
|
@ -26,12 +26,12 @@ import re
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import fileutils
|
||||||
|
from oslo_utils import strutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.common import exception
|
from sysinv.common import exception
|
||||||
from sysinv.common import image_service as service
|
from sysinv.common import image_service as service
|
||||||
from sysinv.common import utils
|
from sysinv.common import utils
|
||||||
from sysinv.openstack.common import fileutils
|
|
||||||
from sysinv.openstack.common import strutils
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ class QemuImgInfo(object):
|
|||||||
if real_size:
|
if real_size:
|
||||||
details = real_size.group(1)
|
details = real_size.group(1)
|
||||||
try:
|
try:
|
||||||
details = strutils.to_bytes(details)
|
details = strutils.string_to_bytes(details, return_int=True)
|
||||||
except (TypeError):
|
except (TypeError):
|
||||||
pass
|
pass
|
||||||
return details
|
return details
|
||||||
|
@ -63,6 +63,9 @@ from netaddr import IPAddress
|
|||||||
from netaddr import IPNetwork
|
from netaddr import IPNetwork
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
from oslo_utils import excutils
|
||||||
|
from oslo_utils import timeutils
|
||||||
from platform_util.license import license
|
from platform_util.license import license
|
||||||
from sqlalchemy.orm import exc
|
from sqlalchemy.orm import exc
|
||||||
from six.moves import http_client as httplib
|
from six.moves import http_client as httplib
|
||||||
@ -97,10 +100,7 @@ from sysinv import objects
|
|||||||
from sysinv.objects import base as objects_base
|
from sysinv.objects import base as objects_base
|
||||||
from sysinv.objects import kube_app as kubeapp_obj
|
from sysinv.objects import kube_app as kubeapp_obj
|
||||||
from sysinv.openstack.common import context as ctx
|
from sysinv.openstack.common import context as ctx
|
||||||
from sysinv.openstack.common import excutils
|
|
||||||
from sysinv.openstack.common import jsonutils
|
|
||||||
from sysinv.openstack.common import periodic_task
|
from sysinv.openstack.common import periodic_task
|
||||||
from sysinv.openstack.common import timeutils
|
|
||||||
from sysinv.openstack.common import uuidutils
|
from sysinv.openstack.common import uuidutils
|
||||||
from sysinv.puppet import common as puppet_common
|
from sysinv.puppet import common as puppet_common
|
||||||
from sysinv.puppet import puppet
|
from sysinv.puppet import puppet
|
||||||
|
@ -25,9 +25,9 @@ import netaddr
|
|||||||
import uuid
|
import uuid
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from oslo_utils import timeutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.common import constants
|
from sysinv.common import constants
|
||||||
from sysinv.openstack.common import timeutils
|
|
||||||
|
|
||||||
|
|
||||||
def datetime_or_none(dt):
|
def datetime_or_none(dt):
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
|
|
||||||
# Copyright 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 inspect
|
|
||||||
|
|
||||||
|
|
||||||
class MissingArgs(Exception):
|
|
||||||
|
|
||||||
def __init__(self, missing):
|
|
||||||
self.missing = missing
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if len(self.missing) == 1:
|
|
||||||
return "An argument is missing"
|
|
||||||
else:
|
|
||||||
return ("%(num)d arguments are missing" %
|
|
||||||
dict(num=len(self.missing)))
|
|
||||||
|
|
||||||
|
|
||||||
def validate_args(fn, *args, **kwargs):
|
|
||||||
"""Check that the supplied args are sufficient for calling a function.
|
|
||||||
|
|
||||||
>>> validate_args(lambda a: None)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
MissingArgs: An argument is missing
|
|
||||||
>>> validate_args(lambda a, b, c, d: None, 0, c=1)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
...
|
|
||||||
MissingArgs: 2 arguments are missing
|
|
||||||
|
|
||||||
:param fn: the function to check
|
|
||||||
:param arg: the positional arguments supplied
|
|
||||||
:param kwargs: the keyword arguments supplied
|
|
||||||
"""
|
|
||||||
argspec = inspect.getargspec(fn)
|
|
||||||
|
|
||||||
num_defaults = len(argspec.defaults or [])
|
|
||||||
required_args = argspec.args[:len(argspec.args) - num_defaults]
|
|
||||||
|
|
||||||
def isbound(method):
|
|
||||||
return getattr(method, 'im_self', None) is not None
|
|
||||||
|
|
||||||
if isbound(fn):
|
|
||||||
required_args.pop(0)
|
|
||||||
|
|
||||||
missing = [arg for arg in required_args if arg not in kwargs]
|
|
||||||
missing = missing[len(args):]
|
|
||||||
if missing:
|
|
||||||
raise MissingArgs(missing)
|
|
@ -29,7 +29,7 @@ import textwrap
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from sysinv.openstack.common import importutils
|
from oslo_utils import importutils
|
||||||
|
|
||||||
|
|
||||||
STROPT = "StrOpt"
|
STROPT = "StrOpt"
|
||||||
|
@ -258,9 +258,9 @@ from sqlalchemy.pool import NullPool, StaticPool
|
|||||||
from sqlalchemy.sql.expression import literal_column
|
from sqlalchemy.sql.expression import literal_column
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import timeutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common.db import exception
|
from sysinv.openstack.common.db import exception
|
||||||
from sysinv.openstack.common import timeutils
|
|
||||||
|
|
||||||
DEFAULT = 'DEFAULT'
|
DEFAULT = 'DEFAULT'
|
||||||
|
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
|
|
||||||
# Copyright 2011 OpenStack Foundation.
|
|
||||||
# Copyright 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Exception related utilities.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import contextlib
|
|
||||||
import logging
|
|
||||||
import six
|
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
from sysinv._i18n import _
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def save_and_reraise_exception():
|
|
||||||
"""Save current exception, run some code and then re-raise.
|
|
||||||
|
|
||||||
In some cases the exception context can be cleared, resulting in None
|
|
||||||
being attempted to be re-raised after an exception handler is run. This
|
|
||||||
can happen when eventlet switches greenthreads or when running an
|
|
||||||
exception handler, code raises and catches an exception. In both
|
|
||||||
cases the exception context will be cleared.
|
|
||||||
|
|
||||||
To work around this, we save the exception state, run handler code, and
|
|
||||||
then re-raise the original exception. If another exception occurs, the
|
|
||||||
saved exception is logged and the new exception is re-raised.
|
|
||||||
"""
|
|
||||||
type_, value, tb = sys.exc_info()
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
except Exception:
|
|
||||||
logging.error(_('Original exception being dropped: %s'),
|
|
||||||
traceback.format_exception(type_, value, tb))
|
|
||||||
raise
|
|
||||||
six.reraise(type_, value, tb)
|
|
@ -1,110 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
|
|
||||||
import contextlib
|
|
||||||
import errno
|
|
||||||
import os
|
|
||||||
|
|
||||||
from oslo_log import log as logging
|
|
||||||
from sysinv._i18n import _
|
|
||||||
from sysinv.openstack.common import excutils
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
_FILE_CACHE = {}
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_tree(path):
|
|
||||||
"""Create a directory (and any ancestor directories required)
|
|
||||||
|
|
||||||
:param path: Directory to create
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
os.makedirs(path)
|
|
||||||
except OSError as exc:
|
|
||||||
if exc.errno == errno.EEXIST:
|
|
||||||
if not os.path.isdir(path):
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def read_cached_file(filename, force_reload=False):
|
|
||||||
"""Read from a file if it has been modified.
|
|
||||||
|
|
||||||
:param force_reload: Whether to reload the file.
|
|
||||||
:returns: A tuple with a boolean specifying if the data is fresh
|
|
||||||
or not.
|
|
||||||
"""
|
|
||||||
global _FILE_CACHE
|
|
||||||
|
|
||||||
if force_reload and filename in _FILE_CACHE:
|
|
||||||
del _FILE_CACHE[filename]
|
|
||||||
|
|
||||||
reloaded = False
|
|
||||||
mtime = os.path.getmtime(filename)
|
|
||||||
cache_info = _FILE_CACHE.setdefault(filename, {})
|
|
||||||
|
|
||||||
if not cache_info or mtime > cache_info.get('mtime', 0):
|
|
||||||
LOG.debug(_("Reloading cached file %s") % filename)
|
|
||||||
with open(filename) as fap:
|
|
||||||
cache_info['data'] = fap.read()
|
|
||||||
cache_info['mtime'] = mtime
|
|
||||||
reloaded = True
|
|
||||||
return (reloaded, cache_info['data'])
|
|
||||||
|
|
||||||
|
|
||||||
def delete_if_exists(path):
|
|
||||||
"""Delete a file, but ignore file not found error.
|
|
||||||
|
|
||||||
:param path: File to delete
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.unlink(path)
|
|
||||||
except OSError as e:
|
|
||||||
if e.errno == errno.ENOENT:
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def remove_path_on_error(path):
|
|
||||||
"""Protect code that wants to operate on PATH atomically.
|
|
||||||
Any exception will cause PATH to be removed.
|
|
||||||
|
|
||||||
:param path: File to work with
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
except Exception:
|
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
delete_if_exists(path)
|
|
||||||
|
|
||||||
|
|
||||||
def file_open(*args, **kwargs):
|
|
||||||
"""Open file
|
|
||||||
|
|
||||||
see built-in file() documentation for more details
|
|
||||||
|
|
||||||
Note: The reason this is kept in a separate module is to easily
|
|
||||||
be able to provide a stub module that doesn't alter system
|
|
||||||
state at all (for unit tests)
|
|
||||||
"""
|
|
||||||
return file(*args, **kwargs)
|
|
@ -1,67 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Import related utilities and helper functions.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
|
|
||||||
def import_class(import_str):
|
|
||||||
"""Returns a class from a string including module and class"""
|
|
||||||
mod_str, _sep, class_str = import_str.rpartition('.')
|
|
||||||
try:
|
|
||||||
__import__(mod_str)
|
|
||||||
return getattr(sys.modules[mod_str], class_str)
|
|
||||||
except (ValueError, AttributeError):
|
|
||||||
raise ImportError('Class %s cannot be found (%s)' %
|
|
||||||
(class_str,
|
|
||||||
traceback.format_exception(*sys.exc_info())))
|
|
||||||
|
|
||||||
|
|
||||||
def import_object(import_str, *args, **kwargs):
|
|
||||||
"""Import a class and return an instance of it."""
|
|
||||||
return import_class(import_str)(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def import_object_ns(name_space, import_str, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Import a class and return an instance of it, first by trying
|
|
||||||
to find the class in a default namespace, then failing back to
|
|
||||||
a full path if not found in the default namespace.
|
|
||||||
"""
|
|
||||||
import_value = "%s.%s" % (name_space, import_str)
|
|
||||||
try:
|
|
||||||
return import_class(import_value)(*args, **kwargs)
|
|
||||||
except ImportError:
|
|
||||||
return import_class(import_str)(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def import_module(import_str):
|
|
||||||
"""Import a module."""
|
|
||||||
__import__(import_str)
|
|
||||||
return sys.modules[import_str]
|
|
||||||
|
|
||||||
|
|
||||||
def try_import(import_str, default=None):
|
|
||||||
"""Try to import a module and if it fails return default."""
|
|
||||||
try:
|
|
||||||
return import_module(import_str)
|
|
||||||
except ImportError:
|
|
||||||
return default
|
|
@ -1,169 +0,0 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
|
|
||||||
# Copyright 2010 United States Government as represented by the
|
|
||||||
# Administrator of the National Aeronautics and Space Administration.
|
|
||||||
# Copyright 2011 Justin Santa Barbara
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
'''
|
|
||||||
JSON related utilities.
|
|
||||||
|
|
||||||
This module provides a few things:
|
|
||||||
|
|
||||||
1) A handy function for getting an object down to something that can be
|
|
||||||
JSON serialized. See to_primitive().
|
|
||||||
|
|
||||||
2) Wrappers around loads() and dumps(). The dumps() wrapper will
|
|
||||||
automatically use to_primitive() for you if needed.
|
|
||||||
|
|
||||||
3) This sets up anyjson to use the loads() and dumps() wrappers if anyjson
|
|
||||||
is available.
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import functools
|
|
||||||
import inspect
|
|
||||||
import itertools
|
|
||||||
import json
|
|
||||||
|
|
||||||
import six
|
|
||||||
import six.moves.xmlrpc_client as xmlrpclib
|
|
||||||
|
|
||||||
from sysinv.openstack.common import timeutils
|
|
||||||
|
|
||||||
|
|
||||||
_nasty_type_tests = [inspect.ismodule, inspect.isclass, inspect.ismethod,
|
|
||||||
inspect.isfunction, inspect.isgeneratorfunction,
|
|
||||||
inspect.isgenerator, inspect.istraceback, inspect.isframe,
|
|
||||||
inspect.iscode, inspect.isbuiltin, inspect.isroutine,
|
|
||||||
inspect.isabstract]
|
|
||||||
|
|
||||||
_simple_types = (type(None), six.integer_types, six.string_types, bool, float)
|
|
||||||
|
|
||||||
|
|
||||||
def to_primitive(value, convert_instances=False, convert_datetime=True,
|
|
||||||
level=0, max_depth=3):
|
|
||||||
"""Convert a complex object into primitives.
|
|
||||||
|
|
||||||
Handy for JSON serialization. We can optionally handle instances,
|
|
||||||
but since this is a recursive function, we could have cyclical
|
|
||||||
data structures.
|
|
||||||
|
|
||||||
To handle cyclical data structures we could track the actual objects
|
|
||||||
visited in a set, but not all objects are hashable. Instead we just
|
|
||||||
track the depth of the object inspections and don't go too deep.
|
|
||||||
|
|
||||||
Therefore, convert_instances=True is lossy ... be aware.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# handle obvious types first - order of basic types determined by running
|
|
||||||
# full tests on nova project, resulting in the following counts:
|
|
||||||
# 572754 <type 'NoneType'>
|
|
||||||
# 460353 <type 'int'>
|
|
||||||
# 379632 <type 'unicode'>
|
|
||||||
# 274610 <type 'str'>
|
|
||||||
# 199918 <type 'dict'>
|
|
||||||
# 114200 <type 'datetime.datetime'>
|
|
||||||
# 51817 <type 'bool'>
|
|
||||||
# 26164 <type 'list'>
|
|
||||||
# 6491 <type 'float'>
|
|
||||||
# 283 <type 'tuple'>
|
|
||||||
if isinstance(value, _simple_types):
|
|
||||||
return value
|
|
||||||
|
|
||||||
if isinstance(value, datetime.datetime):
|
|
||||||
if convert_datetime:
|
|
||||||
return timeutils.strtime(value)
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
# value of itertools.count doesn't get caught by nasty_type_tests
|
|
||||||
# and results in infinite loop when list(value) is called.
|
|
||||||
if type(value) == itertools.count:
|
|
||||||
return six.text_type(value)
|
|
||||||
|
|
||||||
# FIXME(vish): Workaround for LP bug 852095. Without this workaround,
|
|
||||||
# tests that raise an exception in a mocked method that
|
|
||||||
# has a @wrap_exception with a notifier will fail. If
|
|
||||||
# we up the dependency to 0.5.4 (when it is released) we
|
|
||||||
# can remove this workaround.
|
|
||||||
if getattr(value, '__module__', None) == 'mox':
|
|
||||||
return 'mock'
|
|
||||||
|
|
||||||
if level > max_depth:
|
|
||||||
return '?'
|
|
||||||
|
|
||||||
# The try block may not be necessary after the class check above,
|
|
||||||
# but just in case ...
|
|
||||||
try:
|
|
||||||
recursive = functools.partial(to_primitive,
|
|
||||||
convert_instances=convert_instances,
|
|
||||||
convert_datetime=convert_datetime,
|
|
||||||
level=level,
|
|
||||||
max_depth=max_depth)
|
|
||||||
if isinstance(value, dict):
|
|
||||||
return dict((k, recursive(v)) for k, v in value.items())
|
|
||||||
elif isinstance(value, (list, tuple)):
|
|
||||||
return [recursive(lv) for lv in value]
|
|
||||||
|
|
||||||
# It's not clear why xmlrpclib created their own DateTime type, but
|
|
||||||
# for our purposes, make it a datetime type which is explicitly
|
|
||||||
# handled
|
|
||||||
if isinstance(value, xmlrpclib.DateTime):
|
|
||||||
value = datetime.datetime(*tuple(value.timetuple())[:6])
|
|
||||||
|
|
||||||
if convert_datetime and isinstance(value, datetime.datetime):
|
|
||||||
return timeutils.strtime(value)
|
|
||||||
elif hasattr(value, 'iteritems'):
|
|
||||||
return recursive(dict(value.items()), level=level + 1)
|
|
||||||
elif hasattr(value, 'items'):
|
|
||||||
return recursive(dict(value.items()), level=level + 1)
|
|
||||||
elif hasattr(value, '__iter__'):
|
|
||||||
return recursive(list(value))
|
|
||||||
elif convert_instances and hasattr(value, '__dict__'):
|
|
||||||
# Likely an instance of something. Watch for cycles.
|
|
||||||
# Ignore class member vars.
|
|
||||||
return recursive(value.__dict__, level=level + 1)
|
|
||||||
else:
|
|
||||||
if any(test(value) for test in _nasty_type_tests):
|
|
||||||
return six.text_type(value)
|
|
||||||
return value
|
|
||||||
except TypeError:
|
|
||||||
# Class objects are tricky since they may define something like
|
|
||||||
# __iter__ defined but it isn't callable as list().
|
|
||||||
return six.text_type(value)
|
|
||||||
|
|
||||||
|
|
||||||
def dumps(value, default=to_primitive, **kwargs):
|
|
||||||
return json.dumps(value, default=default, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def loads(s):
|
|
||||||
return json.loads(s)
|
|
||||||
|
|
||||||
|
|
||||||
def load(s):
|
|
||||||
return json.load(s)
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
import anyjson
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
anyjson._modules.append((__name__, 'dumps', TypeError,
|
|
||||||
'loads', ValueError, 'load'))
|
|
||||||
anyjson.force_implementation(__name__)
|
|
@ -28,8 +28,8 @@ from eventlet import semaphore
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import fileutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common import fileutils
|
|
||||||
from sysinv.openstack.common import local
|
from sysinv.openstack.common import local
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
@ -23,8 +23,8 @@ from eventlet import event
|
|||||||
from eventlet import greenthread
|
from eventlet import greenthread
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import timeutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common import timeutils
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
|
|
||||||
# Copyright 2012 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Network-related utilities and helper functions.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from oslo_log import log as logging
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_host_port(address, default_port=None):
|
|
||||||
"""
|
|
||||||
Interpret a string as a host:port pair.
|
|
||||||
An IPv6 address MUST be escaped if accompanied by a port,
|
|
||||||
because otherwise ambiguity ensues: 2001:db8:85a3::8a2e:370:7334
|
|
||||||
means both [2001:db8:85a3::8a2e:370:7334] and
|
|
||||||
[2001:db8:85a3::8a2e:370]:7334.
|
|
||||||
|
|
||||||
>>> parse_host_port('server01:80')
|
|
||||||
('server01', 80)
|
|
||||||
>>> parse_host_port('server01')
|
|
||||||
('server01', None)
|
|
||||||
>>> parse_host_port('server01', default_port=1234)
|
|
||||||
('server01', 1234)
|
|
||||||
>>> parse_host_port('[::1]:80')
|
|
||||||
('::1', 80)
|
|
||||||
>>> parse_host_port('[::1]')
|
|
||||||
('::1', None)
|
|
||||||
>>> parse_host_port('[::1]', default_port=1234)
|
|
||||||
('::1', 1234)
|
|
||||||
>>> parse_host_port('2001:db8:85a3::8a2e:370:7334', default_port=1234)
|
|
||||||
('2001:db8:85a3::8a2e:370:7334', 1234)
|
|
||||||
|
|
||||||
"""
|
|
||||||
if address[0] == '[':
|
|
||||||
# Escaped ipv6
|
|
||||||
_host, _port = address[1:].split(']')
|
|
||||||
host = _host
|
|
||||||
if ':' in _port:
|
|
||||||
port = _port.split(':')[1]
|
|
||||||
else:
|
|
||||||
port = default_port
|
|
||||||
else:
|
|
||||||
if address.count(':') == 1:
|
|
||||||
host, port = address.split(':')
|
|
||||||
else:
|
|
||||||
# 0 means ipv4, >1 means ipv6.
|
|
||||||
# We prohibit unescaped ipv6 addresses with port.
|
|
||||||
host = address
|
|
||||||
port = default_port
|
|
||||||
|
|
||||||
return (host, None if port is None else int(port))
|
|
@ -18,11 +18,11 @@ import six
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
from oslo_utils import importutils
|
||||||
|
from oslo_utils import timeutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common import context
|
from sysinv.openstack.common import context
|
||||||
from sysinv.openstack.common import importutils
|
|
||||||
from sysinv.openstack.common import jsonutils
|
|
||||||
from sysinv.openstack.common import timeutils
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from sysinv.openstack.common import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ import time
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import timeutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common import timeutils
|
|
||||||
|
|
||||||
periodic_opts = [
|
periodic_opts = [
|
||||||
cfg.BoolOpt('run_external_periodic_tasks',
|
cfg.BoolOpt('run_external_periodic_tasks',
|
||||||
|
@ -58,14 +58,12 @@ as it allows particular rules to be explicitly disabled.
|
|||||||
|
|
||||||
import abc
|
import abc
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from six.moves.urllib.parse import urlencode
|
from six.moves.urllib.parse import urlencode
|
||||||
from six.moves.urllib.request import urlopen
|
from six.moves.urllib.request import urlopen
|
||||||
from sysinv.openstack.common import jsonutils
|
|
||||||
from oslo_log import log as logging
|
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -1,246 +0,0 @@
|
|||||||
# 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 os
|
|
||||||
import random
|
|
||||||
import shlex
|
|
||||||
import signal
|
|
||||||
|
|
||||||
from eventlet.green import subprocess
|
|
||||||
from eventlet import greenthread
|
|
||||||
|
|
||||||
from oslo_log import log as logging
|
|
||||||
from sysinv._i18n import _
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidArgumentError(Exception):
|
|
||||||
def __init__(self, message=None):
|
|
||||||
super(InvalidArgumentError, self).__init__(message)
|
|
||||||
|
|
||||||
|
|
||||||
class UnknownArgumentError(Exception):
|
|
||||||
def __init__(self, message=None):
|
|
||||||
super(UnknownArgumentError, self).__init__(message)
|
|
||||||
|
|
||||||
|
|
||||||
class ProcessExecutionError(Exception):
|
|
||||||
def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
|
|
||||||
description=None):
|
|
||||||
self.exit_code = exit_code
|
|
||||||
self.stderr = stderr
|
|
||||||
self.stdout = stdout
|
|
||||||
self.cmd = cmd
|
|
||||||
self.description = description
|
|
||||||
|
|
||||||
if description is None:
|
|
||||||
description = "Unexpected error while running command."
|
|
||||||
if exit_code is None:
|
|
||||||
exit_code = '-'
|
|
||||||
message = ("%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r"
|
|
||||||
% (description, cmd, exit_code, stdout, stderr))
|
|
||||||
super(ProcessExecutionError, self).__init__(message)
|
|
||||||
|
|
||||||
|
|
||||||
class NoRootWrapSpecified(Exception):
|
|
||||||
def __init__(self, message=None):
|
|
||||||
super(NoRootWrapSpecified, self).__init__(message)
|
|
||||||
|
|
||||||
|
|
||||||
def _subprocess_setup():
|
|
||||||
# Python installs a SIGPIPE handler by default. This is usually not what
|
|
||||||
# non-Python subprocesses expect.
|
|
||||||
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
|
||||||
|
|
||||||
|
|
||||||
def execute(*cmd, **kwargs):
|
|
||||||
"""
|
|
||||||
Helper method to shell out and execute a command through subprocess with
|
|
||||||
optional retry.
|
|
||||||
|
|
||||||
:param cmd: Passed to subprocess.Popen.
|
|
||||||
:type cmd: string
|
|
||||||
:param process_input: Send to opened process.
|
|
||||||
:type proces_input: string
|
|
||||||
:param check_exit_code: Single bool, int, or list of allowed exit
|
|
||||||
codes. Defaults to [0]. Raise
|
|
||||||
:class:`ProcessExecutionError` unless
|
|
||||||
program exits with one of these code.
|
|
||||||
:type check_exit_code: boolean, int, or [int]
|
|
||||||
:param delay_on_retry: True | False. Defaults to True. If set to True,
|
|
||||||
wait a short amount of time before retrying.
|
|
||||||
:type delay_on_retry: boolean
|
|
||||||
:param attempts: How many times to retry cmd.
|
|
||||||
:type attempts: int
|
|
||||||
:param run_as_root: True | False. Defaults to False. If set to True,
|
|
||||||
the command is prefixed by the command specified
|
|
||||||
in the root_helper kwarg.
|
|
||||||
:type run_as_root: boolean
|
|
||||||
:param root_helper: command to prefix to commands called with
|
|
||||||
run_as_root=True
|
|
||||||
:type root_helper: string
|
|
||||||
:param shell: whether or not there should be a shell used to
|
|
||||||
execute this command. Defaults to false.
|
|
||||||
:type shell: boolean
|
|
||||||
:returns: (stdout, stderr) from process execution
|
|
||||||
:raises: :class:`UnknownArgumentError` on
|
|
||||||
receiving unknown arguments
|
|
||||||
:raises: :class:`ProcessExecutionError`
|
|
||||||
"""
|
|
||||||
|
|
||||||
process_input = kwargs.pop('process_input', None)
|
|
||||||
check_exit_code = kwargs.pop('check_exit_code', [0])
|
|
||||||
ignore_exit_code = False
|
|
||||||
delay_on_retry = kwargs.pop('delay_on_retry', True)
|
|
||||||
attempts = kwargs.pop('attempts', 1)
|
|
||||||
run_as_root = kwargs.pop('run_as_root', False)
|
|
||||||
root_helper = kwargs.pop('root_helper', '')
|
|
||||||
shell = kwargs.pop('shell', False)
|
|
||||||
|
|
||||||
if isinstance(check_exit_code, bool):
|
|
||||||
ignore_exit_code = not check_exit_code
|
|
||||||
check_exit_code = [0]
|
|
||||||
elif isinstance(check_exit_code, int):
|
|
||||||
check_exit_code = [check_exit_code]
|
|
||||||
|
|
||||||
if kwargs:
|
|
||||||
raise UnknownArgumentError(_('Got unknown keyword args '
|
|
||||||
'to utils.execute: %r') % kwargs)
|
|
||||||
|
|
||||||
if run_as_root and os.geteuid() != 0:
|
|
||||||
if not root_helper:
|
|
||||||
raise NoRootWrapSpecified(
|
|
||||||
message=('Command requested root, but did not specify a root '
|
|
||||||
'helper.'))
|
|
||||||
cmd = shlex.split(root_helper) + list(cmd)
|
|
||||||
|
|
||||||
cmd = [str(c) for c in cmd]
|
|
||||||
|
|
||||||
while attempts > 0:
|
|
||||||
attempts -= 1
|
|
||||||
try:
|
|
||||||
LOG.debug(_('Running cmd (subprocess): %s'), ' '.join(cmd))
|
|
||||||
_PIPE = subprocess.PIPE # pylint: disable=E1101
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
preexec_fn = None
|
|
||||||
close_fds = False
|
|
||||||
else:
|
|
||||||
preexec_fn = _subprocess_setup
|
|
||||||
close_fds = True
|
|
||||||
|
|
||||||
obj = subprocess.Popen(cmd,
|
|
||||||
stdin=_PIPE,
|
|
||||||
stdout=_PIPE,
|
|
||||||
stderr=_PIPE,
|
|
||||||
close_fds=close_fds,
|
|
||||||
preexec_fn=preexec_fn,
|
|
||||||
shell=shell)
|
|
||||||
result = None
|
|
||||||
if process_input is not None:
|
|
||||||
result = obj.communicate(process_input)
|
|
||||||
else:
|
|
||||||
result = obj.communicate()
|
|
||||||
obj.stdin.close() # pylint: disable=E1101
|
|
||||||
_returncode = obj.returncode # pylint: disable=E1101
|
|
||||||
if _returncode:
|
|
||||||
LOG.debug(_('Result was %s') % _returncode)
|
|
||||||
if not ignore_exit_code and _returncode not in check_exit_code:
|
|
||||||
(stdout, stderr) = result
|
|
||||||
raise ProcessExecutionError(exit_code=_returncode,
|
|
||||||
stdout=stdout,
|
|
||||||
stderr=stderr,
|
|
||||||
cmd=' '.join(cmd))
|
|
||||||
return result
|
|
||||||
except ProcessExecutionError:
|
|
||||||
if not attempts:
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
LOG.debug(_('%r failed. Retrying.'), cmd)
|
|
||||||
if delay_on_retry:
|
|
||||||
greenthread.sleep(random.randint(20, 200) / 100.0)
|
|
||||||
finally:
|
|
||||||
# NOTE(termie): this appears to be necessary to let the subprocess
|
|
||||||
# call clean something up in between calls, without
|
|
||||||
# it two execute calls in a row hangs the second one
|
|
||||||
greenthread.sleep(0)
|
|
||||||
|
|
||||||
|
|
||||||
def trycmd(*args, **kwargs):
|
|
||||||
"""
|
|
||||||
A wrapper around execute() to more easily handle warnings and errors.
|
|
||||||
|
|
||||||
Returns an (out, err) tuple of strings containing the output of
|
|
||||||
the command's stdout and stderr. If 'err' is not empty then the
|
|
||||||
command can be considered to have failed.
|
|
||||||
|
|
||||||
:discard_warnings True | False. Defaults to False. If set to True,
|
|
||||||
then for succeeding commands, stderr is cleared
|
|
||||||
|
|
||||||
"""
|
|
||||||
discard_warnings = kwargs.pop('discard_warnings', False)
|
|
||||||
|
|
||||||
try:
|
|
||||||
out, err = execute(*args, **kwargs)
|
|
||||||
failed = False
|
|
||||||
except ProcessExecutionError as exn:
|
|
||||||
out, err = '', str(exn)
|
|
||||||
failed = True
|
|
||||||
|
|
||||||
if not failed and discard_warnings and err:
|
|
||||||
# Handle commands that output to stderr but otherwise succeed
|
|
||||||
err = ''
|
|
||||||
|
|
||||||
return out, err
|
|
||||||
|
|
||||||
|
|
||||||
def ssh_execute(ssh, cmd, process_input=None,
|
|
||||||
addl_env=None, check_exit_code=True):
|
|
||||||
LOG.debug(_('Running cmd (SSH): %s'), cmd)
|
|
||||||
if addl_env:
|
|
||||||
raise InvalidArgumentError(_('Environment not supported over SSH'))
|
|
||||||
|
|
||||||
if process_input:
|
|
||||||
# This is (probably) fixable if we need it...
|
|
||||||
raise InvalidArgumentError(_('process_input not supported over SSH'))
|
|
||||||
|
|
||||||
stdin_stream, stdout_stream, stderr_stream = ssh.exec_command(cmd)
|
|
||||||
channel = stdout_stream.channel
|
|
||||||
|
|
||||||
# NOTE(justinsb): This seems suspicious...
|
|
||||||
# ...other SSH clients have buffering issues with this approach
|
|
||||||
stdout = stdout_stream.read()
|
|
||||||
stderr = stderr_stream.read()
|
|
||||||
stdin_stream.close()
|
|
||||||
|
|
||||||
exit_status = channel.recv_exit_status()
|
|
||||||
|
|
||||||
# exit_status == -1 if no exit code was returned
|
|
||||||
if exit_status != -1:
|
|
||||||
LOG.debug(_('Result was %s') % exit_status)
|
|
||||||
if check_exit_code and exit_status != 0:
|
|
||||||
raise ProcessExecutionError(exit_code=exit_status,
|
|
||||||
stdout=stdout,
|
|
||||||
stderr=stderr,
|
|
||||||
cmd=cmd)
|
|
||||||
|
|
||||||
return (stdout, stderr)
|
|
@ -29,8 +29,8 @@ import inspect
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import importutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common import importutils
|
|
||||||
from sysinv.openstack.common import local
|
from sysinv.openstack.common import local
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
@ -39,8 +39,8 @@ from eventlet import semaphore
|
|||||||
# option is removed.
|
# option is removed.
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import excutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common import excutils
|
|
||||||
from sysinv.openstack.common import local
|
from sysinv.openstack.common import local
|
||||||
from sysinv.openstack.common.rpc import common as rpc_common
|
from sysinv.openstack.common.rpc import common as rpc_common
|
||||||
|
|
||||||
|
@ -24,9 +24,9 @@ import traceback
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
from oslo_utils import importutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common import importutils
|
|
||||||
from sysinv.openstack.common import jsonutils
|
|
||||||
from sysinv.openstack.common import local
|
from sysinv.openstack.common import local
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
@ -30,8 +30,8 @@ import kombu.entity
|
|||||||
import kombu.messaging
|
import kombu.messaging
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_utils import netutils as network_utils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common import network_utils
|
|
||||||
from sysinv.openstack.common.rpc import amqp as rpc_amqp
|
from sysinv.openstack.common.rpc import amqp as rpc_amqp
|
||||||
from sysinv.openstack.common.rpc import common as rpc_common
|
from sysinv.openstack.common.rpc import common as rpc_common
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@ import greenlet
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
from oslo_utils import importutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common import importutils
|
|
||||||
from sysinv.openstack.common import jsonutils
|
|
||||||
from sysinv.openstack.common.rpc import amqp as rpc_amqp
|
from sysinv.openstack.common.rpc import amqp as rpc_amqp
|
||||||
from sysinv.openstack.common.rpc import common as rpc_common
|
from sysinv.openstack.common.rpc import common as rpc_common
|
||||||
|
|
||||||
|
@ -32,8 +32,8 @@ from eventlet import event
|
|||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import importutils
|
||||||
from sysinv._i18n import _
|
from sysinv._i18n import _
|
||||||
from sysinv.openstack.common import importutils
|
|
||||||
from sysinv.openstack.common import threadgroup
|
from sysinv.openstack.common import threadgroup
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,217 +0,0 @@
|
|||||||
# 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 re
|
|
||||||
import six
|
|
||||||
import sys
|
|
||||||
import unicodedata
|
|
||||||
|
|
||||||
from sysinv._i18n import _
|
|
||||||
|
|
||||||
|
|
||||||
# Used for looking up extensions of text
|
|
||||||
# to their 'multiplied' byte amount
|
|
||||||
BYTE_MULTIPLIERS = {
|
|
||||||
'': 1,
|
|
||||||
't': 1024 ** 4,
|
|
||||||
'g': 1024 ** 3,
|
|
||||||
'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')
|
|
||||||
|
|
||||||
SLUGIFY_STRIP_RE = re.compile(r"[^\w\s-]")
|
|
||||||
SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+")
|
|
||||||
|
|
||||||
|
|
||||||
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, six.string_types):
|
|
||||||
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 str
|
|
||||||
"""
|
|
||||||
if not isinstance(text, six.string_types):
|
|
||||||
raise TypeError("%s can't be decoded" % type(text))
|
|
||||||
|
|
||||||
if isinstance(text, six.text_type):
|
|
||||||
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 str
|
|
||||||
"""
|
|
||||||
if not isinstance(text, six.string_types):
|
|
||||||
raise TypeError("%s can't be encoded" % type(text))
|
|
||||||
|
|
||||||
if not incoming:
|
|
||||||
incoming = (sys.stdin.encoding or
|
|
||||||
sys.getdefaultencoding())
|
|
||||||
|
|
||||||
if isinstance(text, six.text_type):
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def to_bytes(text, default=0):
|
|
||||||
"""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)
|
|
||||||
|
|
||||||
:param text: String input for bytes size conversion.
|
|
||||||
:param default: Default return value when text is blank.
|
|
||||||
|
|
||||||
"""
|
|
||||||
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)
|
|
||||||
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"):
|
|
||||||
"""Normalize string.
|
|
||||||
|
|
||||||
Convert to lowercase, remove non-word characters, and convert spaces
|
|
||||||
to hyphens.
|
|
||||||
|
|
||||||
Inspired by Django's `slugify` filter.
|
|
||||||
|
|
||||||
:param value: Text to slugify
|
|
||||||
: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: slugified unicode representation of `value`
|
|
||||||
:raises TypeError: If text is not an instance of str
|
|
||||||
"""
|
|
||||||
value = safe_decode(value, incoming, errors)
|
|
||||||
# NOTE(aababilov): no need to use safe_(encode|decode) here:
|
|
||||||
# encodings are always "ascii", error handling is always "ignore"
|
|
||||||
# and types are always known (first: unicode; second: str)
|
|
||||||
value = unicodedata.normalize("NFKD", value).encode(
|
|
||||||
"ascii", "ignore").decode("ascii")
|
|
||||||
value = SLUGIFY_STRIP_RE.sub("", value).strip().lower()
|
|
||||||
return SLUGIFY_HYPHENATE_RE.sub("-", value)
|
|
@ -1,187 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Time related utilities and helper functions.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import calendar
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
import iso8601
|
|
||||||
import six
|
|
||||||
|
|
||||||
|
|
||||||
# ISO 8601 extended time format with microseconds
|
|
||||||
_ISO8601_TIME_FORMAT_SUBSECOND = '%Y-%m-%dT%H:%M:%S.%f'
|
|
||||||
_ISO8601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S'
|
|
||||||
PERFECT_TIME_FORMAT = _ISO8601_TIME_FORMAT_SUBSECOND
|
|
||||||
|
|
||||||
|
|
||||||
def isotime(at=None, subsecond=False):
|
|
||||||
"""Stringify time in ISO 8601 format"""
|
|
||||||
if not at:
|
|
||||||
at = utcnow()
|
|
||||||
st = at.strftime(_ISO8601_TIME_FORMAT
|
|
||||||
if not subsecond
|
|
||||||
else _ISO8601_TIME_FORMAT_SUBSECOND)
|
|
||||||
tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC'
|
|
||||||
st += ('Z' if tz == 'UTC' else tz)
|
|
||||||
return st
|
|
||||||
|
|
||||||
|
|
||||||
def parse_isotime(timestr):
|
|
||||||
"""Parse time from ISO 8601 format"""
|
|
||||||
try:
|
|
||||||
return iso8601.parse_date(timestr)
|
|
||||||
except iso8601.ParseError as e:
|
|
||||||
raise ValueError(str(e))
|
|
||||||
except TypeError as e:
|
|
||||||
raise ValueError(str(e))
|
|
||||||
|
|
||||||
|
|
||||||
def strtime(at=None, fmt=PERFECT_TIME_FORMAT):
|
|
||||||
"""Returns formatted utcnow."""
|
|
||||||
if not at:
|
|
||||||
at = utcnow()
|
|
||||||
return at.strftime(fmt)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_strtime(timestr, fmt=PERFECT_TIME_FORMAT):
|
|
||||||
"""Turn a formatted time back into a datetime."""
|
|
||||||
return datetime.datetime.strptime(timestr, fmt)
|
|
||||||
|
|
||||||
|
|
||||||
def normalize_time(timestamp):
|
|
||||||
"""Normalize time in arbitrary timezone to UTC naive object"""
|
|
||||||
offset = timestamp.utcoffset()
|
|
||||||
if offset is None:
|
|
||||||
return timestamp
|
|
||||||
return timestamp.replace(tzinfo=None) - offset
|
|
||||||
|
|
||||||
|
|
||||||
def is_older_than(before, seconds):
|
|
||||||
"""Return True if before is older than seconds."""
|
|
||||||
if isinstance(before, six.string_types):
|
|
||||||
before = parse_strtime(before).replace(tzinfo=None)
|
|
||||||
return utcnow() - before > datetime.timedelta(seconds=seconds)
|
|
||||||
|
|
||||||
|
|
||||||
def is_newer_than(after, seconds):
|
|
||||||
"""Return True if after is newer than seconds."""
|
|
||||||
if isinstance(after, six.string_types):
|
|
||||||
after = parse_strtime(after).replace(tzinfo=None)
|
|
||||||
return after - utcnow() > datetime.timedelta(seconds=seconds)
|
|
||||||
|
|
||||||
|
|
||||||
def utcnow_ts():
|
|
||||||
"""Timestamp version of our utcnow function."""
|
|
||||||
return calendar.timegm(utcnow().timetuple())
|
|
||||||
|
|
||||||
|
|
||||||
def utcnow():
|
|
||||||
"""Overridable version of utils.utcnow."""
|
|
||||||
if utcnow.override_time:
|
|
||||||
try:
|
|
||||||
return utcnow.override_time.pop(0)
|
|
||||||
except AttributeError:
|
|
||||||
return utcnow.override_time
|
|
||||||
return datetime.datetime.utcnow()
|
|
||||||
|
|
||||||
|
|
||||||
def iso8601_from_timestamp(timestamp):
|
|
||||||
"""Returns a iso8601 formated date from timestamp"""
|
|
||||||
return isotime(datetime.datetime.utcfromtimestamp(timestamp))
|
|
||||||
|
|
||||||
|
|
||||||
utcnow.override_time = None
|
|
||||||
|
|
||||||
|
|
||||||
def set_time_override(override_time=datetime.datetime.utcnow()):
|
|
||||||
"""
|
|
||||||
Override utils.utcnow to return a constant time or a list thereof,
|
|
||||||
one at a time.
|
|
||||||
"""
|
|
||||||
utcnow.override_time = override_time
|
|
||||||
|
|
||||||
|
|
||||||
def advance_time_delta(timedelta):
|
|
||||||
"""Advance overridden time using a datetime.timedelta."""
|
|
||||||
assert(utcnow.override_time is not None)
|
|
||||||
try:
|
|
||||||
for dt in utcnow.override_time:
|
|
||||||
dt += timedelta
|
|
||||||
except TypeError:
|
|
||||||
utcnow.override_time += timedelta
|
|
||||||
|
|
||||||
|
|
||||||
def advance_time_seconds(seconds):
|
|
||||||
"""Advance overridden time by seconds."""
|
|
||||||
advance_time_delta(datetime.timedelta(0, seconds))
|
|
||||||
|
|
||||||
|
|
||||||
def clear_time_override():
|
|
||||||
"""Remove the overridden time."""
|
|
||||||
utcnow.override_time = None
|
|
||||||
|
|
||||||
|
|
||||||
def marshall_now(now=None):
|
|
||||||
"""Make an rpc-safe datetime with microseconds.
|
|
||||||
|
|
||||||
Note: tzinfo is stripped, but not required for relative times."""
|
|
||||||
if not now:
|
|
||||||
now = utcnow()
|
|
||||||
return dict(day=now.day, month=now.month, year=now.year, hour=now.hour,
|
|
||||||
minute=now.minute, second=now.second,
|
|
||||||
microsecond=now.microsecond)
|
|
||||||
|
|
||||||
|
|
||||||
def unmarshall_time(tyme):
|
|
||||||
"""Unmarshall a datetime dict."""
|
|
||||||
return datetime.datetime(day=tyme['day'],
|
|
||||||
month=tyme['month'],
|
|
||||||
year=tyme['year'],
|
|
||||||
hour=tyme['hour'],
|
|
||||||
minute=tyme['minute'],
|
|
||||||
second=tyme['second'],
|
|
||||||
microsecond=tyme['microsecond'])
|
|
||||||
|
|
||||||
|
|
||||||
def delta_seconds(before, after):
|
|
||||||
"""
|
|
||||||
Compute the difference in seconds between two date, time, or
|
|
||||||
datetime objects (as a float, to microsecond resolution).
|
|
||||||
"""
|
|
||||||
delta = after - before
|
|
||||||
try:
|
|
||||||
return delta.total_seconds()
|
|
||||||
except AttributeError:
|
|
||||||
return ((delta.days * 24 * 3600) + delta.seconds +
|
|
||||||
float(delta.microseconds) / (10 ** 6))
|
|
||||||
|
|
||||||
|
|
||||||
def is_soon(dt, window):
|
|
||||||
"""
|
|
||||||
Determines if time is going to happen in the next window seconds.
|
|
||||||
|
|
||||||
:params dt: the time
|
|
||||||
:params window: minimum seconds to remain to consider the time not soon
|
|
||||||
|
|
||||||
:return: True if expiration is within the given duration
|
|
||||||
"""
|
|
||||||
soon = (utcnow() + datetime.timedelta(seconds=window))
|
|
||||||
return normalize_time(dt) <= soon
|
|
@ -36,13 +36,14 @@ import testtools
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_db.sqlalchemy import enginefacade
|
from oslo_db.sqlalchemy import enginefacade
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import timeutils
|
||||||
|
|
||||||
from sysinv.common import paths
|
from sysinv.common import paths
|
||||||
from sysinv.db import api as dbapi
|
from sysinv.db import api as dbapi
|
||||||
from sysinv.db import migration
|
from sysinv.db import migration
|
||||||
import sysinv.helm.utils
|
import sysinv.helm.utils
|
||||||
from sysinv.objects import base as objects_base
|
from sysinv.objects import base as objects_base
|
||||||
from sysinv.openstack.common.fixture import moxstubout
|
from sysinv.openstack.common.fixture import moxstubout
|
||||||
from sysinv.openstack.common import timeutils
|
|
||||||
from sysinv.tests import conf_fixture
|
from sysinv.tests import conf_fixture
|
||||||
from sysinv.tests import policy_fixture
|
from sysinv.tests import policy_fixture
|
||||||
|
|
||||||
|
@ -24,11 +24,11 @@ Unit Tests for :py:class:`sysinv.conductor.rpcapi.ConductorAPI`.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_serialization import jsonutils as json
|
||||||
|
|
||||||
from sysinv.conductor import rpcapi as conductor_rpcapi
|
from sysinv.conductor import rpcapi as conductor_rpcapi
|
||||||
from sysinv.db import api as dbapi
|
from sysinv.db import api as dbapi
|
||||||
from sysinv.openstack.common import context
|
from sysinv.openstack.common import context
|
||||||
from sysinv.openstack.common import jsonutils as json
|
|
||||||
from sysinv.openstack.common import rpc
|
from sysinv.openstack.common import rpc
|
||||||
from sysinv.tests.db import base
|
from sysinv.tests.db import base
|
||||||
from sysinv.tests.db import utils as dbutils
|
from sysinv.tests.db import utils as dbutils
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
"""Sysinv test utilities."""
|
"""Sysinv test utilities."""
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from oslo_serialization import jsonutils as json
|
||||||
from sysinv.common import constants
|
from sysinv.common import constants
|
||||||
from sysinv.openstack.common import jsonutils as json
|
|
||||||
from sysinv.db import api as db_api
|
from sysinv.db import api as db_api
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,11 +21,11 @@ import six
|
|||||||
|
|
||||||
gettext.install('sysinv')
|
gettext.install('sysinv')
|
||||||
|
|
||||||
|
from oslo_utils import timeutils
|
||||||
from sysinv.common import exception
|
from sysinv.common import exception
|
||||||
from sysinv.objects import base
|
from sysinv.objects import base
|
||||||
from sysinv.objects import utils
|
from sysinv.objects import utils
|
||||||
from sysinv.openstack.common import context
|
from sysinv.openstack.common import context
|
||||||
from sysinv.openstack.common import timeutils
|
|
||||||
from sysinv.tests import base as test_base
|
from sysinv.tests import base as test_base
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,7 +16,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
import fixtures
|
||||||
|
|
||||||
|
from oslo_utils import excutils
|
||||||
from sysinv.common import exception
|
from sysinv.common import exception
|
||||||
from sysinv.common import images
|
from sysinv.common import images
|
||||||
from sysinv.tests import base
|
from sysinv.tests import base
|
||||||
@ -35,7 +38,15 @@ class SysinvImagesTestCase(base.TestCase):
|
|||||||
def fake_unlink(path):
|
def fake_unlink(path):
|
||||||
self.executes.append(('rm', path))
|
self.executes.append(('rm', path))
|
||||||
|
|
||||||
def fake_rm_on_errror(path):
|
@contextlib.contextmanager
|
||||||
|
def fake_rm_on_error(path):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except Exception:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
fake_del_if_exists(path)
|
||||||
|
|
||||||
|
def fake_del_if_exists(path):
|
||||||
self.executes.append(('rm', '-f', path))
|
self.executes.append(('rm', '-f', path))
|
||||||
|
|
||||||
def fake_qemu_img_info(path):
|
def fake_qemu_img_info(path):
|
||||||
@ -62,7 +73,12 @@ class SysinvImagesTestCase(base.TestCase):
|
|||||||
self.stub_out('os.unlink', fake_unlink)
|
self.stub_out('os.unlink', fake_unlink)
|
||||||
self.stub_out('sysinv.common.images.fetch', lambda *_: None)
|
self.stub_out('sysinv.common.images.fetch', lambda *_: None)
|
||||||
self.stub_out('sysinv.common.images.qemu_img_info', fake_qemu_img_info)
|
self.stub_out('sysinv.common.images.qemu_img_info', fake_qemu_img_info)
|
||||||
self.stub_out('sysinv.openstack.common.fileutils.delete_if_exists', fake_rm_on_errror)
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
|
'oslo_utils.fileutils.remove_path_on_error',
|
||||||
|
fake_rm_on_error))
|
||||||
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
|
'oslo_utils.fileutils.delete_if_exists',
|
||||||
|
fake_del_if_exists))
|
||||||
|
|
||||||
context = 'opaque context'
|
context = 'opaque context'
|
||||||
image_id = '4'
|
image_id = '4'
|
||||||
|
Loading…
Reference in New Issue
Block a user