Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Current »

Commit: https://bitbucket.org/nocproject/noc/commits/ba029802c63763bb4fc9c6afde82eb42fa72acb8

Изменены:

  • inv/apps/map

Удалены:

  • inv/apps/networkchart
  • inv/models/networkchart.py
  • inv/models/networkchartstate.py

 

# pg_dump -U noc -t inv_networkchart noc >/root/networkchart.sql

# mongodump --db noc --collection noc.inv.networkchartstate --out /root/noc.inv.networkchartstate

 

Preliminary patches:

oldmap
diff -urN inv/apps/mapp/js/Application.js inv/apps/oldmap/js/Application.js
--- inv/apps/mapp/js/Application.js    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/oldmap/js/Application.js    2015-06-30 11:51:11.520432646 +0300
@@ -0,0 +1,679 @@
+//---------------------------------------------------------------------
+// inv.oldmap application
+//---------------------------------------------------------------------
+// Copyright (C) 2007-2013 The NOC Project
+// See LICENSE for details
+//---------------------------------------------------------------------
+console.debug("Defining NOC.inv.oldmap.Application");
+
+Ext.define("NOC.inv.oldmap.Application", {
+    extend: "NOC.core.Application",
+    requires: [
+        "NOC.inv.networkchart.LookupField",
+        "NOC.inv.oldmap.templates.ManagedObjectTooltip",
+        "NOC.inv.oldmap.templates.LinkTooltip",
+        "NOC.inv.oldmap.templates.InterfaceTooltip"
+    ],
+    // Label position style
+    labelPositionStyle: {
+        nw: "verticalLabelPosition=top;verticalAlign=bottom;labelPosition=left;align=right",
+        n: "verticalLabelPosition=top;verticalAlign=bottom",
+        ne: "verticalLabelPosition=top;verticalAlign=bottom;labelPosition=right;align=left",
+        e: "labelPosition=right;align=left",
+        se: "verticalLabelPosition=bottom;verticalAlign=top;labelPosition=right;align=left",
+        s: "verticalLabelPosition=bottom;verticalAlign=top",
+        sw: "verticalLabelPosition=bottom;verticalAlign=top;labelPosition=left;align=right",
+        w: "labelPosition=left;align=right"
+    },
+    edgeStyle: {
+        straight: "",
+        orthogonal: "edgeStyle=elbowEdgeStyle"
+    },
+    NS_NORMAL: "n",
+    NS_WARNING: "w",
+    NS_ALARM: "a",
+    NS_UNREACH: "u",
+
+    initComponent: function() {
+        var me = this;
+        me.chartCombo = Ext.create("NOC.inv.networkchart.LookupField", {
+            fieldLabel: "Chart",
+            labelWidth: 30,
+            minWidth: 280,
+            name: "chart",
+            allowBlank: true,
+            disabled: true,
+            emptyText: "Select chart...",
+            listeners: {
+                scope: me,
+                select: me.onSelectChart
+            }
+        });
+        me.saveButton = Ext.create("Ext.button.Button", {
+            glyph: NOC.glyph.save,
+            text: "Save",
+            tooltip: "Save changes",
+            disabled: true,
+            scope: me,
+            handler: me.onSave
+        });
+        me.reloadButton = Ext.create("Ext.button.Button", {
+            glyph: NOC.glyph.refresh,
+            text: "Reload",
+            tooltip: "Reload map",
+            disabled: true,
+            scope: me,
+            handler: me.onReload
+        });
+        me.zoomInButton = Ext.create("Ext.button.Button", {
+            tooltip: "Zoom In",
+            glyph: NOC.glyph.search_plus,
+            scope: me,
+            handler: me.onZoomIn,
+            disabled: true
+        });
+        me.zoomOutButton = Ext.create("Ext.button.Button", {
+            tooltip: "Zoom Out",
+            glyph: NOC.glyph.search_minus,
+            scope: me,
+            handler: me.onZoomOut,
+            disabled: true
+        });
+        me.zoomActualButton = Ext.create("Ext.button.Button", {
+            tooltip: "Zoom Actual",
+            glyph: NOC.glyph.search,
+            scope: me,
+            handler: me.onZoomActual,
+            disabled: true
+        });
+        Ext.apply(me, {
+            dockedItems: [{
+                xtype: "toolbar",
+                dock: "top",
+                items: [
+                    me.chartCombo,
+                    "-",
+                    // Editing
+                    me.saveButton,
+                    me.reloadButton,
+                    "-",
+                    // Zoom
+                    me.zoomInButton,
+                    me.zoomOutButton,
+                    me.zoomActualButton
+                ]
+            }],
+            items: [{
+                xtype: "component",
+                autoScroll: true,
+                style: {
+                    background: "url('/static/img/grid.gif')"
+                }
+            }]
+        });
+        me.graph = undefined;
+        //
+        me.callParent();
+    },
+    //
+    afterRender: function() {
+        var me = this;
+        me.callParent();
+        //
+        me.mapPanel = me.items.first();
+        me.mapDom = me.mapPanel.el.dom;
+                // Context menus
+        me.nodeContextMenu = Ext.create("Ext.menu.Menu", {
+            renderTo: me.mapDom,
+            items: [
+                {
+                    text: "Fold",
+                    listeners: {
+                        scope: me,
+                        click: me.onFold
+                    }
+                },
+                {
+                    text: "Unfold",
+                    listeners: {
+                        scope: me,
+                        click: me.onUnfold
+                    }
+                },
+                {
+                    text: "Label Position",
+                    menu: {
+                        items: [
+                            {
+                                text: "Top Left",
+                                iconCls: "icon_arrow_nw",
+                                itemId: "nw",
+                                listeners: {
+                                    scope: me,
+                                    click: me.onLabelPositionChange
+                                }
+                            },
+                            {
+                                text: "Top",
+                                glyph: NOC.glyph.arrow_up,
+                                itemId: "n",
+                                listeners: {
+                                    scope: me,
+                                    click: me.onLabelPositionChange
+                                }
+                            },
+                            {
+                                text: "Top Right",
+                                iconCls: "icon_arrow_ne",
+                                itemId: "ne",
+                                listeners: {
+                                    scope: me,
+                                    click: me.onLabelPositionChange
+                                }
+                            },
+                            {
+                                text: "Right",
+                                glyph: NOC.glyph.arrow_right,
+                                itemId: "e",
+                                listeners: {
+                                    scope: me,
+                                    click: me.onLabelPositionChange
+                                }
+                            },
+                            {
+                                text: "Bottom Right",
+                                iconCls: "icon_arrow_se",
+                                itemId: "se",
+                                listeners: {
+                                    scope: me,
+                                    click: me.onLabelPositionChange
+                                }
+                            },
+                            {
+                                text: "Bottom",
+                                glyph: NOC.glyph.arrow_down,
+                                itemId: "s",
+                                listeners: {
+                                    scope: me,
+                                    click: me.onLabelPositionChange
+                                }
+                            },
+                            {
+                                text: "Bottom Left",
+                                iconCls: "icon_arrow_sw",
+                                itemId: "sw",
+                                listeners: {
+                                    scope: me,
+                                    click: me.onLabelPositionChange
+                                }
+                            },
+                            {
+                                text: "Left",
+                                glyph: NOC.glyph.arrow_left,
+                                itemId: "w",
+                                listeners: {
+                                    scope: me,
+                                    click: me.onLabelPositionChange
+                                }
+                            }
+                        ]
+                    }
+                },
+                {
+                    text: "Select Icon ...",
+                    listeners: {
+                        scope: me,
+                        click: me.onSelectIcon
+                    }
+                }
+            ]
+        });
+        me.edgeContextMenu = Ext.create("Ext.menu.Menu", {
+            renderTo: me.mapDom,
+            items: [
+                {
+                    text: "Line Style",
+                    menu: {
+                        items: [
+                            {
+                                text: "Staight",
+                                itemId: "straight",
+                                listeners: {
+                                    scope: me,
+                                    click: me.onEdgeStyleChange
+                                }
+                            },
+                            {
+                                text: "Orthogonal",
+                                itemId: "orthogonal",
+                                listeners: {
+                                    scope: me,
+                                    click: me.onEdgeStyleChange
+                                }
+                            }
+                        ]
+                    }
+                }
+            ]
+        });
+        // Load mxGraph JS library
+        mxLanguage = "en";
+        mxLoadStylesheets = false;  // window scope
+        mxImageBasePath = "/static/pkg/mxgraph/images/";
+        mxLoadResources = false;
+        Ext.Loader.loadScript({
+            url: "/static/pkg/mxgraph/mxClient.js",
+            scope: me,
+            onLoad: me.onLoadJS,
+            onError: function() {
+                NOC.error("Failed to load script");
+            }
+        });
+    },
+    //
+    onLoadJS: function() {
+        var me = this;
+        me.chartCombo.setDisabled(false);
+    },
+    //
+    onSelectChart: function(combo, records, opts) {
+        var me = this;
+        me.mapId = records.get("id");
+        me.requestChart();
+    },
+    //
+    requestChart: function() {
+        var me = this;
+        Ext.Ajax.request({
+            url: "/inv/oldmap/chart/" + me.mapId + "/",
+            method: "GET",
+            scope: me,
+            success: me.loadChart
+        });
+    },
+    // Initialize mxGraph
+    initGraph: function() {
+        var me = this;
+        me.changeLog = [];
+        me.saveButton.setDisabled(true);
+        me.reloadButton.setDisabled(true);
+        if(me.graph) {
+            // Clear graph
+            me.graph.removeCells(me.graph.getChildVertices(me.graph.getDefaultParent()), true);
+        } else {
+            // Create Graph
+            mxEvent.disableContextMenu(me.mapDom); // Disable default context menu
+            me.graph = new mxGraph(me.mapDom);
+            me.graph.disconnectOnMove = false;
+            // me.graph.foldingEnabled = false;
+            me.graph.cellsResizable = false;
+            new mxRubberband(me.graph);
+            me.graph.setPanning(true);
+            me.graph.setTooltips(true);
+            me.graph.foldingEnabled = false;
+            // Custom edge style
+            mxEdgeStyle.NOCEdgeStyle = function(state, source, target, points, result) {
+                if (source != null && target != null) {
+                    var isSourceLeft = (source.x < target.x) ? 1 : -1;
+                    var pt1 = new mxPoint(source.getCenterX() + isSourceLeft * (source.width/2+5), source.getCenterY());
+                    var pt2 = new mxPoint(target.getCenterX() - isSourceLeft * (target.width/2+5), target.getCenterY());
+                    result.push(pt1);
+                    result.push(pt2);
+                }
+            };
+            // Set styles
+            var ss = me.graph.getStylesheet(),
+                edgeStyle = ss.getDefaultEdgeStyle();
+            edgeStyle[mxConstants.STYLE_EDGE] = mxEdgeStyle.NOCEdgeStyle;
+            delete edgeStyle.endArrow;
+            /*
+            var vertexStyle = ss.getDefaultVertexStyle();
+            vertexStyle[mxConstants.STYLE_FILLCOLOR] = "red";
+            vertexStyle[mxConstants.STYLE_STROKECOLOR] = "blue";
+            */
+            // Load stencils
+            var req = mxUtils.load("/inv/oldmap/stencils/");
+            var sroot = req.getDocumentElement();
+            var shape = sroot.firstChild;
+            while(shape != null) {
+                if(shape.nodeType == mxConstants.NODETYPE_ELEMENT) {
+                    mxStencilRegistry.addStencil(shape.getAttribute("name"),
+                        new mxStencil(shape));
+                }
+                shape = shape.nextSibling;
+            }
+            // Inititalize tooltips
+            me.graph.getTooltipForCell = me.getTooltipForCell;
+            //
+            me.graph.panningHandler.factoryMethod = Ext.bind(me.onContextMenu, me);
+            // Add Event Handlers
+            me.graph.addListener(mxEvent.MOVE_CELLS,
+                Ext.bind(me.onNodeMove, me));
+            //
+            me.zoomInButton.setDisabled(false);
+            me.zoomOutButton.setDisabled(false);
+            me.zoomActualButton.setDisabled(false);
+        }
+    },
+    //
+    loadChart: function(response) {
+        var me = this,
+            data = Ext.decode(response.responseText);
+        me.initGraph();
+        var model = me.graph.getModel();
+        model.beginUpdate();
+        try {
+            // Update data
+            var parent = me.graph.getDefaultParent(),
+                nodes = {},  // id -> node
+                ports = {};  // id -> port
+            for(var i in data) {
+                var n = data[i];
+                switch(n.type) {
+                    // Insert node
+                    case "node":
+                        var style = [];
+                        // Label position
+                        if(n.label) {
+                            // Convert label position to style
+                            var lp = n.label_position ? n.label_position : "s";
+                            style.push(me.labelPositionStyle[lp]);
+                        }
+                        // Shape
+                        if(n.shape) {
+                            style.push("shape=" + n.shape + "#" + n.status);
+                        }
+                        // Draw node
+                        var v = me.graph.insertVertex(parent, null,
+                            n.label ? n.label : null,
+                            n.x, n.y, n.w, n.h,
+                            style ? style.join(";") : null
+                        );
+                        v.objectId = n.id;
+                        v.nocStatus = n.status;
+                        v.nocShape = n.shape;
+                        if(n.collapsed) {
+                            model.setCollapsed(v, true);
+                        }
+                        // Attach tooltip
+                        v.nocTooltipTemplate = me.templates.ManagedObjectTooltip;
+                        v.nocTooltipData = {
+                            name: n.label,
+                            id: n.id,
+                            address: n.address,
+                            platform: n.platform,
+                            version: n.version
+                        };
+                        // Save id
+                        if(n.id) {
+                            nodes[n.id] = v;
+                        };
+                        // Create ports
+                        for(var pi in n.ports) {
+                            var pdata = n.ports[pi];
+                            var pv = me.graph.insertVertex(v, null,
+                                pdata.label, 1, 1, 5 * pdata.label.length, 12);
+                            pv.geometry.offset = new mxPoint(3, 14 * pi - n.h);
+                            pv.geometry.relative = true;
+                            ports[pdata.id] = pv;
+                            // Tooltips
+                            pv.nocTooltipTemplate = me.templates.InterfaceTooltip;
+                            pv.nocTooltipData = {
+                                interface: pdata.label
+                            }
+                        }
+                        // Set initial status
+                        me.setNodeStatus(v, n.status);
+                        // End of node processing
+                        break;
+                    // Insert link
+                    case "link":
+                        var style = [];
+                        // Adjust edge style
+                        if(n.edge_style && n.edge_style != "straight") {
+                            style.push(me.edgeStyle[n.edge_style]);
+                        }
+                        // Create edge
+                        var v = me.graph.insertEdge(parent, null, "",
+                            ports[n.ports[0]], ports[n.ports[1]],
+                            style ? style.join(";") : null
+                        );
+                        v.objectId = n.id;
+                        // Tooltips
+                        v.nocTooltipTemplate = me.templates.LinkTooltip;
+                        v.nocTooltipData = {
+                            discovery_method: n.discovery_method
+                        };
+                        break;
+                }
+            }
+        }
+        finally {
+            // Update display
+            model.endUpdate();
+        }
+        me.reloadButton.setDisabled(false);
+    },
+    //
+    getTooltipForCell: function(cell) {
+        if(!cell.nocTooltipTemplate) {
+            return "";
+        }
+        return cell.nocTooltipTemplate(cell.nocTooltipData);
+    },
+    // Save button pressed
+    onSave: function() {
+        var me = this;
+        console.log(me.changeLog);
+        Ext.Ajax.request({
+            url: "/inv/oldmap/chart/" + me.mapId + "/",
+            method: "POST",
+            jsonData: me.changeLog,
+            scope: me,
+            success: function() {
+                me.changeLog = [];
+                me.saveButton.setDisabled(true);
+            }
+        });
+    },
+    //
+    onReload: function() {
+        var me = this;
+        me.requestChart();
+    },
+    //
+    registerChange: function(opts) {
+        var me = this;
+        me.changeLog.push(opts);
+        me.saveButton.setDisabled(false);
+    },
+    // Register cell movement
+    onNodeMove: function(graph, event) {
+        var me = this;
+        for(var i in event.properties.cells) {
+            var c = event.properties.cells[i];
+            if(c.vertex) {
+                // Node moved
+                console.log(c);
+                me.registerChange({
+                    cmd: "move",
+                    type: "mo",
+                    id: c.objectId,
+                    x: c.geometry.x,
+                    y: c.geometry.y,
+                    w: c.geometry.width,
+                    h: c.geometry.height
+                });
+            }
+        }
+    },
+    // Zoom In
+    onZoomIn: function() {
+        var me = this;
+        me.graph.zoomIn();
+    },
+    // Zoom Out
+    onZoomOut: function() {
+        var me = this;
+        me.graph.zoomOut();
+    },
+    // Zoom Actual
+    onZoomActual: function() {
+        var me = this;
+        me.graph.zoomActual();
+    },
+    //
+    onContextMenu: function(menu, cell, evt) {
+        var me = this;
+        if(cell != null) {
+            var m = null;
+            if(cell.isVertex()) {
+                m = me.nodeContextMenu;
+            } else {
+                m = me.edgeContextMenu;
+            }
+            if(m) {
+                m.setLocalXY(evt.layerX, evt.layerY);
+                m.show();
+            }
+        }
+    },
+    //
+    onLabelPositionChange: function(item, event, opt) {
+        var me = this,
+            selection = me.graph.getSelectionCells(),
+            model = me.graph.getModel(),
+            ls = me.labelPositionStyle[item.itemId].split(";");
+        model.beginUpdate();
+        for(var i in selection) {
+            var c = selection[i];
+            if(c.isVertex()) {
+                me.registerChange({
+                    cmd: "label_position",
+                    type: "mo",
+                    id: c.objectId,
+                    label_position: item.itemId
+                });
+                // Reset styles
+                me.graph.setCellStyles("verticalLabelPosition", null, [c]);
+                me.graph.setCellStyles("verticalAlign", null, [c]);
+                me.graph.setCellStyles("labelPosition", null, [c]);
+                me.graph.setCellStyles("align", null, [c]);
+                // Dynamically apply styles
+                for(var j in ls) {
+                    var ss = ls[j].split("=");
+                    me.graph.setCellStyles(ss[0], ss[1], [c]);
+                }
+            }
+        }
+        model.endUpdate();
+    },
+    //
+    setSelectionCollapsed: function(collapsed) {
+        var me = this,
+            selection = me.graph.getSelectionCells(),
+            model = me.graph.getModel();
+        model.beginUpdate()
+        for(var i in selection) {
+            var c = selection[i];
+            if(c.isVertex() && c.isCollapsed() != collapsed) {
+                model.setCollapsed(c, collapsed);
+                me.registerChange({
+                    cmd: "collapsed",
+                    type: "mo",
+                    id: c.objectId,
+                    collapsed: collapsed
+                });
+            }
+        }
+        model.endUpdate()
+    },
+    //
+    onFold: function(item, event, opt) {
+        var me = this;
+        me.setSelectionCollapsed(true);
+    },
+    //
+    onUnfold: function(item, event, opt) {
+        var me = this;
+        me.setSelectionCollapsed(false);
+    },
+    //
+    onEdgeStyleChange: function(item, event, opt) {
+        var me = this,
+            selection = me.graph.getSelectionCells(),
+            model = me.graph.getModel();
+        model.beginUpdate();
+        for(var i in selection) {
+            var c = selection[i];
+            if(c.isEdge()) {
+                me.registerChange({
+                    cmd: "edge_style",
+                    type: "link",
+                    id: c.objectId,
+                    edge_style: item.itemId
+                });
+                var es = {
+                    straight: null,
+                    orthogonal: "elbowEdgeStyle"
+                }[item.itemId];
+                me.graph.setCellStyles(mxConstants.STYLE_EDGE, es, [c]);
+            }
+        }
+        model.endUpdate();
+    },
+    //
+    onSelectIcon: function() {
+        var me = this;
+        Ext.create("NOC.inv.oldmap.SelectIconForm", {app: me});
+    },
+    //
+    setIcon: function(shape) {
+        var me = this,
+            selection = me.graph.getSelectionCells(),
+            model = me.graph.getModel();
+        model.beginUpdate();
+        for(var i in selection) {
+            var c = selection[i];
+            if(c.isVertex()) {
+                me.registerChange({
+                    cmd: "shape",
+                    type: "mo",
+                    id: c.objectId,
+                    shape: shape
+                });
+                c.nocShape = shape;
+                me.graph.setCellStyles(
+                    mxConstants.STYLE_SHAPE, shape + "#" + c.nocStatus, [c]);
+            }
+        }
+        model.endUpdate();
+    },
+    // Manipulate cell overlays
+    setCellOverlay: function(cell, img, tooltip) {
+        var me = this,
+            overlay = new mxCellOverlay(img, tooltip);
+        overlay.addListener(mxEvent.CLICK, function(sender, evt) {});
+        me.removeCellOverlays(cell);
+        me.graph.addCellOverlay(cell, overlay);
+    },
+    removeCellOverlays: function(cell) {
+        var me = this;
+        me.graph.removeCellOverlays(cell);
+    },
+    //
+    setNodeStatus: function(cell, status) {
+        var me = this;
+        if(cell.nocStatus == status) {
+            return;
+        }
+        if(status == me.NS_NORMAL) {
+            me.removeCellOverlays(cell);
+        } else {
+            me.setCellOverlay(cell, me.graph.warningImage, status);
+        }
+        me.graph.setCellStyles(
+            mxConstants.STYLE_SHAPE, cell.nocShape + "#" + cell.nocStatus, [cell]);
+        cell.nocStatus = status;
+    }
+});
diff -urN inv/apps/mapp/js/SelectIconForm.js inv/apps/oldmap/js/SelectIconForm.js
--- inv/apps/mapp/js/SelectIconForm.js    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/oldmap/js/SelectIconForm.js    2015-06-30 11:53:48.002867351 +0300
@@ -0,0 +1,62 @@
+//---------------------------------------------------------------------
+// Icon Selection window
+//---------------------------------------------------------------------
+// Copyright (C) 2007-2012 The NOC Project
+// See LICENSE for details
+//---------------------------------------------------------------------
+// @todo: Auto-fill VC-domain if selected in filter
+//---------------------------------------------------------------------
+console.debug("Defining NOC.oldinv.map.SelectIconForm");
+
+Ext.define("NOC.inv.oldmap.SelectIconForm", {
+    extend: "Ext.Window",
+    requires: [
+        "NOC.main.ref.stencil.LookupField"
+    ],
+    title: "Select Shape",
+    autoShow: true,
+    closable: false,
+    modal: true,
+    app: null,
+    closable: true,
+
+    initComponent: function() {
+        var me = this;
+        Ext.apply(me, {
+            items: [
+                {
+                    xtype: "form",
+                    items: [
+                        {
+                            xtype: "main.ref.stencil.LookupField",
+                            name: "shape",
+                            fieldLabel: "Shape",
+                            labelWidth: 40,
+                            minWidth: 300,
+                            allowBlank: false
+                        }
+                    ]
+                }
+            ],
+            buttons: [
+                {
+                    text: "Set",
+                    itemId: "set",
+                    glyph: NOC.glyph.check,
+                    scope: me,
+                    /*formBind: true,
+                    disabled: true,*/
+                    handler: me.onSet
+                }
+            ]
+        });
+        me.callParent();
+    },
+    // Called when "Set" button pressed
+    onSet: function() {
+        var me = this;
+        var r = me.down("form").getForm().getValues();
+        me.close();
+        me.app.setIcon(r.shape);
+    }
+});
diff -urN inv/apps/mapp/templates/InterfaceTooltip.html inv/apps/oldmap/templates/InterfaceTooltip.html
--- inv/apps/mapp/templates/InterfaceTooltip.html    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/oldmap/templates/InterfaceTooltip.html    2015-06-30 10:57:42.322468167 +0300
@@ -0,0 +1 @@
+Interface: {{ interface }}
\ No newline at end of file
diff -urN inv/apps/mapp/templates/LinkTooltip.html inv/apps/oldmap/templates/LinkTooltip.html
--- inv/apps/mapp/templates/LinkTooltip.html    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/oldmap/templates/LinkTooltip.html    2015-06-30 10:57:42.322468167 +0300
@@ -0,0 +1 @@
+<b>Known via:</b> {{ discovery_method }}
diff -urN inv/apps/mapp/templates/ManagedObjectTooltip.html inv/apps/oldmap/templates/ManagedObjectTooltip.html
--- inv/apps/mapp/templates/ManagedObjectTooltip.html    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/oldmap/templates/ManagedObjectTooltip.html    2015-06-30 10:57:42.322468167 +0300
@@ -0,0 +1,5 @@
+<u><b>{{ name }}</b></u>
+<b>Id:</b> {{ id }}
+<b>Address:</b> {{ address }}
+<b>Platform:</b> {{ platform }}
+<b>Software:</b> {{ version }}
Binary files inv/apps/mapp/tests/__init__.pyc and inv/apps/oldmap/tests/__init__.pyc differ
diff -urN inv/apps/mapp/tests/test.py inv/apps/oldmap/tests/test.py
--- inv/apps/mapp/tests/test.py    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/oldmap/tests/test.py    2015-06-30 10:57:42.322468167 +0300
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+##----------------------------------------------------------------------
+## inv.map unittests
+##----------------------------------------------------------------------
+## Copyright (C) 2007-2013 The NOC Project
+## See LICENSE for details
+##----------------------------------------------------------------------
+
+## NOC modules
+from noc.lib.test import AjaxTestCase
+
+
+class mapTestCase(AjaxTestCase):
+    pass
Binary files inv/apps/mapp/tests/test.pyc and inv/apps/oldmap/tests/test.pyc differ
diff -urN inv/apps/mapp/views.py inv/apps/oldmap/views.py
--- inv/apps/mapp/views.py    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/oldmap/views.py    2015-06-30 12:03:10.838049968 +0300
@@ -0,0 +1,209 @@
+# -*- coding: utf-8 -*-
+##----------------------------------------------------------------------
+## inv.oldmap application
+##----------------------------------------------------------------------
+## Copyright (C) 2007-2013 The NOC Project
+## See LICENSE for details
+##----------------------------------------------------------------------
+
+## Python modules
+from collections import defaultdict
+## NOC modules
+from noc.lib.app import ExtApplication, view
+from noc.inv.models.networkchart import NetworkChart
+from noc.inv.models.interface import Interface
+from noc.sa.models import ManagedObject
+from noc.inv.models.link import Link
+from noc.lib.serialize import json_decode
+from noc.lib.stencil import stencil_registry
+
+
+class OldMapApplication(ExtApplication):
+    """
+    inv.oldmap application
+    """
+    title = "Network Map (Old)"
+    menu = "Network Map (Old)"
+    icon = "icon_map"
+
+    NS_NORMAL = "n"
+    NS_WARNING = "w"
+    NS_ALARM = "a"
+    NS_UNREACH = "u"
+
+    def get_object_shape(self, object):
+        if object.shape:
+            # Use object's shape, if set
+            sn = object.shape
+        elif object.object_profile.shape:
+            # Use profile's shape
+            sn = object.object_profile.shape
+        else:
+            # Fallback to router shape
+            sn = "Cisco/router"
+        return stencil_registry.stencils.get(sn,
+            stencil_registry.stencils["Cisco/router"])
+
+    def get_object_status(self, object):
+        s = object.get_status()
+        return {
+            None: self.NS_UNREACH,
+            True: self.NS_NORMAL,
+            False: self.NS_ALARM
+        }[s]
+
+    @view(url="^chart/(?P<chart_id>\d+)/$", method=["GET"],
+        access="launch", api=True)
+    def view_chart(self, request, chart_id):
+        chart = self.get_object_or_404(NetworkChart, id=int(chart_id))
+        ds = 20
+        dx = 10
+        dy = 10
+        r = []
+        # Get managed objects
+        mos = list(chart.selector.managed_objects)
+        mo_ids = [o.id for o in mos]
+        # Get links
+        if_ids = set(i.id for i in
+                  Interface.objects.filter(managed_object__in=mo_ids,
+                      type__in=["physical", "management"]))
+        links = []
+        mo_links = defaultdict(list)  # mo -> [links]
+        linked_ports = defaultdict(list)  # link -> [port1, port2]
+        for link in Link.objects.filter(interfaces__in=if_ids):
+            interfaces = link.interfaces
+            if not [i for i in interfaces if i.id not in if_ids]:
+                # Both ends on chart
+                links += [link]
+                for i in interfaces:
+                    if i.managed_object not in links:
+                        mo_links[i.managed_object] += [link]
+        # Attach nodes
+        for mo in mos:
+            # Fill managed objects
+            # Restore state
+            state = chart.get_state("mo", mo.id)
+            y = state.get("y")
+            shape = self.get_object_shape(mo)
+            h = shape.height
+            if y is None:
+                y = dy
+                dy += h + ds
+            n = {
+                "type": "node",
+                "id": mo.id,
+                "x": state.get("x", dx),
+                "y": y,
+                "w": shape.width,
+                "h": h,
+                "label": mo.name,
+                "label_position": state.get("label_position", "s"),
+                "collapsed": state.get("collapsed", False),
+                "shape": shape.id,
+                "ports": [],
+                "address": mo.address,
+                "platform": "%s %s" % (mo.get_attr("vendor", ""),
+                                       mo.get_attr("platform", "")),
+                "version": mo.get_attr("version", ""),
+                "status": self.get_object_status(mo)
+            }
+            # Used ports
+            for link in mo_links[mo]:
+                interfaces = [i for i in link.interfaces if i.managed_object == mo]
+                p_id = "%d:%s" % (mo.id, link.id)
+                if p_id not in linked_ports[link]:
+                    n["ports"] += [{
+                        "id": p_id,
+                        "label": ", ".join(i.name for i in interfaces)
+                    }]
+                    linked_ports[link] += [p_id]
+            #
+            r += [n]
+        # Attach links
+        for link in linked_ports:
+            lp = linked_ports[link]
+            if len(lp) == 2:
+                state = chart.get_state("link", str(link.id))
+                dm = link.discovery_method
+                if not dm:
+                    dm = "manual"
+                r += [{
+                    "type": "link",
+                    "id": str(link.id),
+                    "ports": lp,
+                    "edge_style": state.get("edge_style"),
+                    "discovery_method": dm
+                }]
+        return r
+
+    @view(url="^chart/(?P<chart_id>\d+)/$", method=["POST"],
+        access="launch", api=True)
+    def save_chart(self, request, chart_id):
+        chart = self.get_object_or_404(NetworkChart, id=int(chart_id))
+        for cmd in json_decode(request.raw_post_data):
+            if cmd["type"] == "mo":
+                if cmd["cmd"] == "move":
+                    chart.update_state("mo", cmd["id"], {
+                        "x": max(cmd["x"], 0),
+                        "y": max(cmd["y"], 0),
+                        "w": cmd["w"],
+                        "h": cmd["h"]
+                    })
+                elif cmd["cmd"] == "label_position":
+                    chart.update_state("mo", cmd["id"], {
+                        "label_position": cmd["label_position"]
+                    })
+                elif cmd["cmd"] == "collapsed":
+                    chart.update_state("mo", cmd["id"], {
+                        "collapsed": cmd["collapsed"]
+                    })
+                elif cmd["cmd"] == "shape":
+                    try:
+                        o = ManagedObject.objects.get(id=int(cmd["id"]))
+                    except ManagedObject.DoesNotExist:
+                        continue
+                    if o.shape != cmd["shape"]:
+                        o.shape = cmd["shape"]
+                        o.save()
+            elif cmd["type"] == "link":
+                if cmd["cmd"] == "edge_style":
+                    chart.update_state("link", cmd["id"], {
+                        "edge_style": cmd["edge_style"]
+                    })
+        return True
+
+    @view(url="^stencils/$", method=["GET"],
+        access="launch", api=True)
+    def api_stencils(self, request):
+        # @todo: Selective load
+        r = ["<stencils>"]
+        for status in [self.NS_NORMAL, self.NS_WARNING,
+                  self.NS_ALARM, self.NS_UNREACH]:
+            r += [s.get_stencil(status)
+                  for s in stencil_registry.stencils.values()]
+        r += ["</stencils>"]
+        return self.render_response("\n".join(r), content_type="text/xml")
+
+    @view(url="^stencils/(?P<status>[nwau])/(?P<shape>.+)/$",
+        method=["GET"], access=True, api=True)
+    def api_stencil(self, request, status, shape):
+        svg = stencil_registry.get_svg(status, shape)
+        if not svg:
+            return self.response_not_found()
+        else:
+            return self.render_response(svg , content_type="image/svg+xml")
+
+    @view(url="^chart/(?P<chart_id>\d+)/status/$", method=["GET"],
+        access="launch", api=True)
+    def api_status(self, request, chart_id):
+        def f(s):
+            return {
+                None: self.NS_UNREACH,
+                True: self.NS_NORMAL,
+                False: self.NS_ALARM
+            }[s]
+        chart = self.get_object_or_404(NetworkChart, id=int(chart_id))
+        return [{
+            "id": o.id,
+            "status": self.get_object_status(o)
+        } for o in chart.selector.managed_objects]

