def _get_asset(o: Object): def get_asset_data(data): rd = {} for d in data: if d.interface not in rd: rd[d.interface] = {} rd[d.interface][d.attr] = d.value return rd rev = o.get_data("asset", "revision") if rev == "None": rev = "" r = { "id": str(o.id), "model": { "id": str(o.model.id), "name": str(o.model.name), "vendor": {"id": str(o.model.vendor.id), "name": str(o.model.vendor.name)}, "labels": [str(t) for t in o.model.labels or []], # Alias "tags": [str(t) for t in o.model.labels or []], }, "serial": o.get_data("asset", "serial") or "", "revision": rev, "data": get_asset_data(o.data), "slots": [], } if_map = {c.name: c.interface_name for c in o.connections if c.interface_name} for n in o.model.connections: if n.direction == "i": c, r_object, _ = o.get_p2p_connection(n.name) r["slots"] += [ { "name": n.name, "direction": n.direction, "protocols": [str(p) for p in n.protocols], } ] if c: r["slots"][-1]["asset"] = ManagedObjectDataStream._get_asset(r_object) elif n.direction == "s": r["slots"] += [ { "name": n.name, "direction": n.direction, "protocols": [str(p) for p in n.protocols], } ] if n.name in if_map: r["slots"][-1]["interface"] = if_map[n.name] return r
def connect_twinax(self, o1: Object, c1: str, o2: Object, c2: str): """ Connect twinax object o1 and virtual connection c1 to o2:c2 """ free_connections = [] # Resolve virtual name c1 to real connection r_names = [ o1.get_data("twinax", "connection%d" % i) for i in range(1, 3) ] # Check connection is already exists for n in r_names: cn, o, c = o1.get_p2p_connection(n) if not cn: free_connections += [n] continue if o.id == o2.id and c == c2: # Already connected return # Check twinax has free connection if not free_connections: self.logger.error("Twinax has no free connections") return # Connect first free to o2:c2 c = free_connections[0] self.logger.info("Using twinax connection '%s' instead of '%s'", c, c1) self.connect_p2p(o1, c, o2, c2)
def get_name(obj: Object, managed_object: Optional[Any] = None) -> str: """ Generate discovered object's name """ name = None if managed_object: name = managed_object.name sm = obj.get_data("stack", "member") if sm is not None: # Stack member name += "#%s" % sm return name
def submit( self, type: str, part_no: List[str], number: Optional[str] = None, builtin: bool = False, vendor: Optional[str] = None, revision: Optional[str] = None, serial: Optional[str] = None, mfg_date: Optional[str] = None, description: Optional[str] = None, ): # Check the vendor and the serial are sane # OEM transceivers return binary trash often if vendor: # Possible dead code try: vendor.encode("utf-8") except UnicodeDecodeError: self.logger.info("Trash submited as vendor id: %s", vendor.encode("hex")) return if serial: # Possible dead code try: serial.encode("utf-8") except UnicodeDecodeError: self.logger.info("Trash submited as serial: %s", serial.encode("hex")) return # is_unknown_xcvr = not builtin and part_no[0].startswith( "Unknown | Transceiver | ") if not type and is_unknown_xcvr: type = "XCVR" # Skip builtin modules if builtin: # Adjust context anyway self.prepare_context(type, number) return # Builtin must aways have type set # if is_unknown_xcvr: self.logger.info("%s S/N %s should be resolved later", part_no[0], serial) self.prepare_context(type, number) self.objects += [("XCVR", part_no[0], self.ctx.copy(), serial)] return # Cache description if description: for p in part_no: if p not in self.pn_description: self.pn_description[p] = description # Find vendor vnd = self.get_vendor(vendor) if not vnd: # Try to resolve via model map m = self.get_model_map(vendor, part_no, serial) if not m: self.logger.error("Unknown vendor '%s' for S/N %s (%s)", vendor, serial, description) return else: # Find model m = ObjectModel.get_model(vnd, part_no) if not m: # Try to resolve via model map m = self.get_model_map(vendor, part_no, serial) if not m: self.logger.info( "Unknown model: vendor=%s, part_no=%s (%s). " "Skipping", vnd.name, part_no, description, ) self.register_unknown_part_no(vnd, part_no, description) return # Sanitize serial number against the model serial = self.clean_serial(m, number, serial) # if m.cr_context and type != m.cr_context: # Override type with object mode's one self.logger.info("Model changes type to '%s'", m.cr_context) type = m.cr_context if not type: self.logger.info( "Cannot resolve type for: vendor=%s, part_no=%s (%s). " "Skipping", vnd.name, description, part_no, ) return self.prepare_context(type, number) # Get connection rule if not self.rule and m.connection_rule: self.set_rule(m.connection_rule) # Set initial context if type in self.rule_context: scope = self.rule_context[type][0] if scope: self.set_context(scope, number) # Find existing object or create new o: Optional["Object"] = Object.objects.filter(model=m.id, data__match={ "interface": "asset", "attr": "serial", "value": serial }).first() if not o: # Create new object self.logger.info("Creating new object. model='%s', serial='%s'", m.name, serial) data = [ ObjectAttr(scope="", interface="asset", attr="serial", value=serial) ] if revision: data += [ ObjectAttr(scope="", interface="asset", attr="revision", value=revision) ] if mfg_date: data += [ ObjectAttr(scope="", interface="asset", attr="mfg_date", value=mfg_date) ] if self.object.container: container = self.object.container.id else: container = self.lost_and_found o = Object(model=m, data=data, container=container) o.save() o.log( "Created by asset_discovery", system="DISCOVERY", managed_object=self.object, op="CREATE", ) else: # Add all connection to disconnect list self.to_disconnect.update( set((o, c[0], c[1], c[2]) for c in o.iter_inner_connections())) # Check revision if o.get_data("asset", "revision") != revision: # Update revision self.logger.info( "Object revision changed [%s %s] %s -> %s", m.name, o.id, o.get_data("asset", "revision"), revision, ) o.set_data("asset", "revision", revision) o.save() o.log( "Object revision changed: %s -> %s" % (o.get_data("asset", "revision"), revision), system="DISCOVERY", managed_object=self.object, op="CHANGE", ) # Check manufacturing date if mfg_date and o.get_data("asset", "revision") != revision: # Update revision self.logger.info( "Object manufacturing date changed [%s %s] %s -> %s", m.name, o.id, o.get_data("asset", "mfg_date"), mfg_date, ) o.set_data("asset", "mfg_date", mfg_date) o.save() o.log( "Object manufacturing date: %s -> %s" % (o.get_data("asset", "mfg_date"), mfg_date), system="DISCOVERY", managed_object=self.object, op="CHANGE", ) # Check management if o.get_data("management", "managed"): if o.get_data("management", "managed_object") != self.object.id: self.logger.info("Changing object management to '%s'", self.object.name) o.set_data("management", "managed_object", self.object.id) o.save() o.log( "Management granted", system="DISCOVERY", managed_object=self.object, op="CHANGE", ) self.update_name(o) if o.id in self.managed: self.managed.remove(o.id) self.objects += [(type, o, self.ctx.copy(), serial)] # Collect stack members if number and o.get_data("stack", "stackable"): self.stack_member[o] = number
def submit(self, type, part_no, number=None, builtin=False, vendor=None, revision=None, serial=None, description=None): # Check the vendor and the serial are sane # OEM transceivers return binary trash often if vendor: try: vendor.encode("utf-8") except UnicodeDecodeError: self.info("Trash submited as vendor id: %s" % vendor.encode("hex")) return if serial: try: serial.encode("utf-8") except UnicodeDecodeError: self.info("Trash submited as serial: %s" % serial.encode("hex")) return # is_unknown_xcvr = (not builtin and part_no[0].startswith("Unknown | Transceiver | ")) if not type and is_unknown_xcvr: type = "XCVR" # Skip builtin modules if builtin: # Adjust context anyway self.prepare_context(type, number) return # Builtin must aways have type set # if is_unknown_xcvr: self.debug("%s S/N %s should be resolved later" % (part_no[0], serial)) self.prepare_context(type, number) self.objects += [("XCVR", part_no[0], self.ctx.copy(), serial)] return # Cache description if description: for p in part_no: if p not in self.pn_description: self.pn_description[p] = description # Find vendor vnd = self.get_vendor(vendor) if not vnd: # Try to resolve via model map m = self.get_model_map(vendor, part_no, serial) if not m: self.error("Unknown vendor '%s' for S/N %s (%s)" % (vendor, serial, description)) return else: # Find model m = ObjectModel.get_model(vnd, part_no) if not m: # Try to resolve via model map m = self.get_model_map(vendor, part_no, serial) if not m: self.debug( "Unknown model: vendor=%s, part_no=%s (%s). Skipping" % (vnd.name, description, part_no)) self.register_unknown_part_no(vnd, part_no, description) return if m.cr_context and type != m.cr_context: # Override type with object mode's one self.debug("Model changes type to '%s'" % m.cr_context) type = m.cr_context if not type: self.debug( "Cannot resolve type for: vendor=%s, part_no=%s (%s). Skipping" % (vnd.name, description, part_no)) return self.prepare_context(type, number) # Get connection rule if not self.rule and m.connection_rule: self.set_rule(m.connection_rule) # Set initial context if type in self.rule_context: scope = self.rule_context[type][0] if scope: self.set_context(scope, number) # if not serial or serial == "None": serial = self.generate_serial(m, number) self.info("Generating virtual serial: %s" % serial) # Find existing object or create new o = Object.objects.filter(model=m.id, data__asset__serial=serial).first() if not o: # Create new object self.info("Creating new object. model='%s', serial='%s'" % (m.name, serial)) data = {"asset": {"serial": serial}} if revision: data["asset"]["revision"] = revision o = Object(model=m, data=data, container=self.lost_and_found) o.save() o.log("Created by asset_discovery", system="DISCOVERY", managed_object=self.object, op="CREATE") # Check revision if o.get_data("asset", "revision") != revision: # Update revision self.info( "Object revision changed [%s %s] %s -> %s" % (m.name, o.id, o.get_data("asset", "revision"), revision)) o.set_data("asset", "revision", revision) o.save() o.log("Object revision changed: %s -> %s" % (o.get_data("asset", "revision"), revision), system="DISCOVERY", managed_object=self.object, op="CHANGE") # Check management if o.get_data("management", "managed"): if o.get_data("management", "managed_object") != self.object.id: self.info("Changing object management to '%s'" % self.object.name) o.set_data("management", "managed_object", self.object.id) o.save() o.log("Management granted", system="DISCOVERY", managed_object=self.object, op="CHANGE") self.update_name(o) if o.id in self.managed: self.managed.remove(o.id) self.objects += [(type, o, self.ctx.copy(), serial)] # Collect stack members if number and o.get_data("stack", "stackable"): self.stack_member[o] = number