Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions ansible/library/conn_graph_facts.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lxml.etree as ET
import yaml
import os
import logging
import traceback
import ipaddr as ipaddress
from operator import itemgetter
Expand All @@ -12,13 +13,17 @@

try:
from ansible.module_utils.port_utils import get_port_alias_to_name_map
from ansible.module_utils.debug_utils import create_debug_file, print_debug_msg
from ansible.module_utils.debug_utils import config_module_logging
except ImportError:
# Add parent dir for using outside Ansible
import sys
sys.path.append('..')
from module_utils.port_utils import get_port_alias_to_name_map
from module_utils.debug_utils import create_debug_file, print_debug_msg
from module_utils.debug_utils import config_module_logging


config_module_logging('conn_graph_facts')


DOCUMENTATION='''
module: conn_graph_facts.py
Expand Down Expand Up @@ -105,9 +110,6 @@
'''


debug_fname = None


class Parse_Lab_Graph():
"""
Parse the generated lab physical connection graph and insert Ansible fact of the graph
Expand Down Expand Up @@ -263,8 +265,8 @@ def parse_graph(self):
for pdulink in allpdulinks:
start_dev = pdulink.attrib['StartDevice']
end_dev = pdulink.attrib['EndDevice']
print_debug_msg(debug_fname, "pdulink {}".format(pdulink.attrib))
print_debug_msg(debug_fname, "self.pdulinks {}".format(self.pdulinks))
logging.debug("pdulink {}".format(pdulink.attrib))
logging.debug("self.pdulinks {}".format(self.pdulinks))
if start_dev:
if start_dev not in self.pdulinks:
self.pdulinks.update({start_dev : {}})
Expand Down Expand Up @@ -417,20 +419,19 @@ def find_graph(hostnames, part=False):
hostnames: list of duts in the target testbed.
part: select the graph file if over 80% of hosts are found in conn_graph when part is True
"""
global debug_fname
filename = os.path.join(LAB_GRAPHFILE_PATH, LAB_CONNECTION_GRAPH_FILE)
with open(filename) as fd:
file_list = yaml.safe_load(fd)

# Finding the graph file contains all duts from hostnames,
for fn in file_list:
print_debug_msg(debug_fname, "Looking at conn graph file: %s for hosts %s" % (fn, hostnames))
logging.debug("Looking at conn graph file: %s for hosts %s" % (fn, hostnames))
filename = os.path.join(LAB_GRAPHFILE_PATH, fn)
lab_graph = Parse_Lab_Graph(filename)
lab_graph.parse_graph()
print_debug_msg(debug_fname, "For file %s, got hostnames %s" % (fn, lab_graph.devices))
logging.debug("For file %s, got hostnames %s" % (fn, lab_graph.devices))
if lab_graph.contains_hosts(hostnames, part):
print_debug_msg(debug_fname, ("Returning lab graph from conn graph file: %s for hosts %s" % (fn, hostnames)))
logging.debug("Returning lab graph from conn graph file: %s for hosts %s" % (fn, hostnames))
return lab_graph
# Fallback to return an empty connection graph, this is
# needed to bridge the kvm test needs. The KVM test needs
Expand Down Expand Up @@ -489,7 +490,7 @@ def build_results(lab_graph, hostnames, ignore_error=False):
device_vlan_map_list[hostname] = {}

port_name_list_sorted = get_port_name_list(dev['HwSku'])
print_debug_msg(debug_fname, "For %s with hwsku %s, port_name_list is %s" % (hostname, dev['HwSku'], port_name_list_sorted))
logging.debug("For %s with hwsku %s, port_name_list is %s" % (hostname, dev['HwSku'], port_name_list_sorted))
for a_host_vlan in host_vlan["VlanList"]:
# Get the corresponding port for this vlan from the port vlan list for this hostname
found_port_for_vlan = False
Expand Down Expand Up @@ -529,9 +530,6 @@ def main():
supports_check_mode=True
)
m_args = module.params
global debug_fname
debug_fname = create_debug_file("/tmp/conn_graph_debug.txt")

anchor = m_args['anchor']
if m_args['hosts']:
hostnames = m_args['hosts']
Expand Down
68 changes: 48 additions & 20 deletions ansible/module_utils/debug_utils.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,53 @@
import os
from pprint import pprint
import re
import logging
from ansible.module_utils.basic import datetime

MAX_LOG_FILES_PER_MODULE = 10

def create_debug_file(debug_fname, add_timestamp=True):

def config_module_logging(module_name, log_path='/tmp', log_level=logging.DEBUG):
"""Tool for configure logging to file for customized ansible modules

This tool aims to easy the effort for logging in customized ansible modules. To use it in customized ansible
module, please follow below pattern.
```
from asible.module_utils.debug_utils import config_module_logging

config_module_logging('your_module_name')

logging.debug('some message')
logging.info('some message')
```

After the function is imported and called with ansible module name as argument, then we can simply call
logging.debug, logging.info, etc., to log a message. The messages are automatically logged to files like:
/tmp/<ansible_module_name>_<iso_format_timestamp>.log

The default log path '/tmp' can be changed by passing argument `log_path` when calling this function.

Another important feature is that this function will also try to remove old log files of this module. The number
of most recent log files will be kept is specified by the global constant `MAX_LOG_FILES_PER_MODULE`.

Args:
module_name (str): Name of the customized ansible module.
log_path (str, optional): Path of log file. Defaults to '/tmp'.
log_level (log level, optional): Log level. Defaults to logging.DEBUG.
"""

# Cleanup old log files to rotate
pattern = re.compile('{}_[\d\-T:\.]+\.log'.format(module_name))
existing_log_files = sorted([f for f in os.listdir(log_path) if pattern.match(f)])
old_log_files = existing_log_files[:-(MAX_LOG_FILES_PER_MODULE-1)]
try:
[os.remove(os.path.join(log_path, f)) for f in old_log_files]
except Exception as e:
pass

# Configure logging to file
curtime = datetime.datetime.now().isoformat()
if add_timestamp:
# Check if there is an extension
fname_split = os.path.splitext(debug_fname)
if fname_split[1] != '':
# We have an extension
timed_debug_fname = (fname_split[0] + ".%s" + fname_split[1]) % curtime
else:
timed_debug_fname = (fname_split[0] + ".%s") % curtime
else:
timed_debug_fname = debug_fname
if os.path.exists(timed_debug_fname) and os.path.isfile(timed_debug_fname):
os.remove(timed_debug_fname)
return timed_debug_fname


def print_debug_msg(debug_fname, msg):
with open(debug_fname, 'a') as fp:
pprint(msg, fp)
log_filename = os.path.join(log_path, '{}_{}.log'.format(module_name, curtime))
logging.basicConfig(
filename=log_filename,
format='%(asctime)s %(levelname)s #%(lineno)d: %(message)s',
level=log_level)