network chart
diff -urN inv/apps/chartt/js/Application.js inv/apps/networkchart/js/Application.js
--- inv/apps/chartt/js/Application.js    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/networkchart/js/Application.js    2015-06-30 11:37:03.885668651 +0300
@@ -0,0 +1,67 @@
+//---------------------------------------------------------------------
+// inv.networkchart application
+//---------------------------------------------------------------------
+// Copyright (C) 2007-2013 The NOC Project
+// See LICENSE for details
+//---------------------------------------------------------------------
+console.debug("Defining NOC.inv.networkchart.Application");
+
+Ext.define("NOC.inv.networkchart.Application", {
+    extend: "NOC.core.ModelApplication",
+    uses: [
+        "NOC.inv.networkchart.Model",
+        "NOC.sa.managedobjectselector.LookupField"
+    ],
+    model: "NOC.inv.networkchart.Model",
+    search: true,
+    columns: [
+        {
+            text: "Name",
+            dataIndex: "name",
+            width: 200
+        },
+        {
+            text: "Active",
+            dataIndex: "is_active",
+            renderer: NOC.render.Bool,
+            width: 50
+        },
+        {
+            text: "Selector",
+            dataIndex: "selector",
+            renderer: NOC.render.Lookup("selector"),
+            width: 100
+        },
+        {
+            text: "Description",
+            dataIndex: "description",
+            flex: 1
+        }
+    ],
+    fields: [
+        {
+            name: "name",
+            xtype: "textfield",
+            fieldLabel: "Name",
+            allowBlank: false
+        },
+        {
+            name: "description",
+            xtype: "textarea",
+            fieldLabel: "Description",
+            allowBlank: true
+        },
+        {
+            name: "is_active",
+            xtype: "checkboxfield",
+            boxLabel: "Is Active",
+            allowBlank: false
+        },
+        {
+            name: "selector",
+            xtype: "sa.managedobjectselector.LookupField",
+            fieldLabel: "Selector",
+            allowBlank: false
+        }
+    ]
+});
diff -urN inv/apps/chartt/js/LookupField.js inv/apps/networkchart/js/LookupField.js
--- inv/apps/chartt/js/LookupField.js    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/networkchart/js/LookupField.js    2015-06-30 11:37:03.885668651 +0300
@@ -0,0 +1,14 @@
+//---------------------------------------------------------------------
+// NOC.inv.networkchart.Lookup
+//---------------------------------------------------------------------
+// Copyright (C) 2007-2013 The NOC Project
+// See LICENSE for details
+//---------------------------------------------------------------------
+console.debug("Defining NOC.inv.networkchart.LookupField");
+
+Ext.define("NOC.inv.networkchart.LookupField", {
+    extend: "NOC.core.LookupField",
+    alias: "widget.inv.networkchart.LookupField",
+    requires: ["NOC.inv.networkchart.Lookup"],
+    uiStyle: "medium"
+});
diff -urN inv/apps/chartt/js/Lookup.js inv/apps/networkchart/js/Lookup.js
--- inv/apps/chartt/js/Lookup.js    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/networkchart/js/Lookup.js    2015-06-30 11:37:03.885668651 +0300
@@ -0,0 +1,12 @@
+//---------------------------------------------------------------------
+// NOC.inv.networkchart.Lookup
+//---------------------------------------------------------------------
+// Copyright (C) 2007-2013 The NOC Project
+// See LICENSE for details
+//---------------------------------------------------------------------
+console.debug("Defining NOC.inv.networkchart.Lookup");
+
+Ext.define("NOC.inv.networkchart.Lookup", {
+    extend: "NOC.core.Lookup",
+    url: "/inv/networkchart/lookup/"
+});
diff -urN inv/apps/chartt/js/Model.js inv/apps/networkchart/js/Model.js
--- inv/apps/chartt/js/Model.js    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/networkchart/js/Model.js    2015-06-30 11:37:03.885668651 +0300
@@ -0,0 +1,41 @@
+//---------------------------------------------------------------------
+// inv.networkchart Model
+//---------------------------------------------------------------------
+// Copyright (C) 2007-2013 The NOC Project
+// See LICENSE for details
+//---------------------------------------------------------------------
+console.debug("Defining NOC.inv.networkchart.Model");
+
+Ext.define("NOC.inv.networkchart.Model", {
+    extend: "Ext.data.Model",
+    rest_url: "/inv/networkchart/",
+
+    fields: [
+        {
+            name: "id",
+            type: "string"
+        },
+        {
+            name: "name",
+            type: "string"
+        },
+        {
+            name: "description",
+            type: "string"
+        },
+        {
+            name: "is_active",
+            type: "boolean",
+            defaultValue: true
+        },
+        {
+            name: "selector",
+            type: "int"
+        },
+        {
+            name: "selector__label",
+            type: "string",
+            persist: false
+        }
+    ]
+});
diff -urN inv/apps/chartt/tests/test.py inv/apps/networkchart/tests/test.py
--- inv/apps/chartt/tests/test.py    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/networkchart/tests/test.py    2015-06-30 11:37:03.885668651 +0300
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+##----------------------------------------------------------------------
+## inv.networkchart unittes
+##----------------------------------------------------------------------
+## Copyright (C) 2007-2013 The NOC Project
+## See LICENSE for details
+##----------------------------------------------------------------------
+
+## NOC modules
+from noc.lib.test import RestModelTestCase, unittest
+
+
+@unittest.skip("Not ready")
+class NetworkChartTestCase(RestModelTestCase):
+    app = "inv.networkchart"
+
+    scenario = [
+        {
+            "GET": {
+                # key: value
+            },
+            "POST": {
+                # key: value
+            },
+            "PUT": {
+                # key: value
+            }
+        }
+    ]
diff -urN inv/apps/chartt/views.py inv/apps/networkchart/views.py
--- inv/apps/chartt/views.py    1970-01-01 03:00:00.000000000 +0300
+++ inv/apps/networkchart/views.py    2015-06-30 11:37:03.885668651 +0300
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+##----------------------------------------------------------------------
+## inv.networkchart application
+##----------------------------------------------------------------------
+## Copyright (C) 2007-2013 The NOC Project
+## See LICENSE for details
+##----------------------------------------------------------------------
+
+## NOC modules
+from noc.lib.app import ExtModelApplication, view
+from noc.inv.models.networkchart import NetworkChart
+
+
+class NetworkChartApplication(ExtModelApplication):
+    """
+    NetworkChart application
+    """
+    title = "Network Charts"
+    menu = "Setup | Network Charts"
+    model = NetworkChart

