def init_plugin(self): super(ConduitsPlugin, self).init_plugin() self.add_view("api_plugin_%s_get_neighbors" % self.name, self.api_get_neighbors, url="^(?P<id>[0-9a-f]{24})/plugin/%s/get_neighbors/$" % self.name, method=["GET"]) self.add_view( "api_plugin_%s_create_ducts" % self.name, self.api_create_ducts, url="^(?P<id>[0-9a-f]{24})/plugin/%s/$" % self.name, method=["POST"], validate={ "ducts": DictListParameter( attrs={ "target": DocumentParameter(Object), "project_distance": FloatParameter(), "conduits": DictListParameter( attrs={ "id": DocumentParameter(Object, required=False), "n": IntParameter(), "x": IntParameter(), "y": IntParameter(), "status": BooleanParameter() }) }) }) # self.conduits_model = ObjectModel.objects.filter( name=self.CONDUITS_MODEL).first()
def __init__(self, model): self.model = model self.app = None self.pk_field_name = "id" # Prepare field converters self.clean_fields = self.clean_fields.copy() # name -> Parameter for name, f in self.model._fields.items(): if isinstance(f, BooleanField): self.clean_fields[name] = BooleanParameter() elif isinstance(f, IntField): self.clean_fields[name] = IntParameter() elif isinstance(f, PlainReferenceField): self.clean_fields[name] = DocumentParameter(f.document_type) # if not self.query_fields: self.query_fields = [ "%s__%s" % (n, self.query_condition) for n, f in self.model._fields.items() if f.unique and isinstance(f, StringField) ] # Find field_* and populate custom fields self.custom_fields = {} for fn in [n for n in dir(self) if n.startswith("field_")]: h = getattr(self, fn) if callable(h): self.custom_fields[fn[6:]] = h
def api_action_group_edit(self, request): validator = DictParameter( attrs={"ids": ListOfParameter(element=DocumentParameter(self.model), convert=True)} ) rv = self.deserialize(request.body) try: v = validator.clean(rv) except InterfaceTypeError as e: self.logger.info("Bad request: %r (%s)", request.body, e) return self.render_json( {"status": False, "message": "Bad request", "traceback": str(e)}, status=self.BAD_REQUEST, ) objects = v["ids"] del v["ids"] try: v = self.clean(v) except ValueError as e: return self.render_json( {"status": False, "message": "Bad request", "traceback": str(e)}, status=self.BAD_REQUEST, ) for o in objects: for p in v: setattr(o, p, v[p]) o.save() return "%d records has been updated" % len(objects)
class UnknownModelApplication(ExtDocApplication): """ UnknownModel application """ title = _("Unknown Models") menu = _("Unknown Models") model = UnknownModel query_condition = "icontains" query_fields = [ "vendor", "managed_object", "platform", "part_no", "description" ] @view( url="^actions/remove/$", method=["POST"], access="launch", api=True, validate={ "ids": ListOfParameter(element=DocumentParameter(UnknownModel), convert=True) }, ) def api_action_run_discovery(self, request, ids): UnknownModel.objects.filter(id__in=[x.id for x in ids]) return _("Cleaned")
class ConnectionRuleApplication(ExtDocApplication): """ ConnectionRule application """ title = _("Connection Rules") menu = [_("Setup"), _("Connection Rules")] model = ConnectionRule query_fields = ["name__icontains", "description__icontains"] @view( url="^actions/json/$", method=["POST"], access="read", validate={ "ids": ListOfParameter(element=DocumentParameter(ConnectionRule), convert=True) }, api=True, ) def api_action_json(self, request, ids): r = [o.json_data for o in ids] s = to_json(r, order=["name", "description"]) return {"data": s}
def init_plugin(self): super().init_plugin() self.add_view( "api_plugin_%s_get_layer" % self.name, self.api_get_layer, url=r"^plugin/%s/layers/(?P<layer>\S+)/$" % self.name, method=["GET"], ) self.add_view( "api_plugin_%s_object_data" % self.name, self.api_object_data, url="^(?P<id>[0-9a-f]{24})/plugin/%s/object_data/$" % self.name, method=["GET"], ) self.add_view( "api_plugin_%s_set_geopoint" % self.name, self.api_set_geopoint, url="^(?P<id>[0-9a-f]{24})/plugin/%s/set_geopoint/$" % self.name, method=["POST"], validate={ "srid": StringParameter(), "x": FloatParameter(), "y": FloatParameter() }, ) self.add_view( "api_plugin_%s_set_layer_visibility" % self.name, self.api_set_layer_visibility, url="^plugin/%s/layer_visibility/$" % self.name, method=["POST"], validate={ "layer": StringParameter(), "status": BooleanParameter() }, ) self.add_view( "api_plugin_%s_create" % self.name, self.api_create, url="^plugin/%s/$" % self.name, method=["POST"], validate={ "model": DocumentParameter(ObjectModel), "name": UnicodeParameter(), "srid": StringParameter(), "x": FloatParameter(), "y": FloatParameter(), }, )
class ObjectModelApplication(ExtDocApplication): """ ObjectModel application """ title = "Object Models" menu = "Setup | Object Models" model = ObjectModel parent_model = DocCategory parent_field = "parent" query_fields = [ "name__icontains", "description__icontains", "data__asset__part_no", "data__asset__order_part_no", "uuid" ] def clean(self, data): if "data" in data: data["data"] = ModelInterface.clean_data(data["data"]) if "plugins" in data and data["plugins"]: data["plugins"] = [ x.strip() for x in data["plugins"].split(",") if x.strip() ] else: data["plugins"] = None return super(ObjectModelApplication, self).clean(data) def cleaned_query(self, q): if "is_container" in q: q["data__container__container"] = True q["name__ne"] = "Root" del q["is_container"] return super(ObjectModelApplication, self).cleaned_query(q) @view(url="^(?P<id>[0-9a-f]{24})/compatible/$", method=["GET"], access="read", api=True) def api_compatible(self, request, id): o = self.get_object_or_404(ObjectModel, id=id) # Connections r = [] for c in o.connections: # Find compatible objects proposals = [] for t, n in o.get_connection_proposals(c.name): m = ObjectModel.objects.filter(id=t).first() mc = m.get_model_connection(n) proposals += [{ "model": m.name, "model_description": m.description, "name": n, "description": mc.description, "gender": mc.gender }] # if (r and r[-1]["direction"] == c.direction and r[-1]["gender"] == c.gender and r[-1]["connections"] == proposals): r[-1]["names"] += [{ "name": c.name, "description": c.description }] else: r += [{ "names": [{ "name": c.name, "description": c.description }], "direction": c.direction, "gender": c.gender, "connections": proposals }] # Crossing # @todo: Count splitter interface rc = [] for c in o.connections: if c.cross: rc += [{"y": c.name, "x": c.cross, "v": "1"}] return {"connections": r, "crossing": rc} @view(url="^actions/json/$", method=["POST"], access="read", validate={ "ids": ListOfParameter(element=DocumentParameter(ObjectModel), convert=True) }, api=True) def api_action_json(self, request, ids): r = [o.json_data for o in ids] s = to_json(r, order=["name", "vendor__code", "description"]) return {"data": s}
def __init__(self, *args, **kwargs): super(ExtDocApplication, self).__init__(*args, **kwargs) self.pk = "id" # @todo: detect properly self.has_uuid = False # Prepare field converters self.clean_fields = self.clean_fields.copy() # name -> Parameter for name, f in six.iteritems(self.model._fields): if isinstance(f, BooleanField): self.clean_fields[name] = BooleanParameter() elif isinstance(f, GeoPointField): self.clean_fields[name] = GeoPointParameter() elif isinstance(f, ForeignKeyField): self.clean_fields[f.name] = ModelParameter(f.document_type, required=f.required) elif isinstance(f, ListField): if isinstance(f.field, EmbeddedDocumentField): self.clean_fields[f.name] = ListOfParameter( element=EmbeddedDocumentParameter(f.field.document_type) ) elif isinstance(f, ReferenceField): dt = f.document_type_obj if dt == "self": dt = self.model self.clean_fields[f.name] = DocumentParameter(dt, required=f.required) if f.primary_key: self.pk = name if name == "uuid": self.has_uuid = True # if not self.query_fields: self.query_fields = [ "%s__%s" % (n, self.query_condition) for n, f in six.iteritems(self.model._fields) if f.unique and isinstance(f, StringField) ] self.unique_fields = [n for n, f in six.iteritems(self.model._fields) if f.unique] # Install JSON API call when necessary self.json_collection = self.model._meta.get("json_collection") if ( self.has_uuid and hasattr(self.model, "to_json") and not hasattr(self, "api_to_json") and not hasattr(self, "api_json") ): self.add_view( "api_json", self._api_to_json, url=r"^(?P<id>[0-9a-f]{24})/json/$", method=["GET"], access="read", api=True, ) self.add_view( "api_share_info", self._api_share_info, url=r"^(?P<id>[0-9a-f]{24})/share_info/$", method=["GET"], access="read", api=True, ) if self.json_collection: self.bulk_fields += [self._bulk_field_is_builtin] # Find field_* and populate custom fields self.custom_fields = {} for fn in [n for n in dir(self) if n.startswith("field_")]: h = getattr(self, fn) if callable(h): self.custom_fields[fn[6:]] = h
class ValidationPolicySettingsApplication(ExtDocApplication): """ ValidationPolicySettings application """ title = _("Validation Policy Settings") model = ValidationPolicySettings MODEL_SCOPES = { "sa.ManagedObject": 2, "sa.ManagedObjectProfile": 2, "inv.Interface": 2, "inv.InterfaceProfile": 2, } @view( "^(?P<model_id>[^/]+)/(?P<object_id>[^/]+)/settings/$", method=["GET"], access="read", api=True, ) def api_get_settings(self, request, model_id, object_id): if model_id not in self.MODEL_SCOPES: return self.response_not_found("Invalid model") o = ValidationPolicySettings.objects.filter( model_id=model_id, object_id=object_id).first() if o: # Policy settings return [{ "policy": str(p.policy.id), "policy__label": p.policy.name, "is_active": p.is_active, } for p in o.policies] else: return {} @view( "^(?P<model_id>[^/]+)/(?P<object_id>[^/]+)/settings/$", method=["POST"], access="read", api=True, validate={ "policies": DictListParameter( attrs={ "policy": DocumentParameter(ValidationPolicy), "is_active": BooleanParameter(), }) }, ) def api_save_settings(self, request, model_id, object_id, policies): def save_settings(o): o.save() return self.response({"status": True}, self.OK) o = ValidationPolicySettings.objects.filter( model_id=model_id, object_id=object_id).first() seen = set() ps = [] for p in policies: if p["policy"].id in seen: continue ps += [ ValidationPolicyItem(policy=p["policy"], is_active=p["is_active"]) ] seen.add(p["policy"].id) if o: o.policies = ps else: o = ValidationPolicySettings(model_id=model_id, object_id=object_id, policies=ps) self.submit_slow_op(request, save_settings, o)
class InterfaceAppplication(ExtApplication): """ inv.interface application """ title = _("Interfaces") menu = _("Interfaces") mrt_config = { "get_mac": { "map_script": "get_mac_address_table", "timeout": config.script.timeout, "access": "get_mac", } } implied_permissions = { "get_mac": [ "inv:inv:read", "inv:interface:view", "sa:managedobject:lookup", "sa:managedobject:read", ] } @view(url=r"^(?P<managed_object>\d+)/$", method=["GET"], access="view", api=True) def api_get_interfaces(self, request, managed_object): """ GET interfaces :param managed_object: :return: """ def sorted_iname(s): return list(sorted(s, key=lambda x: alnum_key(x["name"]))) def get_style(i): profile = i.profile if profile: try: return style_cache[profile.id] except KeyError: pass if profile.style: s = profile.style.css_class_name else: s = "" style_cache[profile.id] = s return s else: return "" def get_link(i): link = i.link if not link: return None if link.is_ptp: # ptp o = link.other_ptp(i) label = "%s:%s" % (o.managed_object.name, o.name) elif link.is_lag: # unresolved LAG o = [ ii for ii in link.other(i) if ii.managed_object.id != i.managed_object.id ] label = "LAG %s: %s" % (o[0].managed_object.name, ", ".join( ii.name for ii in o)) else: # Broadcast label = ", ".join("%s:%s" % (ii.managed_object.name, ii.name) for ii in link.other(i)) return {"id": str(link.id), "label": label} # Get object o = self.get_object_or_404(ManagedObject, id=int(managed_object)) if not o.has_access(request.user): return self.response_forbidden("Permission denied") # Physical interfaces # @todo: proper ordering default_state = ResourceState.get_default() style_cache = {} # profile_id -> css_style l1 = [{ "id": str(i.id), "name": i.name, "description": i.description, "mac": i.mac, "ifindex": i.ifindex, "lag": (i.aggregated_interface.name if i.aggregated_interface else ""), "link": get_link(i), "profile": str(i.profile.id) if i.profile else None, "profile__label": smart_text(i.profile) if i.profile else None, "enabled_protocols": i.enabled_protocols, "project": i.project.id if i.project else None, "project__label": smart_text(i.project) if i.project else None, "state": i.state.id if i.state else default_state.id, "state__label": smart_text(i.state if i.state else default_state), "vc_domain": i.vc_domain.id if i.vc_domain else None, "vc_domain__label": smart_text(i.vc_domain) if i.vc_domain else None, "row_class": get_style(i), } for i in Interface.objects.filter(managed_object=o.id, type="physical")] # LAG lag = [{ "id": str(i.id), "name": i.name, "description": i.description, "members": [ j.name for j in Interface.objects.filter(managed_object=o.id, aggregated_interface=i.id) ], "profile": str(i.profile.id) if i.profile else None, "profile__label": smart_text(i.profile) if i.profile else None, "enabled_protocols": i.enabled_protocols, "project": i.project.id if i.project else None, "project__label": smart_text(i.project) if i.project else None, "state": i.state.id if i.state else default_state.id, "state__label": smart_text(i.state if i.state else default_state), "vc_domain": i.vc_domain.id if i.vc_domain else None, "vc_domain__label": smart_text(i.vc_domain) if i.vc_domain else None, "row_class": get_style(i), } for i in Interface.objects.filter(managed_object=o.id, type="aggregated")] # L2 interfaces l2 = [{ "name": i.name, "description": i.description, "untagged_vlan": i.untagged_vlan, "tagged_vlans": i.tagged_vlans, } for i in SubInterface.objects.filter(managed_object=o.id, enabled_afi="BRIDGE")] # L3 interfaces q = Q(enabled_afi="IPv4") | Q(enabled_afi="IPv6") l3 = [{ "name": i.name, "description": i.description, "ipv4_addresses": i.ipv4_addresses, "ipv6_addresses": i.ipv6_addresses, "enabled_protocols": i.enabled_protocols, "vlan": i.vlan_ids, "vrf": i.forwarding_instance.name if i.forwarding_instance else "", } for i in SubInterface.objects.filter(managed_object=o.id).filter(q)] return { "l1": sorted_iname(l1), "lag": sorted_iname(lag), "l2": sorted_iname(l2), "l3": sorted_iname(l3), } @view( url=r"^link/$", method=["POST"], validate={ "type": StringParameter(choices=["ptp"]), "interfaces": ListOfParameter(element=DocumentParameter(Interface)), }, access="link", api=True, ) def api_link(self, request, type, interfaces): if type == "ptp": if len(interfaces) == 2: interfaces[0].link_ptp(interfaces[1]) return {"status": True} else: raise ValueError("Invalid interfaces length") return {"status": False} @view(url=r"^unlink/(?P<iface_id>[0-9a-f]{24})/$", method=["POST"], access="link", api=True) def api_unlink(self, request, iface_id): i = Interface.objects.filter(id=iface_id).first() if not i: return self.response_not_found() try: i.unlink() return {"status": True, "msg": "Unlinked"} except ValueError as why: return {"status": False, "msg": str(why)} @view(url=r"^unlinked/(?P<object_id>\d+)/$", method=["GET"], access="link", api=True) def api_unlinked(self, request, object_id): def get_label(i): if i.description: return "%s (%s)" % (i.name, i.description) else: return i.name o = self.get_object_or_404(ManagedObject, id=int(object_id)) r = [{ "id": str(i.id), "label": get_label(i) } for i in Interface.objects.filter(managed_object=o.id, type="physical").order_by("name") if not i.link] return list(sorted(r, key=lambda x: alnum_key(x["label"]))) @view( url=r"^l1/(?P<iface_id>[0-9a-f]{24})/change_profile/$", validate={"profile": DocumentParameter(InterfaceProfile)}, method=["POST"], access="profile", api=True, ) def api_change_profile(self, request, iface_id, profile): i = Interface.objects.filter(id=iface_id).first() if not i: return self.response_not_found() if i.profile != profile: i.profile = profile i.profile_locked = True i.save() return True @view( url=r"^l1/(?P<iface_id>[0-9a-f]{24})/change_state/$", validate={"state": ModelParameter(ResourceState)}, method=["POST"], access="profile", api=True, ) def api_change_state(self, request, iface_id, state): i = Interface.objects.filter(id=iface_id).first() if not i: return self.response_not_found() if i.state != state: i.state = state i.save() return True @view( url=r"^l1/(?P<iface_id>[0-9a-f]{24})/change_project/$", validate={"project": ModelParameter(Project, required=False)}, method=["POST"], access="profile", api=True, ) def api_change_project(self, request, iface_id, project): i = Interface.objects.filter(id=iface_id).first() if not i: return self.response_not_found() if i.project != project: i.project = project i.save() return True @view( url=r"^l1/(?P<iface_id>[0-9a-f]{24})/change_vc_domain/$", validate={"vc_domain": ModelParameter(VCDomain, required=False)}, method=["POST"], access="profile", api=True, ) def api_change_vc_domain(self, request, iface_id, vc_domain): i = Interface.objects.filter(id=iface_id).first() if not i: return self.response_not_found() if i.vc_domain != vc_domain: i.vc_domain = vc_domain i.save() return True
class MetricSettingsApplication(ExtDocApplication): """ MetricSettings application """ title = "Metric Settings" model = MetricSettings @view("^(?P<model_id>[^/]+)/(?P<object_id>[^/]+)/settings/$", method=["GET"], access="read", api=True) def api_get_settings(self, request, model_id, object_id): o = MetricSettings.objects.filter(model_id=model_id, object_id=object_id).first() if o: return [{ "metric_set": str(ms.metric_set.id), "metric_set__label": ms.metric_set.name, "is_active": ms.is_active } for ms in o.metric_sets] else: return [] @view("^(?P<model_id>[^/]+)/(?P<object_id>[^/]+)/settings/$", method=["POST"], access="read", api=True, validate={ "metric_sets": DictListParameter( attrs={ "metric_set": DocumentParameter(MetricSet), "is_active": BooleanParameter() }) }) def api_save_settings(self, request, model_id, object_id, metric_sets): def save_settings(o): o.save() return self.response({"status": True}, self.OK) o = MetricSettings.objects.filter(model_id=model_id, object_id=object_id).first() seen = set() mset = [] for ms in metric_sets: if ms["metric_set"].id in seen: continue mset += [ MetricSettingsItem(metric_set=ms["metric_set"], is_active=ms["is_active"]) ] seen.add(ms["metric_set"].id) if o: o.metric_sets = mset else: o = MetricSettings(model_id=model_id, object_id=object_id, metric_sets=mset) self.submit_slow_op(request, save_settings, o) @view("^(?P<model_id>[^/]+)/(?P<object_id>[^/]+)/effective/trace/$", method=["GET"], access="read", api=True) def api_trace_effective(self, request, model_id, object_id): o = MetricSettings(model_id=model_id, object_id=object_id).get_object() if not o: return self.response_not_found() r = [] for es in MetricSettings.get_effective_settings(o, trace=True, recursive=True): for m in es.metrics: r += [{ "metric": m.metric or None, "metric_type": m.metric_type.name, "is_active": es.is_active, "probe": es.probe.name if es.probe else None, "interval": es.interval if es.interval else None, "thresholds": m.thresholds, "handler": es.handler, "config": es.config, "errors": es.errors, "traces": es.traces }] return r
def get_label(i): if i.description: return "%s (%s)" % (i.name, i.description) else: return i.name o = self.get_object_or_404(ManagedObject, id=int(object_id)) r = [{"id": str(i.id), "label": get_label(i)} for i in Interface.objects.filter(managed_object=o.id, type="physical").order_by("name") if not i.link] return sorted(r, key=lambda x: split_alnum(x["label"])) @view(url="^l1/(?P<iface_id>[0-9a-f]{24})/change_profile/$", validate={ "profile": DocumentParameter(InterfaceProfile) }, method=["POST"], access="profile", api=True) def api_change_profile(self, request, iface_id, profile): i = Interface.objects.filter(id=iface_id).first() if not i: return self.response_not_found() if i.profile != profile: i.profile = profile i.profile_locked = True i.save() return True @view(url="^l1/(?P<iface_id>[0-9a-f]{24})/change_state/$", validate={ "state": ModelParameter(ResourceState)