ece0a3e936
Change-Id: Id5fd48b8149d3934e4854366e59475f37624ec24
358 lines
10 KiB
Python
358 lines
10 KiB
Python
# 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 copy
|
|
import re
|
|
|
|
|
|
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: str
|
|
|
|
:raises: TypeError if lhs or rhs is not a dict.
|
|
"""
|
|
if not rhs:
|
|
return
|
|
|
|
if not isinstance(lhs, dict):
|
|
raise TypeError('lhs type is %s while expected is dict' % type(lhs),
|
|
lhs)
|
|
|
|
if not isinstance(rhs, dict):
|
|
raise TypeError('rhs type is %s while expected is dict' % type(rhs),
|
|
rhs)
|
|
|
|
for key, value in rhs.items():
|
|
if (
|
|
isinstance(value, dict) and key in lhs and
|
|
isinstance(lhs[key], dict)
|
|
):
|
|
merge_dict(lhs[key], value, override)
|
|
else:
|
|
if override or key not in lhs:
|
|
lhs[key] = copy.deepcopy(value)
|
|
|
|
|
|
def order_keys(keys, orders):
|
|
"""Get ordered keys.
|
|
|
|
:param keys: keys to be sorted.
|
|
:type keys: list of str
|
|
:param orders: the order of the keys. '.' is all other keys not in order.
|
|
:type orders: list of str.
|
|
|
|
:returns: keys as list sorted by orders.
|
|
|
|
:raises: TypeError if keys or orders is not list.
|
|
"""
|
|
|
|
if not isinstance(keys, list):
|
|
raise TypeError('keys %s type should be list' % keys)
|
|
|
|
if not isinstance(orders, list):
|
|
raise TypeError('orders ^s type should be list' % orders)
|
|
|
|
found_dot = False
|
|
pres = []
|
|
posts = []
|
|
for order in orders:
|
|
if order == '.':
|
|
found_dot = True
|
|
else:
|
|
if found_dot:
|
|
posts.append(order)
|
|
else:
|
|
pres.append(order)
|
|
|
|
return ([pre for pre in pres if pre in keys] +
|
|
[key for key in keys if key not in orders] +
|
|
[post for post in posts if post in keys])
|
|
|
|
|
|
def is_instance(instance, expected_types):
|
|
"""Check instance type is in one of expected types.
|
|
|
|
:param instance: instance to check the type.
|
|
:param expected_types: types to check if instance type is in them.
|
|
:type expected_types: list of type
|
|
|
|
:returns: True if instance type is in expect_types.
|
|
"""
|
|
for expected_type in expected_types:
|
|
if isinstance(instance, expected_type):
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def flat_lists_with_possibility(lists):
|
|
"""Return list of item from list of list of identity item.
|
|
|
|
:param lists: list of list of identity item.
|
|
|
|
:returns: list.
|
|
|
|
.. note::
|
|
For each first k elements in the returned list, it should be the k
|
|
most possible items. e.g. the input lists is
|
|
['a', 'a', 'a', 'a'], ['b', 'b'], ['c'],
|
|
the expected output is ['a', 'b', 'c', 'a', 'a', 'b', 'a'].
|
|
"""
|
|
lists = copy.deepcopy(lists)
|
|
lists = sorted(lists, key=len, reverse=True)
|
|
list_possibility = []
|
|
max_index = 0
|
|
total_elements = 0
|
|
possibilities = []
|
|
for items in lists:
|
|
list_possibility.append(0.0)
|
|
length = len(items)
|
|
if length > 0:
|
|
total_elements += length
|
|
possibilities.append(1.0 / length)
|
|
else:
|
|
possibilities.append(0.0)
|
|
|
|
output = []
|
|
while total_elements > 0:
|
|
if not lists[max_index]:
|
|
list_possibility[max_index] -= total_elements
|
|
else:
|
|
list_possibility[max_index] -= possibilities[max_index]
|
|
element = lists[max_index].pop(0)
|
|
output.append(element)
|
|
total_elements -= 1
|
|
max_index = list_possibility.index(max(list_possibility))
|
|
|
|
return output
|
|
|
|
|
|
def pretty_print(*contents):
|
|
"""pretty print contents."""
|
|
if len(contents) == 0:
|
|
print ""
|
|
else:
|
|
print "\n".join(content for content in contents)
|
|
|
|
|
|
def get_clusters_from_str(clusters_str):
|
|
"""get clusters from string."""
|
|
clusters = {}
|
|
for cluster_and_hosts in clusters_str.split(';'):
|
|
if not cluster_and_hosts:
|
|
continue
|
|
|
|
if ':' in cluster_and_hosts:
|
|
cluster_str, hosts_str = cluster_and_hosts.split(
|
|
':', 1)
|
|
else:
|
|
cluster_str = cluster_and_hosts
|
|
hosts_str = ''
|
|
|
|
hosts = [
|
|
host for host in hosts_str.split(',')
|
|
if host
|
|
]
|
|
clusters[cluster_str] = hosts
|
|
|
|
return clusters
|
|
|
|
|
|
def _get_switch_ips(switch_config):
|
|
"""Helper function to get switch ips."""
|
|
ips = []
|
|
blocks = switch_config['switch_ips'].split('.')
|
|
ip_blocks_list = []
|
|
for block in blocks:
|
|
ip_blocks_list.append([])
|
|
sub_blocks = block.split(',')
|
|
for sub_block in sub_blocks:
|
|
if not sub_block:
|
|
continue
|
|
|
|
if '-' in sub_block:
|
|
start_block, end_block = sub_block.split('-', 1)
|
|
start_block = int(start_block)
|
|
end_block = int(end_block)
|
|
if start_block > end_block:
|
|
continue
|
|
|
|
ip_block = start_block
|
|
while ip_block <= end_block:
|
|
ip_blocks_list[-1].append(str(ip_block))
|
|
ip_block += 1
|
|
|
|
else:
|
|
ip_blocks_list[-1].append(sub_block)
|
|
|
|
ip_prefixes = [[]]
|
|
for ip_blocks in ip_blocks_list:
|
|
prefixes = []
|
|
for ip_block in ip_blocks:
|
|
for prefix in ip_prefixes:
|
|
prefixes.append(prefix + [ip_block])
|
|
|
|
ip_prefixes = prefixes
|
|
|
|
for prefix in ip_prefixes:
|
|
if not prefix:
|
|
continue
|
|
|
|
ips.append('.'.join(prefix))
|
|
|
|
return ips
|
|
|
|
|
|
def _get_switch_filter_ports(switch_config):
|
|
"""Helper function to get switch filter ports."""
|
|
port_pat = re.compile(r'(\D*)(\d+(?:-\d+)?)')
|
|
filter_ports = []
|
|
for port_range in switch_config['filter_ports'].split(','):
|
|
if not port_range:
|
|
continue
|
|
|
|
mat = port_pat.match(port_range)
|
|
if not mat:
|
|
filter_ports.append(port_range)
|
|
else:
|
|
port_prefix = mat.group(1)
|
|
port_range = mat.group(2)
|
|
if '-' in port_range:
|
|
start_port, end_port = port_range.split('-', 1)
|
|
start_port = int(start_port)
|
|
end_port = int(end_port)
|
|
if start_port > end_port:
|
|
continue
|
|
|
|
port = start_port
|
|
while port <= end_port:
|
|
filter_ports.append('%s%s' % (port_prefix, port))
|
|
port += 1
|
|
|
|
else:
|
|
filter_ports.append('%s%s' % (port_prefix, port_range))
|
|
|
|
return filter_ports
|
|
|
|
|
|
def get_switch_filters(switch_configs):
|
|
"""get switch filters."""
|
|
switch_filters = []
|
|
for switch_config in switch_configs:
|
|
ips = _get_switch_ips(switch_config)
|
|
filter_ports = _get_switch_filter_ports(switch_config)
|
|
|
|
for ip_addr in ips:
|
|
for filter_port in filter_ports:
|
|
switch_filters.append(
|
|
{'ip': ip_addr, 'filter_port': filter_port})
|
|
|
|
return switch_filters
|
|
|
|
|
|
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_info': switch_vendor,
|
|
'credential': {
|
|
'version': switch_version,
|
|
'community': switch_community,
|
|
},
|
|
'state': switch_state,
|
|
})
|
|
elif columns[0] == 'machine':
|
|
switch_ip, switch_port, vlan, mac = columns[1:]
|
|
switch_machines.setdefault(switch_ip, []).append({
|
|
'mac': mac,
|
|
'port': switch_port,
|
|
'vlan': int(vlan)
|
|
})
|
|
|
|
return (switches, switch_machines)
|
|
|
|
|
|
def get_properties_from_str(properties_str):
|
|
"""get matching properties from string."""
|
|
properties = {}
|
|
if not properties_str:
|
|
return properties
|
|
|
|
for property_str in properties_str.split(','):
|
|
if not property_str:
|
|
# ignore empty str
|
|
continue
|
|
|
|
property_name, property_value = property_str.split('=', 1)
|
|
properties[property_name] = property_value
|
|
|
|
return properties
|
|
|
|
|
|
def get_properties_name_from_str(properties_name_str):
|
|
"""get properties name to print from string."""
|
|
properties_name = []
|
|
for property_name in properties_name_str.split(','):
|
|
if not property_name:
|
|
# ignore empty str
|
|
continue
|
|
|
|
properties_name.append(property_name)
|
|
|
|
return properties_name
|
|
|
|
|
|
def print_properties(properties):
|
|
"""print properties."""
|
|
print '-----------------------------------------------'
|
|
for property_item in properties:
|
|
property_pairs = []
|
|
for property_name, property_value in property_item.items():
|
|
property_pairs.append('%s=%s' % (property_name, property_value))
|
|
|
|
print ','.join(property_pairs)
|
|
|
|
print '-----------------------------------------------'
|