diff options
author | Harry Huang <huangxiangyu5@huawei.com> | 2017-11-17 14:53:44 +0800 |
---|---|---|
committer | Harry Huang <huangxiangyu5@huawei.com> | 2017-12-21 16:36:30 +0800 |
commit | 8646b8d62cf4ca7b6bccae537a0c9e72ba45eab3 (patch) | |
tree | 73a9a983e0dd1423e9df928a78a5023a09d5a7f9 /compass-tasks/utils/util.py | |
parent | 6234176ae292a75dcda5520324cb7857d6105988 (diff) |
Merge compass-tasks-osa and compass-tasks-k8s
JIRA: COMPASS-568
rename compass-tasks to compass-tasks-base.
add both osa and k8s support in compass-tasks
Change-Id: I438f5b17e509d4cb751ced0ffe640ec70899882f
Signed-off-by: Harry Huang <huangxiangyu5@huawei.com>
Diffstat (limited to 'compass-tasks/utils/util.py')
-rw-r--r-- | compass-tasks/utils/util.py | 395 |
1 files changed, 0 insertions, 395 deletions
diff --git a/compass-tasks/utils/util.py b/compass-tasks/utils/util.py deleted file mode 100644 index 39978ca..0000000 --- a/compass-tasks/utils/util.py +++ /dev/null @@ -1,395 +0,0 @@ -# Copyright 2014 Huawei Technologies Co. Ltd -# -# 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. - -"""Module to provider util functions in all compass code - - .. moduleauthor:: Xiaodong Wang <xiaodongwang@huawei.com> -""" - -import crypt -import datetime -import logging -import os -import os.path -import re -import setting_wrapper as setting -import sys -import warnings - - -def deprecated(func): - """This is a decorator which can be used to mark functions as deprecated. - - It will result in a warning being emitted when the function is used. - """ - def new_func(*args, **kwargs): - warnings.warn( - "Call to deprecated function %s." % func.__name__, - category=DeprecationWarning - ) - return func(*args, **kwargs) - - new_func.__name__ = func.__name__ - new_func.__doc__ = func.__doc__ - new_func.__dict__.update(func.__dict__) - return new_func - - -def parse_datetime(date_time, exception_class=Exception): - """Parse datetime str to get datetime object. - - The date time format is %Y-%m-%d %H:%M:%S - """ - try: - return datetime.datetime.strptime( - date_time, '%Y-%m-%d %H:%M:%S' - ) - except Exception as error: - logging.exception(error) - raise exception_class( - 'date time %s format is invalid' % date_time - ) - - -def parse_datetime_range(date_time_range, exception_class=Exception): - """parse datetime range str to pair of datetime objects. - - The date time range format is %Y-%m-%d %H:%M:%S,%Y-%m-%d %H:%M:%S - """ - try: - start, end = date_time_range.split(',') - except Exception as error: - logging.exception(error) - raise exception_class( - 'there is no `,` in date time range %s' % date_time_range - ) - if start: - start_datetime = parse_datetime(start, exception_class) - else: - start_datetime = None - if end: - end_datetime = parse_datetime(end, exception_class) - else: - end_datetime = None - return start_datetime, end_datetime - - -def parse_request_arg_dict(arg, exception_class=Exception): - """parse string to dict. - - The str is formatted like a=b;c=d and parsed to - {'a': 'b', 'c': 'd'} - """ - arg_dict = {} - arg_pairs = arg.split(';') - for arg_pair in arg_pairs: - try: - arg_name, arg_value = arg_pair.split('=', 1) - except Exception as error: - logging.exception(error) - raise exception_class( - 'there is no `=` in %s' % arg_pair - ) - arg_dict[arg_name] = arg_value - return arg_dict - - -def format_datetime(date_time): - """Generate string from datetime object.""" - return date_time.strftime("%Y-%m-%d %H:%M:%S") - - -def merge_dict(lhs, rhs, override=True): - """Merge nested right dict into left nested dict recursively. - - :param lhs: dict to be merged into. - :type lhs: dict - :param rhs: dict to merge from. - :type rhs: dict - :param override: the value in rhs overide the value in left if True. - :type override: boolean - """ - if not isinstance(lhs, dict) or not isinstance(rhs, dict): - if override: - return rhs - else: - return lhs - - for key, value in rhs.items(): - if key not in lhs: - lhs[key] = rhs[key] - else: - lhs[key] = merge_dict(lhs[key], value, override) - - return lhs - - -def recursive_merge_dict(name, all_dicts, parents): - """Recursively merge parent dict into base dict.""" - parent_name = parents.get(name, None) - base_dict = all_dicts.get(name, {}) - if not parent_name: - return base_dict - merged = recursive_merge_dict(parent_name, all_dicts, parents) - return merge_dict(base_dict, merged, override=False) - - -def encrypt(value, crypt_method=None): - """Get encrypted value.""" - if not crypt_method: - if hasattr(crypt, 'METHOD_MD5'): - crypt_method = crypt.METHOD_MD5 - else: - # for python2.7, copy python2.6 METHOD_MD5 logic here. - from random import choice - import string - - _saltchars = string.ascii_letters + string.digits + './' - - def _mksalt(): - """generate salt.""" - salt = '$1$' - salt += ''.join(choice(_saltchars) for _ in range(8)) - return salt - - crypt_method = _mksalt() - - return crypt.crypt(value, crypt_method) - - -def parse_time_interval(time_interval_str): - """parse string of time interval to time interval. - - supported time interval unit: ['d', 'w', 'h', 'm', 's'] - Examples: - time_interval_str: '3d 2h' time interval to 3 days and 2 hours. - """ - if not time_interval_str: - return 0 - - time_interval_tuple = [ - time_interval_element - for time_interval_element in time_interval_str.split(' ') - if time_interval_element - ] - time_interval_dict = {} - time_interval_unit_mapping = { - 'd': 'days', - 'w': 'weeks', - 'h': 'hours', - 'm': 'minutes', - 's': 'seconds' - } - for time_interval_element in time_interval_tuple: - mat = re.match(r'^([+-]?\d+)(w|d|h|m|s).*', time_interval_element) - if not mat: - continue - - time_interval_value = int(mat.group(1)) - time_interval_unit = time_interval_unit_mapping[mat.group(2)] - time_interval_dict[time_interval_unit] = ( - time_interval_dict.get(time_interval_unit, 0) + time_interval_value - ) - - time_interval = datetime.timedelta(**time_interval_dict) - if sys.version_info[0:2] > (2, 6): - return time_interval.total_seconds() - else: - return ( - time_interval.microseconds + ( - time_interval.seconds + time_interval.days * 24 * 3600 - ) * 1e6 - ) / 1e6 - - -def get_plugins_config_files(name, suffix=".conf"): - """walk through each of plugin to find all the config files in the""" - """name directory""" - - plugins_path = setting.PLUGINS_DIR - files = [] - if os.path.exists(plugins_path): - for plugin in os.listdir(plugins_path): - plugin_path = os.path.join(plugins_path, plugin) - plugin_config = os.path.join(plugin_path, name) - if os.path.exists(plugin_config): - for component in os.listdir(plugin_config): - if not component.endswith(suffix): - continue - files.append(os.path.join(plugin_config, component)) - return files - - -def load_configs( - config_dir, config_name_suffix='.conf', - env_globals={}, env_locals={} -): - """Load configurations from config dir.""" - """The config file could be in the config_dir or in plugins config_dir""" - """The plugins config_dir is formed as, for example /etc/compass/adapter""" - """Then the plugins config_dir is /etc/compass/plugins/xxx/adapter""" - - # TODO(Carl) instead of using config_dir, it should use a name such as - # adapter etc, however, doing it requires a lot client sites changes, - # will do it later. - - configs = [] - config_files = [] - config_dir = str(config_dir) - - """search for config_dir""" - if os.path.exists(config_dir): - for component in os.listdir(config_dir): - if not component.endswith(config_name_suffix): - continue - config_files.append(os.path.join(config_dir, component)) - - """search for plugins config_dir""" - index = config_dir.rfind("/") - - config_files.extend(get_plugins_config_files(config_dir[index + 1:], - config_name_suffix)) - - if not config_files: - logging.error('path %s and plugins does not exist', config_dir) - for path in config_files: - logging.debug('load config from %s', path) - config_globals = {} - config_globals.update(env_globals) - config_locals = {} - config_locals.update(env_locals) - try: - execfile(path, config_globals, config_locals) - except Exception as error: - logging.exception(error) - raise error - configs.append(config_locals) - return configs - - -def pretty_print(*contents): - """pretty print contents.""" - if len(contents) == 0: - print "" - else: - print "\n".join(content for content in contents) - - -def get_switch_machines_from_file(filename): - """get switch machines from file.""" - switches = [] - switch_machines = {} - with open(filename) as switch_file: - for line in switch_file: - line = line.strip() - if not line: - # ignore empty line - continue - - if line.startswith('#'): - # ignore comments - continue - - columns = [column for column in line.split(',')] - if not columns: - # ignore empty line - continue - - if columns[0] == 'switch': - (switch_ip, switch_vendor, switch_version, - switch_community, switch_state) = columns[1:] - switches.append({ - 'ip': switch_ip, - 'vendor': switch_vendor, - 'credentials': { - 'version': switch_version, - 'community': switch_community, - }, - 'state': switch_state, - }) - elif columns[0] == 'machine': - switch_ip, switch_port, mac = columns[1:] - switch_machines.setdefault(switch_ip, []).append({ - 'mac': mac, - 'port': switch_port, - }) - - return (switches, switch_machines) - - -def execute_cli_by_ssh(cmd, host, username, password=None, - keyfile='/root/.ssh/id_rsa', nowait=False): - """SSH to execute script on remote machine - - :param host: ip of the remote machine - :param username: username to access the remote machine - :param password: password to access the remote machine - :param cmd: command to execute - - """ - if not cmd: - logging.error("No command found!") - raise Exception('No command found!') - - if nowait: - cmd = "nohup %s >/dev/null 2>&1 &" % cmd - - stdin = None - stdout = None - stderr = None - try: - import paramiko - from paramiko import ssh_exception - - client = paramiko.SSHClient() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - - if password: - client.connect(host, username=username, password=password) - else: - client.load_system_host_keys() - client.connect( - host, username=username, - key_filename=keyfile, look_for_keys=True - ) - stdin, stdout, stderr = client.exec_command(cmd) - result = stdout.readlines() - logging.info("result of command '%s' is '%s'!" % (cmd, result)) - return result - - except ImportError: - err_msg = "Cannot find Paramiko package!" - logging.error(err_msg) - raise ImportError(err_msg) - - except (ssh_exception.BadHostKeyException, - ssh_exception.AuthenticationException, - ssh_exception.SSHException): - - err_msg = 'SSH connection error or command execution failed!' - logging.error(err_msg) - raise Exception(err_msg) - - except Exception as exc: - logging.error( - 'Failed to execute command "%s", exception is %s' % (cmd, exc) - ) - raise Exception(exc) - - finally: - for resource in [stdin, stdout, stderr]: - if resource: - resource.close() - - client.close() |