From 456a36db70eff76f443055e9b44e06b94ee98fe8 Mon Sep 17 00:00:00 2001 From: Sachin Bansal Date: Wed, 24 Feb 2016 13:48:05 -0800 Subject: [PATCH] Replace ifmap_view with the new ifmap_search Keeping the positional arguments same as before except that ip and port are now optional and can be skipped. Change-Id: I769af79f39ba99cf9129e9e4c25a8e25af87c104 Closes-Bug: 1543835 (cherry picked from commit cc2a4102f47043786f7eefd99520263bd73051af) --- src/config/schema-transformer/ifmap_view.py | 409 ++++++-------------- 1 file changed, 112 insertions(+), 297 deletions(-) diff --git a/src/config/schema-transformer/ifmap_view.py b/src/config/schema-transformer/ifmap_view.py index b9132bdd1b0..1ce547dd8da 100644 --- a/src/config/schema-transformer/ifmap_view.py +++ b/src/config/schema-transformer/ifmap_view.py @@ -3,6 +3,8 @@ # Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. # +import logging +from pprint import pformat import argparse import sys reload(sys) @@ -13,207 +15,17 @@ import re import json -from distutils.sysconfig import get_python_lib -sys.path.append(get_python_lib() + '/vnc_cfg_api_server') +from cfgm_common.ifmap.client import client +from cfgm_common.ifmap.request import NewSessionRequest, SearchRequest +from cfgm_common.ifmap.response import newSessionResult +from cfgm_common.ifmap.id import Identity -from operator import itemgetter, attrgetter -from vnc_api import vnc_api -from vnc_cfg_api_server import gen -from vnc_api.gen.resource_xsd import * -from vnc_api.gen.resource_common import * -from vnc_cfg_api_server.gen.vnc_ifmap_client_gen import * -from vnc_api.gen.vnc_api_client_gen import * +logger = logging.getLogger(__name__) -import pycassa -from pycassa.system_manager import * -# Global variables -vnc = None -dbg_outfile = None -""" - Input is list of tuple dictionary - type := project, domain ... - value := dependent graph - prop := Properties of this node - refs := parenr->node reference meta data -""" +class IfmapSearcher(): - -def mypretty(l, indent=0, verbose=0, outfile=sys.stdout): - l = sorted(l, key=itemgetter('type')) - prop_fmt = '\n' + ' ' * (indent + 1) - ref_fmt = '\n' + ' ' * indent - for i in l: - """ Prepare property string""" - propstr = '' - propstr2 = '' - if i['props']: - propstr = [p['name'] for p in i['props']] - propstr = ' (' + ', '.join(propstr) + ')' - if verbose >= 2: - show_list = [] - for p in i['props']: - if p['name'] not in vnc_viewer.skip: - show_list.append(p) - propstr2 = ['%s=%s' % (p['name'], p['value']) - for p in show_list] - propstr2 = '\n'.join(propstr2) - propstr2 = propstr2.split('\n') - propstr2 = prop_fmt.join(propstr2) - outfile.write(' ' * indent + '%s = '\ - % (i['type']) + str(i['name']) + propstr + '\n') - - """ Prepare reference string""" - ref_str = [] - if verbose >= 1 and i['refs']: - ref_str = [r['value'] for r in i['refs']] - ref_str = '\n'.join(ref_str) - ref_str = ref_str.split('\n') - ref_str = ref_fmt.join(ref_str) - if len(ref_str) > 0: - outfile.write(' ' * indent + ref_str + '\n') - - if len(propstr2) > 0: - outfile.write(' ' * (indent + 1) + propstr2 + '\n') - if len(i['value']) > 0: - mypretty(i['value'], indent + 1, verbose, outfile) -# end mypretty - -""" -Find name in node list. Return the parent and subgraph -for subsequent traversal. Otherwise return def_node (typically None) -""" - - -def find_node(name, node_list, def_node): - # traverse thru list of dict - for item in node_list: - if name == item['name']: - return (item, item['value']) - return (def_node, def_node) - - -def find_node_in_tree(fq_path, tree): - path = fq_path.split(':') - - # Traverse until name is finished - match, node = find_node('root', tree, tree) - for name in path: - match, n = find_node(name, node, None) - if n is None: - return None - node = n - return node -# end find_node_in_tree - - -def parse_config(soap_config): - root = et.fromstring(soap_config) - config = [] - for r_i in root.findall('*/*/*/resultItem'): - ids = r_i.findall('identity') - ident1 = ids[0].get('name') - try: - ident2 = ids[1].get('name') - except IndexError: - ident2 = None - metas = r_i.find('metadata') - - # details - dbg_outfile.write('\n' + et.tostring(r_i) + '\n') - dbg_outfile.write('ident1 = %s\n' % (ident1)) - if ident2: - dbg_outfile.write('ident2 = %s\n' % (ident2)) - if metas is not None: - dbg_outfile.write('metas = %s\n' % (et.tostring(metas))) - - if not re.match("^contrail:", ident1): - continue - - res = re.search("^contrail:([^:]+):(.*:)*(.*)$", ident1) - type1 = res.group(1) - name1 = res.group(3) - id1 = ident1.split(':') - # strip contrail, type - id1 = id1[2:] - dbg_outfile.write('Ident1 type = %s, name = %s\n' % (type1, name1)) - - if ident2: - res = re.search("^contrail:([^:]+):(.*:)*(.*)$", ident2) - type2 = res.group(1) - name2 = res.group(3) - id2 = ident2.split(':') - # strip contrail, type - id2 = id2[2:] - dbg_outfile.write('Ident2 type = %s, name = %s\n' % (type2, name2)) - - # Traverse until name is finished - match, node = find_node('root', config, config) - for name in id1: - match, n = find_node(name, node, None) - if n is None: - node.append( - {'type': type1, 'name': name1, 'value': [], - 'props': [], 'refs': []}) - match = node[-1] - node = node[-1]['value'] - break - node = n - - node1 = node - - if ident2: - match, n = find_node(name2, node1, None) - if n is None: - match = {'type': type2, 'name': name2, - 'value': [], 'props': [], 'refs': []} - node1.append(match) - - # attach property or reference info if available - if metas is None: - continue - - for meta in metas: - meta_name = re.sub('{.*}', '', meta.tag) - dbg_outfile.write('Handling meta = %s\n' % (meta_name)) - if ident2: - if meta_name in link_name_to_xsd_type: - obj = eval(link_name_to_xsd_type[meta_name])() - obj.build(meta) - obj_json = json.dumps( - obj, - default=lambda o: dict( - (k, v) for k, - v in o.__dict__.iteritems()), indent=4) - dbg_outfile.write( - 'Attaching Reference %s to Id %s\n' - % (meta_name, ident2)) - dbg_outfile.write('JSON %s = %s\n' % (meta_name, obj_json)) - match['refs'].append( - {'name': '%s' % (meta_name), 'value': obj_json}) - else: - if meta_name in vnc.prop_name_to_xsd_type: - obj = eval(vnc.prop_name_to_xsd_type[meta_name])() - obj.build(meta) - obj_json = json.dumps( - obj, - default=lambda o: dict( - (k, v) for k, - v in o.__dict__.iteritems()), indent=4) - dbg_outfile.write( - 'Attaching Property %s to Id %s\n' - % (meta_name, ident1)) - dbg_outfile.write('JSON %s = %s\n' % (meta_name, obj_json)) - match['props'].append( - {'name': '%s' % (meta_name), 'value': obj_json}) - - return config -# end parse_config - - -class IfmapClient(): - - def __init__(self, ifmap_srv_ip, ifmap_srv_port, uname, passwd): + def __init__(self): """ .. attention:: username/passwd from right place """ @@ -233,20 +45,25 @@ def __init__(self, ifmap_srv_ip, ifmap_srv_port, uname, passwd): 'contrail': self._CONTRAIL_XSD } - mapclient = client(("%s" % (ifmap_srv_ip), "%s" % (ifmap_srv_port)), - uname, passwd, namespaces) + self.parse_args() + if self._args.verbose: + logger.setLevel('DEBUG') + mapclient = client(("%s" % (self._args.ip), + "%s" % (self._args.port)), + self._args.username, + self._args.password, namespaces) result = mapclient.call('newSession', NewSessionRequest()) mapclient.set_session_id(newSessionResult(result).get_session_id()) mapclient.set_publisher_id(newSessionResult(result).get_publisher_id()) self._mapclient = mapclient + self.soap_doc = None # end __init__ - def _search(self, start_id, match_meta=None, result_meta=None, - max_depth=1): + def _search(self, start_id, match_meta=None, result_meta=None): # set ifmap search parmeters srch_params = {} - srch_params['max-depth'] = str(max_depth) + srch_params['max-depth'] = self._args.max_depth srch_params['max-size'] = '50000000' if match_meta is not None: @@ -269,111 +86,109 @@ def _search(self, start_id, match_meta=None, result_meta=None, result = mapclient.call('search', srch_req) return result - # end _search - - def ifmap_read(self, ifmap_id, srch_meta, result_meta, field_names=None): - start_id = str( - Identity(name=ifmap_id, type='other', other_type='extended')) - srch_result = self._search( - start_id, srch_meta, result_meta, max_depth=10) - return srch_result - # end ifmap_read - -# end class IfmapClient - - -class VncViewer(): + # end _search def parse_args(self): - # Eg. python vnc_ifmap_view.py 192.168.1.17 8443 test2 test2 + # Eg. python ifmap_search.py 192.168.1.17 8443 test2 test2 --identifier parser = argparse.ArgumentParser( description="Display IFMAP configuration") - parser.add_argument( - 'ifmap_server_ip', help="IP address of ifmap server") - parser.add_argument('ifmap_server_port', help="Port of ifmap server") - parser.add_argument( - 'ifmap_username', help="Username known to ifmap server") - parser.add_argument( - 'ifmap_password', help="Password known to ifmap server") - parser.add_argument('-v', type=int, default=0, choices=range(0, 3), - help="Turn verbosity on. Default is 0") - parser.add_argument('-f', '--format', default='text', choices=['text','xml'], - help="Output format. Default is text/human-readable") - parser.add_argument('-o', '--outfile', default=sys.stdout, type=argparse.FileType('w'), - help="Output file to write to. Default is stdout") - """ - parser.add_argument('-n', '--node', default=None, - help = "Start node (fully qualified name such as - default-domain:admin:vn2") - parser.add_argument('-s', '--skip', action='append', - help = "Skip property (such as id-perms)") - """ + parser.add_argument('ip', default='localhost', nargs='?', + help="Hostname/IP address of ifmap server") + parser.add_argument('--port', default='8443', nargs='?', + help="Port of ifmap server") + parser.add_argument('username', + help="Username known to ifmap server") + parser.add_argument('password', + help="Password known to ifmap server") + parser.add_argument('--search-identifier', + default = 'contrail:config-root:root', + help = "IFMAP identifier to search e.g." + "contrail:virtual-network:default-domain:admin:test-net") + parser.add_argument('--search-metas', + help = "Comma separated metadata names to search e.g." + "contrail:project-virtual-network") + parser.add_argument('--result-metas', + help = "Comma separated metadata names to pick in response e.g." + "contrail:project-virtual-network") + parser.add_argument('--max-depth', default='10', + help = "Maximum depth to span from search-identifier e.g. 1") + parser.add_argument('--verbose', + action='store_true', default=False) self._args = parser.parse_args() - self.verbose = self._args.v - """ - self.start_node = self._args.node - self.skip = self._args.skip - """ - self.start_node = None - self.skip = ['id-perms'] - print 'MAP server connection = %s:%s'\ - % (self._args.ifmap_server_ip, self._args.ifmap_server_port) - print 'MAP server credentials = %s:%s'\ - % (self._args.ifmap_username, self._args.ifmap_password) - print 'Start node = %s' % (self.start_node) - print 'Skip List = %s' % (self.skip) - print 'Verbose = %s' % (self.verbose) - print '' # end parse_args - def db_connect(self): - ifmap_ip = self._args.ifmap_server_ip - ifmap_port = self._args.ifmap_server_port - user = self._args.ifmap_username - passwd = self._args.ifmap_password - - # ifmap interface - db_conn = IfmapClient(ifmap_ip, ifmap_port, user, passwd) - self._db_conn = db_conn - # end db_connect + def search(self): + if self._args.search_metas: + search_metas = ' or '.join( + self._args.search_metas.split(',')) + else: + search_metas = None + if self._args.result_metas: + result_metas = ' or '.join( + self._args.result_metas.split(',')) + else: + result_metas = None + start_id = str( + Identity(name=self._args.search_identifier, + type='other', other_type='extended')) + soap_result = self._search( + start_id, + search_metas, + result_metas) + self.soap_doc = et.fromstring(soap_result) + self.result_items = self.soap_doc.xpath( + '/a:Envelope/a:Body/b:response/searchResult/resultItem', + namespaces={'a': 'http://www.w3.org/2003/05/soap-envelope', + 'b': 'http://www.trustedcomputinggroup.org/2010/IFMAP/2'}) + + #vnc_viewer._args.outfile.write(et.tostring(soap_doc, pretty_print=True)) + # end search + + def print_search_results(self): + if self._args.verbose: + if self.soap_doc is None: + logger.error("Not able to get a result for search") + return + logger.debug("Raw search result:\n%s", + et.tostring(self.soap_doc, pretty_print=True)) + + logger.info("Number of result items for search = %s", + len(self.result_items)) + + props = [] + links = [] + for r_item in self.result_items: + if (len(r_item) == 2 and + r_item[0].get('name') == self._args.search_identifier): + props.extend([x.tag for x in r_item[1]]) + elif len(r_item) == 3: + if r_item[1].get('name') != self._args.search_identifier: + links.append(r_item[1].get('name')) + else: + links.append(r_item[0].get('name')) + + logger.info("Properties on identifier = %s", pformat(props)) + logger.info("Links from identifier = %s", pformat(links)) + # end print_search_results +# end IfmapSearcher def main(): - vnc_viewer = VncViewer() - vnc_viewer.parse_args() - vnc_viewer.db_connect() - - #vnc = VncApi('admin', 'contrail123', 'admin', '127.0.0.1', '8082') - global vnc - global dbg_outfile - vnc = VncApiClientGen(obj_serializer=None) - dbg_outfile = file("debug.txt", "w") - - """ sample search metas - srch_meta = 'contrail:config-root-domain' (retunn only domains) - srch_meta = ' or '.join(['contrail:config-root-domain', - 'contrail:config-root-virtual-router']) (domain or virtual-router) - srch_meta = 'contrail:config-root-domain or - contrail:config-root-virtual-router' (same as above) - srch_meta = 'contrail:domain-project' (search all projects) - srch_meta = None (search everything) - """ + searcher = IfmapSearcher() + searcher.search() + searcher.print_search_results() +# end main - srch_meta = None - result_meta = 'all' - soap_result = vnc_viewer._db_conn.ifmap_read( - 'contrail:config-root:root', srch_meta, result_meta) - if vnc_viewer._args.format == 'xml': - soap_doc = et.fromstring(soap_result) - vnc_viewer._args.outfile.write(et.tostring(soap_doc, pretty_print=True)) - # we are done - return +if __name__ == '__main__': - config = parse_config(soap_result) - if vnc_viewer.start_node is None: - node = config[0]['value'] - else: - node = find_node_in_tree(vnc_viewer.start_node, config) - mypretty(node, verbose=vnc_viewer.verbose, outfile=vnc_viewer._args.outfile) + # Example usage: + # python ifmap_search.py localhost 8443 + # --search-identifier contrail:virtual-network:default-domain:admin:test-net + # --search-metas contrail:project-virtual-network --verbose --max-depth 1 + logger.setLevel('INFO') + logformat = logging.Formatter("%(levelname)s: %(message)s") + stdout = logging.StreamHandler() + stdout.setLevel('DEBUG') + stdout.setFormatter(logformat) + logger.addHandler(stdout) -if __name__ == '__main__': main()