def reduce_switchport(task): from noc.lib.app.simplereport import Report, TableSection,\ SectionRow, TableColumn from noc.lib.text import list_to_ranges # Prepare data data = [] for mt in task.maptask_set.filter(status="C"): data += [SectionRow("%s (%s)" % ( mt.managed_object.name, mt.managed_object.profile_name))] for r in mt.script_result: data += [[ r["interface"], r.get("description", ""), r["status"], r.get("untagged", ""), list_to_ranges(r.get("tagged", [])), ", ".join(r.get("members", [])) ]] # Prepare report r = Report() r.append_section(TableSection(name="", columns=["Interface", "Description", TableColumn("Status", format="bool"), "Untagged", "Tagged", "Members"], data=data)) return r
def clean(self, value): if isinstance(value, six.string_types) and not value.strip(): return "" vp = VLANIDParameter() try: return list_to_ranges([vp.clean(v) for v in ranges_to_list(value)]) except SyntaxError: self.raise_error(value)
def clean(self, value): """ >>> VLANIDMapParameter().clean("1,2,5-10") '1-2,5-10' >>> VLANIDMapParameter().clean("") '' """ if isinstance(value, basestring) and not value.strip(): return "" vp = VLANIDParameter() try: return list_to_ranges([vp.clean(v) for v in ranges_to_list(value)]) except SyntaxError: self.raise_error(value)
def get_data(self, request, sel): """Get_data function.""" data = [] columns = [ _("Managed Objects"), _("Switch availability status"), _("IP address"), _("Model"), _("Software"), _("Port name"), _("Port status"), _("Link status"), _("VLAN id") ] ip = InterfaceProfile.objects.get(name=sel.name) interf = Interface.objects.filter(profile=ip, type="physical") for i in interf: si = list(i.subinterface_set.filter(enabled_afi="BRIDGE")) if len(si) == 1: si = si[0] try: tagged = (list_to_ranges(si.tagged_vlans).replace( ",", ", ")).strip() data += [[ i.managed_object.name, "Is available" if i.managed_object.get_status() is True else "Not available", i.managed_object.address, str(i.managed_object.vendor) + " " + str(i.managed_object.platform), "\"" + str(i.managed_object.version) + "\"", i.name, "UP" if i.admin_status is True else "Down", "UP" if i.oper_status is True else "Down", ("U: " + str(si.untagged_vlan) if si.untagged_vlan is not None else "" + " T: " + tagged if tagged != "" else "").strip() ]] except AttributeError: pass return self.from_dataset(title=self.title, columns=columns, data=data, enumerate=True)
def execute(self, configs, protect_switchport=True, protect_type=True, debug=False): def is_access(c): return "untagged" in c and ("tagged" not in c or not c["tagged"]) # Get existing switchports. interface -> config ports = dict( (p["interface"], p) for p in self.scripts.get_switchport()) # Validate restrictions errors = [] for c in configs: iface = c["interface"] if protect_switchport and iface not in ports: errors += ["Interface '%s' is not switchport" % iface] if protect_type and is_access(c) != is_access(ports[iface]): errors += ["Invalid port type for interface '%s'" % iface] if errors: return {"status": False, "message": ".\n".join(errors)} # Prepare scenario commands = [] for c in configs: ic = [] iface = c["interface"] p = ports[iface] # Check description if ("description" in c and c["description"] and ("description" not in p or c["description"] != p["description"])): ic += [" description %s" % c["description"]] # Check status if c["status"] and not p["status"]: ic += [" no shutdown"] elif p["status"] and not c["status"]: ic += [" shutdown"] # Check switchport if iface not in ports: ic += [" switchport"] if is_access(c): # Configuring access port if not is_access(p): # trunk -> access ic += [" switchport mode access"] ic += [" no switchport trunk allowed vlan"] # ic += [" switchport trunk allowed vlan remove all"] # ??? ic += [" no switchport trunk native vlan"] # @todo: set vlan only when necessary ic += [" switchport access vlan %d" % c["untagged"]] else: # Configuring trunk port if is_access(p): # access -> trunk # ic += [" switchport trunk encapsulation dot1q"] ic += [" switchport mode trunk"] ic += [" no switchport access vlan"] if ("untagged" in c and ("untagged" not in p or c["untagged"] != p["untagged"]) or is_access(p)): # Add native vlan ic += [" switchport trunk native vlan %d" % c["untagged"]] if "untagged" not in c and "untagged" in p: # Remove native vlan ic += [" no switchport trunk native vlan"] cv = list_to_ranges(c["tagged"]) pv = list_to_ranges(p["tagged"]) if cv != pv: # Change untagged vlans ic += [" switchport trunk allowed vlan add %s" % cv] # Configure edge-port ept = { True: "spanning-tree portfast", False: "spanning-tree portfast trunk" } if is_access(c) != is_access(p): # access <-> trunk. Remove old edgeport settings ic += [" no %s" % ept[not is_access(c)]] if c["edge_port"]: ic += [" %s" % ept[is_access(c)]] else: ic += [" no %s" % ept[is_access(c)]] # if ic: commands += ["interface %s" % iface] + ic + [" exit"] # Apply commands if not debug and commands: with self.configure(): for c in commands: self.cli(c) self.save_config() # Return result return {"status": True, "message": "Ok", "log": "\n".join(commands)}
def api_report( self, request, o_format, administrative_domain=None, selector=None, interface_profile=None, zero=None, def_profile=None, columns=None, enable_autowidth=False, ): def humanize_speed(speed): if not speed: return "-" for t, n in [(1000000, "G"), (1000, "M"), (1, "k")]: if speed >= t: if speed // t * t == speed: return "%d%s" % (speed // t, n) else: return "%.2f%s" % (float(speed) / t, n) return str(speed) def row(row): def qe(v): if v is None: return "" if isinstance(v, unicode): return v.encode("utf-8") elif isinstance(v, datetime.datetime): return v.strftime("%Y-%m-%d %H:%M:%S") elif not isinstance(v, str): return str(v) else: return v return [qe(x) for x in row] def translate_row(row, cmap): return [row[i] for i in cmap] cols = [ "object_name", "object_address", "object_model", "object_software", "object_port_name", "object_port_profile_name", "object_port_status", "object_link_status", "object_port_speed", "object_port_duplex", "object_port_untagged_vlan", "object_port_tagged_vlans", ] header_row = [ "MANAGED_OBJECT", "OBJECT_ADDRESS", "OBJECT_MODEL", "OBJECT_SOFTWARE", "PORT_NAME", "PORT_PROFILE_NAME", "PORT_STATUS", "LINK_STATUS", "PORT_SPEED", "PORT_DUPLEX", "PORT_UNTAGGED_VLAN", "PORT_TAGGED_VLANS", ] if columns: cmap = [] for c in columns.split(","): try: cmap += [cols.index(c)] except ValueError: continue else: cmap = list(range(len(cols))) r = [translate_row(header_row, cmap)] mo = {} if_p = {} DUPLEX = {True: "Full", False: "Half"} for ifp in InterfaceProfile.objects.filter(): if_p[ifp.id] = {"name": ifp.name} mos = ManagedObject.objects.filter(is_managed=True) if (request.user.is_superuser and not administrative_domain and not selector and not interface_profile): mos = ManagedObject.objects.filter(is_managed=True) if not request.user.is_superuser: mos = mos.filter( administrative_domain__in=UserAccess.get_domains(request.user)) if administrative_domain: ads = AdministrativeDomain.get_nested_ids( int(administrative_domain)) mos = mos.filter(administrative_domain__in=ads) if selector: selector = ManagedObjectSelector.get_by_id(int(selector)) mos = mos.filter(selector.Q) for o in mos: mo[o.id] = { "type": "managedobject", "id": str(o.id), "name": o.name, "status": o.is_managed, "address": o.address, "vendor": o.vendor, "version": o.version, "platform": o.platform, } mos_id = list(mos.values_list("id", flat=True)) rld = ReportInterfaceStatus(mos_id, zero, def_profile, interface_profile) for i in rld.out: untag, tagged = "", "" if i["subs"]: untag = i["subs"][0].get("untagged_vlan", "") tagged = list_to_ranges(i["subs"][0].get("tagged_vlans", [])) r += [ translate_row( row([ mo[i["managed_object"]]["name"], mo[i["managed_object"]]["address"], "%s %s" % ( str(mo[i["managed_object"]]["vendor"]), str(mo[i["managed_object"]]["platform"]), ), str(mo[i["managed_object"]]["version"]), i["name"], if_p[i["profile"]]["name"], "UP" if i["admin_status"] is True else "Down", "UP" if "oper_status" in i and i["oper_status"] is True else "Down", humanize_speed(i["in_speed"]) if "in_speed" in i else "-", DUPLEX.get(i["full_duplex"]) if "full_duplex" in i and "in_speed" in i else "-", untag, tagged, ]), cmap, ) ] filename = "interface_status_report_%s" % datetime.datetime.now( ).strftime("%Y%m%d") if o_format == "csv": response = HttpResponse(content_type="text/csv") response[ "Content-Disposition"] = 'attachment; filename="%s.csv"' % filename writer = csv.writer(response, dialect="excel", delimiter=";") writer.writerows(r) return response elif o_format == "xlsx": response = StringIO() wb = xlsxwriter.Workbook(response) cf1 = wb.add_format({"bottom": 1, "left": 1, "right": 1, "top": 1}) ws = wb.add_worksheet("Objects") max_column_data_length = {} for rn, x in enumerate(r): for cn, c in enumerate(x): if rn and (r[0][cn] not in max_column_data_length or len(str(c)) > max_column_data_length[r[0][cn]]): max_column_data_length[r[0][cn]] = len(str(c)) ws.write(rn, cn, c, cf1) ws.autofilter(0, 0, rn, cn) ws.freeze_panes(1, 0) for cn, c in enumerate(r[0]): # Set column width width = get_column_width(c) if enable_autowidth and width < max_column_data_length[c]: width = max_column_data_length[c] ws.set_column(cn, cn, width=width) wb.close() response.seek(0) response = HttpResponse(response.getvalue(), content_type="application/vnd.ms-excel") # response = HttpResponse( # content_type="application/x-ms-excel") response[ "Content-Disposition"] = 'attachment; filename="%s.xlsx"' % filename response.close() return response
def process_mstp(self): r = { "mode": "MSTP", "instances": [], "configuration": { "MSTP": { "region": self.mib_get("hpicfBridgeMSTRegionName"), "revision": self.mib_get("hpicfBridgeMSTRegionRevision") } } } # Get bridge id bridge_id = self.mib_get("dot1dBaseBridgeAddress").replace(" ", "") bridge_id = "%s-%s" % (bridge_id[:6], bridge_id[6:]) # Create instances instances = {} # id -> {data} """ instance id -> data: interface, port_id, state, role, priority, designated_bridge_id, designated_bridge_priority, designated_port_id, edge, point_to_point """ interfaces = {} v = self.mib_walk("hpicfBridgeMSTInstanceRowStatus") for instance_id in v: if v[instance_id] == "1": instances[instance_id] = {"id": instance_id} interfaces[instance_id] = {} # Set root id and root priority v = self.mib_walk("hpicfBridgeMSTInstanceDesignatedRoot") for instance_id in v: if instance_id in instances: root = v[instance_id].replace(" ", "") root_priority = int(root[:2] + "00", 16) root = "%s-%s" % (root[4:10], root[10:]) instances[instance_id]["root_id"] = root instances[instance_id]["root_priority"] = root_priority # Set bridge priority v = self.mib_walk("hpicfBridgeMSTInstancePriority") for instance_id in v: if instance_id in instances: instances[instance_id]["bridge_id"] = bridge_id instances[instance_id]["bridge_priority"] = v[ instance_id].replace(",", "") # Get instance vlans vlans = {} # instance -> vlans for i in [1, 2, 3, 4]: v = self.mib_walk("hpicfBridgeMSTInstanceVlanMap%dk" % i) for instance_id in v: if instance_id in instances: try: vlans[instance_id] += v[instance_id] except KeyError: vlans[instance_id] = v[instance_id] if not vlans.has_key(0): vlans[0] = '' # Convert bitmask to vlan list rest_vlans = set(range(1, 4096)) for instance_id in vlans: v = set() for i, m in enumerate(vlans[instance_id].split()): m = int(m, 16) for j in range(8): if m & (1 << (7 - j)): vlan = i * 8 + j + 1 v.add(vlan) rest_vlans.remove(vlan) vlans[instance_id] = v # Set instnace vlans for instance_id in vlans: v = vlans[instance_id] if not v and instance_id == 0: v = rest_vlans instances[instance_id]["vlans"] = list_to_ranges(sorted(v)) # # Process interfaces # # port_id -> {"interface","port_id","edge","point_to_point"} ports = {} ifname = self.mib_walk("ifName") v = self.mib_walk("dot1dBasePortIfIndex") for port_id in v: ports[port_id] = { "interface": ifname[int(v[port_id])], "port_id": port_id } # Edge port status v = self.mib_walk("hpicfBridgeRstpOperEdgePort") for port_id in v: ports[port_id]["edge"] = v[port_id] == "1" # point_to_point status v = self.mib_walk("hpicfBridgeRstpOperPointToPointMac") for port_id in v: ports[port_id]["point_to_point"] = v[port_id] == "1" # # Process instance interfaces # instance_ports = {} # instance_id -> port_id -> data for instance_id in instances: instance_ports[instance_id] = {} for port_id in ports: instance_ports[instance_id][port_id] = ports[port_id].copy() # Port priority v = self.mib_walk("hpicfBridgeMSTPortPriority") for instance_id, port_id in v: instance_ports[instance_id][port_id]["priority"] = v[instance_id, port_id] # Port state v = self.mib_walk("hpicfBridgeMSTPortState") for instance_id, port_id in v: instance_ports[instance_id][port_id]["state"] = { "1": "disabled", "2": "discarding", "??": "learning", "5": "forwarding", "_": "unknown" }[v[instance_id, port_id]] # @todo: refine states # Port role v = self.mib_walk("hpicfBridgeMSTPortRole") for instance_id, port_id in v: instance_ports[instance_id][port_id]["role"] = { "1": "disabled", "?": "alternate", "5": "backup", "6": "disabled", "2": "root", "3": "designated", "_": "master", "__": "nonstp", "!!": "unknown" }[v[instance_id, port_id]] # @todo: refine roles # Designated bridge v = self.mib_walk("hpicfBridgeMSTPortDesignatedBridge") for instance_id, port_id in v: bridge = v[instance_id, port_id].replace(" ", "") priority = int(bridge[:2] + "00", 16) bridge = "%s-%s" % (bridge[4:10], bridge[10:]) instance_ports[instance_id][port_id][ "designated_bridge_id"] = bridge instance_ports[instance_id][port_id][ "designated_bridge_priority"] = priority # Designated port v = self.mib_walk("hpicfBridgeMSTPortDesignatedPort") for instance_id, port_id in v: x = v[instance_id, port_id] if " " in x: pr, p = x.split(" ") instance_ports[instance_id][port_id][ "designated_port_id"] = "%d.%d" % (int(pr, 16), int(p, 16)) else: instance_ports[instance_id][port_id][ "designated_port_id"] = "%d.%d" % (ord(x[0]), ord(x[1])) # Fill missed designated bridge ids for instance_id in instance_ports: for port_id in instance_ports[instance_id]: v = instance_ports[instance_id][port_id] if "designated_bridge_id" not in v: v["designated_bridge_id"] = bridge_id if "designated_bridge_priority" not in v: v["designated_bridge_priority"] = 32768 # # Install interfaces # for instance_id in instances: instances[instance_id]["interfaces"] = sorted( instance_ports[instance_id].values(), lambda x, y: cmp(x["port_id"], y["port_id"])) # # Install instances # r["instances"] = sorted(instances.values(), lambda x, y: cmp(x["id"], y["id"])) return r
def get_db_prep_value(self, value, connection, prepared=False): return list_to_ranges(sorted(value))
def switchport_validation_reduce(task): from noc.lib.app.simplereport import Report, TableSection, SectionRow from noc.lib.text import list_to_ranges switchports = {} # object -> interface -> (description, set of vlans) macs = {} # object -> interface -> set of vlans # Collect data for mt in task.maptask_set.filter(status="C"): o = mt.managed_object if mt.map_script.endswith(".get_mac_address_table"): # Populate macs macs[o] = {} for m in mt.script_result: for i in m["interfaces"]: if i not in macs[o]: macs[o][i] = set() macs[o][i].add(m["vlan_id"]) elif mt.map_script.endswith(".get_switchport"): # Populate switchports switchports[o] = {} for p in mt.script_result: if not p["status"]: # Skip ports in shutdown continue i = p["interface"] if i not in switchports[o]: switchports[o][i] = (p.get("description", ""), set()) if "untagged" in p and p["untagged"]: switchports[o][i][1].add(p["untagged"]) if p["tagged"]: switchports[o][i][1].update(p["tagged"]) else: raise Exception("Inconsistent map task") if not macs or not switchports: return "Failed to retrieve the data!!!" # Process data data = [] for o in switchports: if o not in macs or not macs[o]: continue # Find inconsistent ports inconsistent_ports = [] # (port, swtichport vlans, excessive vlans) for i in switchports[o]: if i not in macs[o]: # No mac data for port inconsistent_ports += [(i, switchports[o][i][0], switchports[o][i][1], None)] else: # Remove intersection v = switchports[o][i][1] - macs[o][i] if v: inconsistent_ports += [(i, switchports[o][i][0], switchports[o][i][1], v)] # Add to data if inconsistent ports found if inconsistent_ports: data += [SectionRow(o.name)] data += [(p, d, list_to_ranges(v), list_to_ranges(e) if e is not None else "No MACs found") for p, d, v, e in sorted(inconsistent_ports, lambda x, y: cmp(x[0], y[0]))] # if not data: return "Failed to retrieve data!!!" # Build report r = Report() r.append_section( TableSection("", columns=[ "Port", "Description", "Switchport VLANs", "Excessive VLANs" ], data=data)) return r
def get_data(self): def get_container_path(self): # Get container path if not self.object: return None cp = [] if self.object.container: c = self.object.container.id while c: try: o = Object.objects.get(id=c) # @todo: Address data if o.container: cp.insert(0, { "id": o.id, "name": o.name }) c = o.container.id if o.container else None except DoesNotExist: metrics["error", ("type", "no_such_object")] += 1 break return cp if not self.object: return None # @todo: Stage # @todo: Service range # @todo: Open TT now = datetime.datetime.now() # Get object status and uptime alarms = list(ActiveAlarm.objects.filter(managed_object=self.object.id)) current_start = None duration = None if self.object.is_managed: if self.object.get_status(): if alarms: current_state = "alarm" else: current_state = "up" uptime = Uptime.objects.filter(object=self.object.id, stop=None).first() if uptime: current_start = uptime.start else: current_state = "down" outage = Outage.objects.filter(object=self.object.id, stop=None).first() if outage is not None: current_start = outage.start else: current_state = "unmanaged" if current_start: duration = now - current_start cp = get_container_path(self) # MAC addresses macs = [] o_macs = DiscoveryID.macs_for_object(self.object) if o_macs: for f, l in o_macs: if f == l: macs += [f] else: macs += ["%s - %s" % (f, l)] # Links uplinks = set(self.object.data.uplinks) if len(uplinks) > 1: if self.object.segment.lost_redundancy: redundancy = "L" else: redundancy = "R" else: redundancy = "N" links = [] for l in Link.object_links(self.object): local_interfaces = [] remote_interfaces = [] remote_objects = set() for i in l.interfaces: if i.managed_object.id == self.object.id: local_interfaces += [i] else: remote_interfaces += [i] remote_objects.add(i.managed_object) if len(remote_objects) == 1: ro = remote_objects.pop() if ro.id in uplinks: role = "uplink" else: role = "downlink" links += [{ "id": l.id, "role": role, "local_interface": sorted( local_interfaces, key=lambda x: split_alnum(x.name) ), "remote_object": ro, "remote_interface": sorted( remote_interfaces, key=lambda x: split_alnum(x.name) ), "remote_status": "up" if ro.get_status() else "down" }] links = sorted(links, key=lambda x: (x["role"] != "uplink", split_alnum(x["local_interface"][0].name))) # Build global services summary service_summary = ServiceSummary.get_object_summary(self.object) # Interfaces interfaces = [] mo = ManagedObject.objects.filter(id=self.object.id) iface_metrics, last_ts = get_interface_metrics(mo[0]) iface_metrics = iface_metrics[mo[0]] objects_metrics, last_time = get_objects_metrics(mo[0]) objects_metrics = objects_metrics.get(mo[0]) meta = "" metric_type_name = dict(MetricType.objects.filter().scalar("name", "measure")) metric_type_field = dict(MetricType.objects.filter().scalar("field_name", "measure")) if objects_metrics is not None: if objects_metrics.get("") is not None: for key in objects_metrics.get("").keys(): if metric_type_name[key] in ["bytes", "bit/s", "bool"]: objects_metrics.get("")[key] = { "type": metric_type_name[key], "value": self.humanize_speed(objects_metrics.get("")[key], metric_type_name[key]) } else: objects_metrics.get("")[key] = { "type": metric_type_name[key], "value": objects_metrics.get("")[key] } meta = objects_metrics.get("") else: meta = {} if iface_metrics is not None: for i in Interface.objects.filter(managed_object=self.object.id, type="physical"): load_in = "-" load_out = "-" errors_in = "-" errors_out = "-" iface_get_link_name = iface_metrics.get(str(i.name)) if iface_get_link_name is not None: for key in iface_get_link_name.keys(): meta_type = metric_type_name.get(key) or metric_type_field.get(key) iface_get_link_name[key] = { "type": meta_type, "value": self.humanize_speed( str(iface_get_link_name[key]), meta_type) } if key in ['Interface | Load | In', 'Interface | Load | Out', 'Interface | Errors | In', 'Interface | Errors | Out']: try: load_in = iface_get_link_name['Interface | Load | In']["value"] + \ iface_get_link_name['Interface | Load | In']["type"] load_out = iface_get_link_name['Interface | Load | Out']["value"] + \ iface_get_link_name['Interface | Load | Out']["type"] errors_in = iface_get_link_name['Interface | Errors | In']["value"] errors_out = iface_get_link_name['Interface | Errors | Out']["value"] except TypeError: pass else: iface_get_link_name = {} interfaces += [{ "id": i.id, "name": i.name, "admin_status": i.admin_status, "oper_status": i.oper_status, "mac": i.mac or "", "full_duplex": i.full_duplex, "load_in": load_in, "load_out": load_out, "errors_in": errors_in, "errors_out": errors_out, "speed": max([i.in_speed or 0, i.out_speed or 0]) / 1000, "untagged_vlan": None, "tagged_vlan": None, "profile": i.profile, "service": i.service, "service_summary": service_summary.get("interface").get(i.id, {}) }] si = list(i.subinterface_set.filter(enabled_afi="BRIDGE")) if len(si) == 1: si = si[0] interfaces[-1]["untagged_vlan"] = si.untagged_vlan interfaces[-1]["tagged_vlans"] = list_to_ranges(si.tagged_vlans).replace(",", ", ") interfaces = sorted(interfaces, key=lambda x: split_alnum(x["name"])) # Resource groups # Service groups (i.e. server) static_services = set(self.object.static_service_groups) service_groups = [] for rg_id in self.object.effective_service_groups: rg = ResourceGroup.get_by_id(rg_id) service_groups += [{ "id": rg_id, "name": rg.name, "technology": rg.technology, "is_static": rg_id in static_services }] # Client groups (i.e. client) static_clients = set(self.object.static_client_groups) client_groups = [] for rg_id in self.object.effective_client_groups: rg = ResourceGroup.get_by_id(rg_id) client_groups += [{ "id": rg_id, "name": rg.name, "technology": rg.technology, "is_static": rg_id in static_clients }] # @todo: Administrative domain path # Alarms alarm_list = [] for a in alarms: alarm_list += [{ "id": a.id, "root_id": self.get_root(alarms), "timestamp": a.timestamp, "duration": now - a.timestamp, "subject": a.subject, "managed_object": a.managed_object, "service_summary": { "service": SummaryItem.items_to_dict(a.total_services), "subscriber": SummaryItem.items_to_dict(a.total_subscribers)}, "alarm_class": a.alarm_class }] alarm_list = sorted(alarm_list, key=operator.itemgetter("timestamp")) # Maintenance maintenance = [] for m in Maintenance.objects.filter( affected_objects__object=self.object.id, is_completed=False, start__lte=now + datetime.timedelta(hours=1) ): maintenance += [{ "maintenance": m, "id": m.id, "subject": m.subject, "start": m.start, "stop": m.stop, "in_progress": m.start <= now }] # Get Inventory inv = [] for p in self.object.get_inventory(): c = self.get_nested_inventory(p) c["name"] = p.name or self.object.name inv += [c] # Build result if self.object.platform is not None: platform = self.object.platform.name else: platform = "Unknown" if self.object.version is not None: version = self.object.version.version else: version = "" r = { "id": self.object.id, "object": self.object, "name": self.object.name, "address": self.object.address, "platform": platform, # self.object.platform.name if self.object.platform else "Unknown", "version": version, # self.object.version.version if self.object.version else "", "description": self.object.description, "object_profile": self.object.object_profile.id, "object_profile_name": self.object.object_profile.name, "macs": ", ".join(sorted(macs)), "segment": self.object.segment, "firmware_status": FirmwarePolicy.get_status( self.object.platform, self.object.version), "firmware_recommended": FirmwarePolicy.get_recommended_version(self.object.platform), "service_summary": service_summary, "container_path": cp, "current_state": current_state, # Start of uptime/downtime "current_start": current_start, # Current uptime/downtime "current_duration": duration, "service_groups": service_groups, "client_groups": client_groups, "tt": [], "links": links, "alarms": alarm_list, "interfaces": interfaces, "metrics": meta, "maintenance": maintenance, "redundancy": redundancy, "inventory": self.flatten_inventory(inv), "serial_number": self.object.get_attr("Serial Number") } return r