networkchart.py
--- inv/models/networkchart.py.old    1970-01-01 03:00:00.000000000 +0300
+++ inv/models/networkchart.py    2015-06-30 11:37:29.654723050 +0300
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+##----------------------------------------------------------------------
+## NetworkChart
+##----------------------------------------------------------------------
+## Copyright (C) 2007-2013 The NOC Project
+## See LICENSE for details
+##----------------------------------------------------------------------
+
+## Django modules
+from django.utils.translation import ugettext_lazy as _
+from django.db import models
+## NOC modules
+from noc.sa.models.managedobjectselector import ManagedObjectSelector
+from networkchartstate import NetworkChartState
+
+
+class NetworkChart(models.Model):
+    class Meta:
+        verbose_name = _("Network Chart")
+        verbose_name_plural = _("Network Charts")
+        db_table = "inv_networkchart"
+        app_label = "inv"
+        ordering = ["name"]
+
+    name = models.CharField(_("Name"), max_length=64, unique=True)
+    description = models.TextField(_("Description"), blank=True, null=True)
+    is_active = models.BooleanField(_("Is Active"), default=True)
+    selector = models.ForeignKey(ManagedObjectSelector,
+        verbose_name=_("Selector"))
+
+    def __unicode__(self):
+        return self.name
+
+    def get_state(self, type, object):
+        """
+        Get current object state
+        :param type:
+        :param object:
+        :return:
+        """
+        s = NetworkChartState.objects.filter(
+            chart=self.id, type=type, object=str(object)).first()
+        if s:
+            return s.state
+        else:
+            return {}
+
+    def update_state(self, type, object, state):
+        """
+        Update current object state
+        :param type:
+        :param object:
+        :param state:
+        :return:
+        """
+        object = str(object)
+        s = NetworkChartState.objects.filter(
+            chart=self.id, type=type, object=object).first()
+        if s:
+            cs = s.state.copy()
+            cs.update(state)
+            s.state = cs
+            s.save()
+        else:
+            # Create state
+            NetworkChartState(
+                chart=self.id, type=type, object=object, state=state
+            ).save()

networkchartstate.py
--- inv/models/networkchartstate.py.old    1970-01-01 03:00:00.000000000 +0300
+++ inv/models/networkchartstate.py    2015-06-30 11:37:45.179358355 +0300
@@ -0,0 +1,34 @@
+## -*- coding: utf-8 -*-
+##----------------------------------------------------------------------
+## Network Chart State
+##----------------------------------------------------------------------
+## Copyright (C) 2007-2013 The NOC Project
+## See LICENSE for details
+##----------------------------------------------------------------------
+
+## NOC modules
+from noc.lib.nosql import (Document, StringField, DictField,
+                           IntField)
+
+
+class NetworkChartState(Document):
+    """
+    Network Chart State
+    """
+    meta = {
+        "collection": "noc.inv.networkchartstate",
+        "allow_inheritance": False,
+        "indexes": [("chart", "type", "object")]
+    }
+
+    chart = IntField()   # Network chart reference
+    type = StringField(
+        choices=[
+            ("mo", "Managed Object"),
+            ("link", "Link")
+        ])
+    object = StringField()  # Object reference
+    state = DictField()  # Arbitrary state data
+
+    def __unicode__(self):
+        return "%s %s %s" % (self.chart, self.type, self.object)

 

 

  • No labels