def site_detail(request, handle_id): nh = get_object_or_404(NodeHandle, pk=handle_id) # Get node from neo4j-database site = nh.get_node() last_seen, expired = helpers.neo4j_data_age(site.data) relations = site.get_relations() # Direct equipment (aka not racked) equipment_relationships = _nodes_without( site.get_located_in().get('Located_in', []), 'operational_state', ['decommissioned']) # Racked equipment q = """ MATCH (site:Site {handle_id: {handle_id}})-[:Has]->(rack:Node) OPTIONAL MATCH (rack)<-[:Located_in]-(item:Node) WHERE NOT item.operational_state IN ['Decommissioned'] OR NOT exists(item.operational_state) RETURN rack, item order by toLower(rack.name), toLower(item.name) """ rack_list = nc.query_to_list(nc.graphdb.manager, q, handle_id=nh.handle_id) # Create racked equipment table racks_table = Table('Rack', 'Equipment') racks_table.rows = [ TableRow(r.get('rack'), r.get('item')) for r in rack_list ] urls = helpers.get_node_urls(site, equipment_relationships, relations, rack_list) return render( request, 'noclook/detail/site_detail.html', { 'node_handle': nh, 'node': site, 'last_seen': last_seen, 'expired': expired, 'equipment_relationships': equipment_relationships, 'relations': relations, 'racks_table': racks_table, 'history': True, 'urls': urls, })
def search_simple_port_typeahead(request): ''' This view is a simplification of the above search_port_typeahead to be used by PortSearchConnection as a typeahead simple port name search ''' response = HttpResponse(content_type='application/json') to_find = request.GET.get('query', None) result = [] if to_find: # split for search try: q = """ MATCH (port:Port) WHERE port.name CONTAINS $name RETURN port.name AS name, port.handle_id AS handle_id, null as parent_id """ result = nc.query_to_list(nc.graphdb.manager, q, name=to_find) except Exception as e: raise e json.dump(result, response) return response
def get_subtype_form_data(request, slug, key, value): """ Compiles a list of the nodes children and returns a list of node name, node id tuples. If node_type is set the function will only return nodes of that type. """ node_type = helpers.slug_to_node_type(slug).type.replace(' ', '_') q = """ MATCH (n:{node_type}) WHERE n.{key} = '{value}' RETURN n.handle_id as handle_id, n.name as name, n.description as description ORDER BY n.name """.format(node_type=node_type, key=key, value=value) subtype_list = [] for subtype in nc.query_to_list(nc.graphdb.manager, q): name = subtype['name'] if subtype.get('description', None): name = u'{} ({})'.format(name, subtype['description']) subtype_list.append((subtype['handle_id'], name)) subtype_list = sorted(subtype_list, key=itemgetter(1)) return JsonResponse(subtype_list, safe=False)
def list_ports(request): q = """ MATCH (port:Port) OPTIONAL MATCH (port)<-[:Has]-(parent:Node) RETURN port, collect(parent) as parent order by toLower(port.name) """ port_list = nc.query_to_list(nc.graphdb.manager, q) port_list = _filter_expired(port_list, request, select=lambda n: n.get('port')) urls = get_node_urls(port_list) table = Table('Name', 'Description', 'Equipment') table.rows = [_port_row(item) for item in port_list] _set_filters_expired(table, request) return render(request, 'noclook/list/list_generic.html', { 'table': table, 'name': 'Ports', 'urls': urls })
def get_host_backup(host): """ :param host: norduniclient model :return: String Return a string that expresses the current backup solution used for the host or 'No'. """ backup = host.data.get('backup', 'No') if backup == 'No': q = """ MATCH (:Node {handle_id: {handle_id}})<-[r:Depends_on]-(:Node {name: "vnetd"}) WHERE r.state IN ['open', 'open|filtered'] RETURN r """ for hit in nc.query_to_list(nc.graphdb.manager, q, handle_id=host.handle_id): last_seen, expired = neo4j_data_age(hit) if not expired: backup = 'netbackup' return backup
def cable_detail(request, handle_id): nh = get_object_or_404(NodeHandle, pk=handle_id) cable = nh.get_node() last_seen, expired = helpers.neo4j_data_age(cable.data) # TODO: should be fixed in nc.get_connected_equipment q = """ MATCH (n:Node {handle_id: {handle_id}})-[rel:Connected_to]->(port) OPTIONAL MATCH (port)<-[:Has*1..10]-(end) WITH rel, port, last(collect(end)) as end OPTIONAL MATCH (end)-[:Located_in]->(location) OPTIONAL MATCH (location)<-[:Has*1..10]-(site:Site) RETURN id(rel) as rel_id, rel, port, end, location, site ORDER BY end.name, port.name """ connections = nc.query_to_list(nc.graphdb.manager, q, handle_id=cable.handle_id) # connections = cable.get_connected_equipment() relations = cable.get_relations() dependent = cable.get_dependent_as_types() connection_path = cable.get_connection_path() urls = helpers.get_node_urls(cable, connections, relations, dependent) if not any(dependent.values()): dependent = None return render( request, 'noclook/detail/cable_detail.html', { 'node': cable, 'node_handle': nh, 'last_seen': last_seen, 'expired': expired, 'connections': connections, 'dependent': dependent, 'connection_path': connection_path, 'history': True, 'relations': relations, 'urls': urls })
def list_external_equipment(request): q = """ MATCH (equipment:External_Equipment) OPTIONAL MATCH (equipment)<-[:Owns]-(owner:Node) RETURN equipment, owner ORDER BY equipment.name """ equipment_list = nc.query_to_list(nc.graphdb.manager, q) urls = get_node_urls(equipment_list) table = Table('Name', 'Description', 'Owner') table.rows = [ _external_equipment_table(item['equipment'], item['owner']) for item in equipment_list ] return render(request, 'noclook/list/list_generic.html', { 'table': table, 'name': 'External Equipment', 'urls': urls })
def list_routers(request): q = """ MATCH (router:Router) RETURN router ORDER BY router.name """ router_list = nc.query_to_list(nc.graphdb.manager, q) router_list = _filter_expired(router_list, request, select=lambda n: n.get('router')) urls = get_node_urls(router_list) table = Table('Router', 'Model', 'JUNOS version', 'Operational state') table.rows = [_router_table(item['router']) for item in router_list] _set_filters_expired(table, request) return render(request, 'noclook/list/list_generic.html', { 'table': table, 'name': 'Routers', 'urls': urls })
def list_optical_nodes(request): q = """ MATCH (node:Optical_Node) RETURN node ORDER BY node.name """ optical_node_list = nc.query_to_list(nc.graphdb.manager, q) optical_node_list = _filter_operational_state( optical_node_list, request, select=lambda n: n.get('node')) urls = get_node_urls(optical_node_list) table = Table('Name', 'Type', 'Link', 'OTS') table.rows = [ _optical_nodes_table(item['node']) for item in optical_node_list ] _set_filters_operational_state(table, request) return render(request, 'noclook/list/list_generic.html', { 'table': table, 'name': 'Optical Nodes', 'urls': urls })
def list_sites(request): q = """ MATCH (site:Site) OPTIONAL MATCH (site)<-[:Responsible_for]-(owner:Site_Owner) RETURN site, owner ORDER BY site.country_code, site.name """ site_list = nc.query_to_list(nc.graphdb.manager, q) urls = get_node_urls(site_list) table = Table('Country', 'Site name', 'Area', 'Responsible') table.rows = [ _site_table(item['site'], item['owner']) for item in site_list ] table.no_badges = True return render(request, 'noclook/list/list_generic.html', { 'table': table, 'name': 'Sites', 'urls': urls })
def patch_panel_detail(request, handle_id): nh = get_object_or_404(NodeHandle, pk=handle_id) # Get node from neo4j-database patch_panel = nh.get_node() last_seen, expired = helpers.neo4j_data_age(patch_panel.data) # Get ports in Patch Panel # connections = patch_panel.get_connections() # TODO: should be fixed in nc.get_connections q = """ MATCH (n:Node {handle_id: {handle_id}})-[:Has*1..10]->(porta:Port) OPTIONAL MATCH (porta)<-[r0:Connected_to]-(cable) OPTIONAL MATCH (cable)-[r1:Connected_to]->(portb:Port) WHERE ID(r1) <> ID(r0) OPTIONAL MATCH (portb)<-[:Has*1..10]-(end) WITH porta, r0, cable, portb, r1, last(collect(end)) as end OPTIONAL MATCH (end)-[:Located_in]->(location) OPTIONAL MATCH (location)<-[:Has*1..10]-(site:Site) RETURN porta, r0, cable, r1, portb, end, location, site """ connections = nc.query_to_list(nc.graphdb.manager, q, handle_id=patch_panel.handle_id) # Get location location_path = patch_panel.get_location_path() urls = helpers.get_node_urls(patch_panel, connections, location_path) return render( request, 'noclook/detail/patch_panel_detail.html', { 'node': patch_panel, 'node_handle': nh, 'last_seen': last_seen, 'expired': expired, 'connections': connections, 'location_path': location_path, 'history': True, 'urls': urls })
def obj_get(self, bundle, **kwargs): handle_id = int(kwargs.get('pk')) q = """ MATCH (h:Host {handle_id: {handle_id}})<-[r:Depends_on]-(s:Host_Service) WHERE h.operational_state <> 'Decommissioned' AND r.state CONTAINS 'open' AND r.noclook_last_seen > {last_seen} RETURN h.handle_id as handle_id, h.ip_addresses as ip_addresses, collect(distinct r.protocol + r.port) as ports """ host_list = nc.query_to_list(nc.graphdb.manager, q, handle_id=handle_id, last_seen=self.last_seen()) if len(host_list) == 0: raise NotFound( 'HostScan object not found with handle_id: {}'.format( handle_id)) if len(host_list) > 1: raise HttpMultipleChoices( 'Found {} HostScan objects with handle_id: {}'.format( len(host_list), handle_id)) return HostScan(host_list[0])
def search_location_typeahead(request): response = HttpResponse(content_type='application/json') to_find = request.GET.get('query', None) result = [] if to_find: # split for search match_q = regex_escape(to_find.split()) try: # find all has relations to the top q = """ MATCH (l:Location) WHERE l.name =~ $name_re MATCH p = () - [:Has * 0..20]->(l) WITH COLLECT(nodes(p)) as paths, MAX(length(nodes(p))) AS maxLength, l.handle_id as handle_id WITH FILTER(path IN paths WHERE length(path) = maxLength) AS longestPaths, handle_id as handle_id UNWIND(longestPaths) AS location_path RETURN REDUCE(s = "", n IN location_path | s + n.name + " ") AS name, handle_id """ name_re = '(?i).*{}.*'.format('.*'.join(match_q)) result = nc.query_to_list(nc.graphdb.manager, q, name_re=name_re) except Exception as e: raise e json.dump(result, response) return response
def list_organizations(request): q = """ MATCH (org:Organization) OPTIONAL MATCH (parent_org)-[:Parent_of]->(org:Organization) RETURN org, parent_org ORDER BY org.name """ org_list = nc.query_to_list(nc.graphdb.manager, q) urls = get_node_urls(org_list) table = Table('Name', 'Parent Org.') table.rows = [] orgs_dict = {} for item in org_list: org = item['org'] parent_org = item['parent_org'] org_handle_id = org.get('handle_id') if org_handle_id not in orgs_dict: orgs_dict[org_handle_id] = {'org': org, 'parent_orgs': []} if item['parent_org']: orgs_dict[org_handle_id]['parent_orgs'].append(item['parent_org']) for org_dict in orgs_dict.values(): table.rows.append( _organization_table(org_dict['org'], org_dict['parent_orgs'])) table.no_badges = True return render(request, 'noclook/list/list_generic.html', { 'table': table, 'name': 'Organizations', 'urls': urls })
def host_user_detail(request, handle_id): nh = get_object_or_404(NodeHandle, pk=handle_id) # Get node from neo4j-database host_user = nh.get_node() last_seen, expired = helpers.neo4j_data_age(host_user.data) result = host_user.with_same_name() same_name_relations = NodeHandle.objects.in_bulk( (result.get('ids'))).values() q = """ MATCH (n:Node {handle_id: {handle_id}})-[r:Uses|:Owns]->(u) RETURN labels(u) as labels, u.handle_id as handle_id, u.name as name, u.noclook_last_seen as noclook_last_seen, u.noclook_auto_manage as noclook_auto_manage """ host_relationships = nc.query_to_list(nc.graphdb.manager, q, handle_id=host_user.handle_id) urls = helpers.get_node_urls(host_user, same_name_relations, host_relationships) return render( request, 'noclook/detail/host_user_detail.html', { 'node_handle': nh, 'node': host_user, 'last_seen': last_seen, 'expired': expired, 'same_name_relations': same_name_relations, 'host_relationships': host_relationships, 'history': True, 'urls': urls }, )
def list_services(request, service_class=None): where_statement = '' name = 'Services' if service_class: where_statement = 'WHERE service.service_class = "%s"' % service_class name = '{} Services'.format(service_class) q = """ MATCH (service:Service) %s OPTIONAL MATCH (service)<-[:Uses]-(customer:Customer) WITH service, COLLECT(customer) as customers OPTIONAL MATCH (service)<-[:Uses]-(end_user:End_User) RETURN service, customers, COLLECT(end_user) as end_users ORDER BY service.name """ % where_statement service_list = nc.query_to_list(nc.graphdb.manager, q) service_list = _filter_operational_state(service_list, request, select=lambda n: n.get('service')) urls = get_node_urls(service_list) table = Table('Service', 'Service Class', 'Service Type', 'Description', 'Customers', 'End Users') table.rows = [ _service_table(item['service'], item['customers'], item['end_users']) for item in service_list ] _set_filters_operational_state(table, request) return render(request, 'noclook/list/list_generic.html', { 'table': table, 'name': name, 'urls': urls })
def list_optical_paths(request): q = """ MATCH (path:Optical_Path) RETURN path ORDER BY path.name """ optical_path_list = nc.query_to_list(nc.graphdb.manager, q) optical_path_list = _filter_operational_state( optical_path_list, request, select=lambda n: n.get('path')) urls = get_node_urls(optical_path_list) table = Table('Optical Path', 'Framing', 'Capacity', 'Wavelength', 'Description', 'ENRs') table.rows = [ _optical_path_table(item['path']) for item in optical_path_list ] _set_filters_operational_state(table, request) return render(request, 'noclook/list/list_generic.html', { 'table': table, 'name': 'Optical Paths', 'urls': urls })
def list_odfs(request): q = """ MATCH (odf:ODF) OPTIONAL MATCH (odf)-[:Located_in]->(location) OPTIONAL MATCH (location)<-[:Has]-(site) RETURN odf, location, site ORDER BY site.name, location.name, odf.name """ odf_list = nc.query_to_list(nc.graphdb.manager, q) odf_list = _filter_operational_state(odf_list, request, select=lambda n: n.get('odf')) urls = get_node_urls(odf_list) table = Table("Location", "Name") table.rows = [_odf_table(item) for item in odf_list] # Filter out _set_filters_operational_state(table, request) return render(request, 'noclook/list/list_generic.html', { 'table': table, 'name': 'ODFs', 'urls': urls })
def get(self, request, slug, handle_id): nh = get_object_or_404(NodeHandle, handle_id=handle_id) q = """ MATCH p=(n:Node {handle_id: {handle_id}})-[r:Has|:Located_in*1..3]-(x) WHERE (not exists(x.operational_state) or x.operational_state <> 'Decommissioned') RETURN tail(nodes(p)) as nodes, labels(x) as labels """ results = nc.query_to_list(nc.graphdb.manager, q, handle_id=nh.handle_id) output = self.extract_results(results) # Sorting output... helpers.sort_nicely(output, "name") for item in output: self.sort_data(item) json_result = json.dumps(output, indent=4) filename = u"{}.{}_export.json".format(nh.node_type, nh.node_name) resp = HttpResponse(json_result, content_type="application/json") resp['Content-Disposition'] = u'attachment; filename="{}"'.format( filename) return resp
def typeahead_slugs(request, slug='Node'): response = HttpResponse(content_type='application/json') to_find = request.GET.get('query', None) result = [] if to_find: # split for search match_q = regex_escape(to_find.split()) labels = [helpers.slug_to_node_type(slug).get_label() for s in slug.split('+')] try: q = """ MATCH (n:Node) WHERE any(label in labels(n) where label in $labels) OPTIONAL MATCH (n)<-[:Has]-(e:Node) WITH n.handle_id as handle_id, coalesce(e.name, "") + " "+ n.name as name WHERE name =~ $name_re RETURN handle_id, trim(name) as name """ name_re = '(?i).*{}.*'.format('.*'.join(match_q)) result = nc.query_to_list(nc.graphdb.manager, q, labels=labels, name_re=name_re) except Exception as e: raise e json.dump(result, response) return response
def handle(self, *args, **options): for contract_number in options['contract_number']: utcnow = datetime.utcnow() last_month = utcnow - relativedelta(months=1) subject = 'NOCLook host report for %s' % contract_number to = getattr(django_settings, 'REPORTS_TO', []) cc = getattr(django_settings, 'REPORTS_CC', None) bcc = getattr(django_settings, 'REPORTS_BCC', None) extra_report = getattr(django_settings, 'EXTRA_REPORT_TO', {}) extended_to = to + extra_report.get(contract_number, []) # Avoid changing REPORTS_TO :) body = ''' This is an auto generated report from NOCLook for contract number %s. This report was generated on %s UTC. ''' % (contract_number, utcnow.strftime('%Y-%m-%d %H:%M')) price_per_host = 95 header = [ 'Host user', 'Host', 'Host type', 'IP address(es)', 'Contract number', 'Description', 'Responsible', 'Backup', 'Syslog', 'Nagios', 'Operational State', 'Security Class', 'Location', 'Last seen', 'Uptime (days)' ] result = [] q = ''' MATCH (host_user:Host_User)-[r:Uses|Owns]->(host:Host) WHERE host.contract_number = {contract_number} RETURN host_user.name as host_user_name, host.name, host.handle_id as host_handle_id ORDER BY host_user.name, host.name ''' for item in nc.query_to_list(nc.graphdb.manager, q, contract_number=contract_number): host = nc.get_node_model(nc.graphdb.manager, item['host_handle_id']) age = helpers.neo4j_report_age(host.data, 15, 30) operational_state = host.data.get('operational_state', 'Not set') host_type = host.meta_type host_user = item['host_user_name'] uptime = host.data.get('uptime', '') if uptime: uptime = timestamp_to_td(uptime).days if host_type == 'Logical' and age != 'very_old' and operational_state != 'Decommissioned': values = [ u'{}'.format(host_user), u'{}'.format(host.data['name']), u'{}'.format(host_type).capitalize(), u', '.join([address for address in host.data['ip_addresses']]), u'{}'.format(host.data['contract_number']), u'{}'.format(host.data.get('description', '')), u'{}'.format(host.data.get('responsible_group', '')), u'{}'.format(host.data.get('backup', 'Not set')), u'{}'.format(yesno(host.data.get('syslog', None), 'Yes,No,Not set')), u'{}'.format(yesno(host.data.get('nagios_checks', False), 'Yes,No,Not set')), u'{}'.format(operational_state), u'{}'.format(host.data.get('security_class', '')), u'{}'.format(''), u'{}'.format(date(helpers.isots_to_dt(host.data), "Y-m-d")), u'{}'.format(uptime), ] result.append(dict(zip(header, values))) num_hosts = len(result) filename = '%s hosts %s.xls' % (contract_number, last_month.strftime('%B %Y')) wb = helpers.dicts_to_xls(result, header, contract_number) # Calculate and write pricing info ws = wb.get_sheet(0) ws.write(num_hosts + 2, 1, 'Number of Virtual Servers') ws.write(num_hosts + 2, 4, '%d' % num_hosts) ws.write(num_hosts + 3, 1, 'Price') ws.write(num_hosts + 3, 4, '%d' % price_per_host) ws.write(num_hosts + 4, 1, 'Total Invoice amount ex. VAT') ws.write(num_hosts + 4, 4, '%d' % (num_hosts * price_per_host)) with tempfile.TemporaryFile() as temp: wb.save(temp) temp.seek(0) msg = helpers.create_email(subject, body, extended_to, cc, bcc, temp.read(), filename, 'application/excel') msg.send() self.stdout.write('Sent report for contract number {}'.format(contract_number))
def gmaps_optical_nodes(request): """ Return a json object with dicts of optical node and cables. { nodes: [ { name: '', url: '', lng: 0.0, lat: 0.0 }, ], edges: [ { name: '', url: '', end_points: [{lng: 0.0, lat: 0.0,},] } ] """ # Cypher query to get all cables with cable type fiber that are connected # to two optical node. q = """ MATCH (cable:Cable) WHERE cable.cable_type = "Dark Fiber" MATCH (cable)-[Connected_to]->(port) WITH cable, port MATCH (port)<-[:Has*0..]-(equipment) WHERE (equipment:Optical_Node) AND NOT equipment.type =~ "(?i).*tss.*" WITH cable, port, equipment MATCH p2=(equipment)-[:Located_in]->()<-[:Has*0..]-(loc) WHERE (loc:Site) RETURN cable, equipment, loc """ result = nc.query_to_list(nc.graphdb.manager, q) nodes = {} edges = {} for item in result: node = { 'name': item['equipment']['name'], 'url': helpers.get_node_url(item['equipment']['handle_id']), 'lng': float(str(item['loc'].get('longitude', 0))), 'lat': float(str(item['loc'].get('latitude', 0))) } coords = { 'lng': float(str(item['loc'].get('longitude', 0))), 'lat': float(str(item['loc'].get('latitude', 0))) } edge = { 'name': item['cable']['name'], 'url': helpers.get_node_url(item['cable']['handle_id']), 'end_points': [coords] } nodes[item['equipment']['name']] = node if item['cable']['name'] in edges: edges[item['cable']['name']]['end_points'].append(coords) else: edges[item['cable']['name']] = edge response = HttpResponse(content_type='application/json') json.dump({ 'nodes': list(nodes.values()), 'edges': list(edges.values()) }, response) return response
def create_generic_graph(root_node, graph_dict=None): """ Creates a data structure from the root node and adjacent nodes. This will be done in a special way for known node types else a generic way will be used. {"nodes": { id: { "color": "", "label": "" }, "edges": { id: { "other_id": { "directed": true, "label": "" } } } """ if not graph_dict: graph_dict = {'nodes': defaultdict(dict), 'edges': defaultdict(dict)} # Generic graph dict graph_dict['nodes'].update({ root_node.handle_id: { 'color': COLOR_MAP[root_node.meta_type], 'label': '{} {}'.format(labels_to_node_type(root_node.labels), root_node.data['name']), 'fixed': True, } }) q = """ MATCH (n:Node {handle_id: {handle_id}})-[r]->(end) WHERE NOT end.operational_state IN ['Decommissioned'] OR NOT exists(end.operational_state) RETURN type(r) as relation, collect(distinct end) as nodes """ relations = nc.query_to_list(nc.graphdb.manager, q, handle_id=root_node.handle_id) q = """ MATCH (n:Node {handle_id: {handle_id}})<-[r]-(start) WHERE NOT start.operational_state IN ['Decommissioned'] OR NOT exists(start.operational_state) RETURN type(r) as relation, collect(distinct start) as nodes """ dependencies = nc.query_to_list(nc.graphdb.manager, q, handle_id=root_node.handle_id) for rel in relations: rel_type = rel['relation'].replace('_', ' ') for node in rel['nodes']: graph_dict['nodes'].update(to_arbor_node(node)) graph_dict['edges'][root_node.handle_id].update({ n['handle_id']: { "directed": True, "label": rel_type } for n in rel['nodes'] }) for dep in dependencies: rel_type = dep['relation'].replace('_', ' ') for node in dep['nodes']: graph_dict['nodes'].update(to_arbor_node(node)) graph_dict['edges'][node['handle_id']].update( {root_node.handle_id: { "directed": True, "label": rel_type }}) urls = get_node_urls(root_node, relations, dependencies) for node in graph_dict['nodes']: graph_dict['nodes'][node]['url'] = urls.get(node) return graph_dict