Changeset f9a4dab0b40a in nodewatcher


Ignore:
Timestamp:
01/03/2018 10:01:43 AM (19 months ago)
Author:
raslavmilutinovic
Branches:
feature/cidr
Children:
c56c8951172601131e07435c6083091d2be52359
Parents:
80bd0394c57d
git-author:
Raslav Milutinovic <raslav.milutinovic@…> (01/03/2018 10:01:43 AM)
git-committer:
Raslav Milutinovic <raslav.milutinovic@…> (01/03/2018 10:01:43 AM)
Message:

Adding recursive utilization calculation.

Location:
nodewatcher/modules/frontend/ip_space/static/ip_space/js
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • nodewatcher/modules/frontend/ip_space/static/ip_space/js/draw_pools.js

    r80bd0394c57d rf9a4dab0b40a  
    1 window.DrawCidr = class DrawCidr { 
    2     constructor(svg, size, subnet, url) { 
    3         this.svg = svg; 
    4         this.loadedPrefixes = 0; 
     1utilization 
     2functutilization, y) { 
     3    this.x = x; 
     4    this.y = y; 
     5} 
    56 
    6         this.n_ips = Math.pow(2, 32 - parseInt(subnet.split("/")[1])); 
    7         this.size = Math.sqrt(this.n_ips); 
    8         this.displaySize = this.closestPower(size); 
     7Point.prototype = { 
     8  rotate: function (n, x, y) { 
     9      if (y === 0) { 
     10          if (x === 1) { 
     11              this.x = n-1 - this.x; 
     12              this.y = n-1 - this.y; 
     13          } 
    914 
    10         $('#ipspace').css('transform', 'scale(' + this.displaySize / this.size + ')'); 
    11         $('#wraper').width($('#ipspace').width() + 'px'); 
    12         $('#wraper').height($('#ipspace').height() + 'px'); 
     15          this.x = [this.x, this.y = this.x][0]; 
     16      } 
     17  } 
     18}; 
    1319 
    14         this.svg.style('width', this.size + 'px').style('height', this.size + 'px'); 
     20/** 
     21 * Maps a number to a x,y and returns the point 
     22 * @param d The number to be mapped 
     23 * @param n The maximum number of d (by default 2**32) 
     24 * @returns {Point} A point to which d was mapped 
     25 */ 
     26function d2xy(d, n=2**32) { 
     27    var p = new Point(0, 0); 
     28    var rx = 0; 
     29    var ry = 0; 
     30    var t=d; 
    1531 
    16         this.subnet = String(subnet); 
    17         this.ips_side = Math.sqrt(this.n_ips); 
    18         this.ips_pixel = this.ips_side / (this.size * 1.0); 
    19         this.offset = 0; 
    20         this.draw(subnet, "Smallest possible network to fit all the ip pools"); 
    21         this.data = new Array(33); 
    22         this.base_url = url; 
    23         self = this; 
    24         $('#topnodes').on('click', '#cidr', function(event) { 
    25             var scale = self.size / self.subnetSize($(event.target).parent().attr('cidr')); 
    26             var start = self.subnetXY($(event.target).parent().attr('cidr')); 
    27             history.replaceState({}, document.title, self.UpdateQueryString('scale', scale, window.url)); 
    28             history.replaceState({}, document.title, self.UpdateQueryString('start', start, window.url)); 
    29             self.svg.selectAll('rect').attr('transform', 'translate(' + start[0] * -1 * scale + ',' + start[1] * -1 * scale + ') scale(' + scale + ')'); 
    30         }); 
     32    for (var s=1; s<n; s*=2) { 
     33        rx = 1 & (t/2); 
     34        ry = 1 & (t ^ rx); 
     35        p.rotate(s, rx, ry); 
     36        p.x += s * rx; 
     37        p.y += s * ry; 
     38        t /= 4; 
    3139    } 
     40    return p; 
     41} 
    3242 
    33     closestPower(number) { 
    34         return 2 ** Math.floor(Math.log2(number)); 
    35     } 
    36  
    37     ip2num(ip) { 
    38         var d = String(ip).split('.'); 
    39         return ((((((+d[0]) * 256) + (+d[1])) * 256) + (+d[2])) * 256) + (+d[3]); 
    40     } 
    41  
    42     num2ip(num) { 
    43         var d = num % 256; 
    44         for (var i = 3; i > 0; i--) { 
    45             num = Math.floor(num / 256); 
    46             d = num % 256 + '.' + d; 
     43/** 
     44 * Maps a 2D point to a matching 1D number 
     45 * @param p Point to be mapped 
     46 * @param n Maximum value of 1D (by default 2**32) 
     47 * @returns {number} The 1D mapped from a 2D point 
     48 */ 
     49function xy2d(p, n=2**32){ 
     50        var rx; 
     51        var ry; 
     52        var d=0; 
     53        for (var s=n/2; s>0; s/=2) { 
     54            rx = (p.x & s) > 0; 
     55            ry = (p.y & s) > 0; 
     56            d += s * s * ((3 * rx) ^ ry); 
     57            p.rotate(s, rx, ry); 
    4758        } 
    4859        return d; 
     60} 
     61 
     62/** 
     63 * Maps a dot notation of IP to a number 
     64 * @param ip Ip dotted notation 
     65 * @returns {number} The number that matches the notation 
     66 */ 
     67function ip2num(ip){ 
     68    ip = ip.split("."); 
     69    return parseInt(ip[0])*256**3 + parseInt(ip[1])*256**2 + parseInt(ip[2])*256 + parseInt(ip[3]); 
     70} 
     71 
     72/** 
     73 * Holds information about a pool 
     74 * @param id Of a pool 
     75 * @param ip Of network 
     76 * @param prefix Of a pool 
     77 * @param parent Parent object 
     78 * @param description Description of a pool 
     79 * @constructor 
     80 */ 
     81function Pool(id, ip, prefix, parent, description){ 
     82    this.id = id; 
     83    this.ip = ip; 
     84    this.prefix = prefix; 
     85    this.parent = parent; 
     86    this.description = description; 
     87    this.subnets = []; 
     88    this.isTopLevel = false; 
     89    this.utalization = 100; 
     90    this.numberOfIps =  2 ** (32-prefix); 
     91} 
     92 
     93Pool.prototype = { 
     94    /** 
     95     * Adds a pool to the pools array of subnets 
     96     * @param child 
     97     */ 
     98    addSubnet: function (child) { 
     99        this.subnets.push(child); 
     100    }, 
     101    /** 
     102     * Returns the percentage of pool utilization, if a pool has no subnets its utilization is 100 if not its calculated according to the utilization of subnets 
     103     * @returns {number} 
     104     */ 
     105    getUtilization(){ 
     106        if(this.subnets.length === 0){ 
     107            this.utalization = 100; 
     108            console.log("this is leaf", this.ip+'/'+this.prefix, this.utalization, this.numberOfIps); 
     109            return this.utalization; 
     110        } 
     111        this.utalization = 0; 
     112        for(var i=0; i<this.subnets.length; i++){ 
     113            var item = this.subnets[i]; 
     114            this.utalization += (item.numberOfIps/this.numberOfIps) * item.getUtilization(); 
     115            console.log('current utalization', this.utalization); 
     116        } 
     117        console.log("this is not leaf", this.ip+'/'+this.prefix, this.utalization, this.numberOfIps); 
     118        return this.utalization; 
    49119    } 
    50  
    51     subnetSize(subnet) { 
    52         var subnet_str = String(subnet); 
    53         var times = 32 - parseInt(subnet_str.split("/")[1]); 
    54         var subnet_ips = Math.pow(2, times); 
    55         var shape_size = Math.sqrt(subnet_ips) / this.ips_pixel; 
    56         return shape_size; 
    57     } 
    58  
    59     subnetXY(subnet) { 
    60         var subnet_str = String(subnet); 
    61         var start_num = this.ip2num(subnet_str.split("/")[0]); 
    62         var start_xy = d2xy(start_num); 
    63         var x = start_xy.x / this.ips_pixel; 
    64         var y = start_xy.y / this.ips_pixel; 
    65         return [x, y]; 
    66     } 
    67  
    68     HSVtoRGB(h, s, v) { 
    69         var r, g, b, i, f, p, q, t; 
    70         if (arguments.length === 1) { 
    71             s = h.s, v = h.v, h = h.h; 
    72         } 
    73         i = Math.floor(h * 6); 
    74         f = h * 6 - i; 
    75         p = v * (1 - s); 
    76         q = v * (1 - f * s); 
    77         t = v * (1 - (1 - f) * s); 
    78         switch (i % 6) { 
    79             case 0: 
    80                 r = v, g = t, b = p; 
    81                 break; 
    82             case 1: 
    83                 r = q, g = v, b = p; 
    84                 break; 
    85             case 2: 
    86                 r = p, g = v, b = t; 
    87                 break; 
    88             case 3: 
    89                 r = p, g = q, b = v; 
    90                 break; 
    91             case 4: 
    92                 r = t, g = p, b = v; 
    93                 break; 
    94             case 5: 
    95                 r = v, g = p, b = q; 
    96                 break; 
    97         } 
    98  
    99         return { 
    100             r: Math.round(r * 255), 
    101             g: Math.round(g * 255), 
    102             b: Math.round(b * 255) 
    103         }; 
    104     } 
    105  
    106     componentToHex(c) { 
    107         var hex = c.toString(16); 
    108         return hex.length == 1 ? '0' + hex : hex; 
    109     } 
    110  
    111     rgbToHex(r, g, b) { 
    112         return '#' + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b); 
    113     } 
    114  
    115     getUrlParam(sParam) { 
    116         var sPageURL = decodeURIComponent(window.location.search.substring(1)); 
    117         var sURLVariables = sPageURL.split('&'); 
    118         var sParameterName; 
    119         var i; 
    120  
    121         for (i = 0; i < sURLVariables.length; i++) { 
    122             sParameterName = sURLVariables[i].split('='); 
    123  
    124             if (sParameterName[0] === sParam) { 
    125                 return sParameterName[1] === undefined ? true : sParameterName[1]; 
    126             } 
    127         } 
    128         return false; 
    129     } 
    130  
    131     UpdateQueryString(key, value, url) { 
    132         if (!url) { 
    133             url = window.location.href; 
    134         } 
    135         var re = new RegExp('([?&])' + key + '=.*?(&|#|$)(.*)', 'gi'), 
    136             hash; 
    137  
    138         if (re.test(url)) { 
    139             if (typeof value !== 'undefined' && value !== null) { 
    140                 return url.replace(re, '$1' + key + '=' + value + '$2$3'); 
    141             } 
    142             else { 
    143                 hash = url.split('#'); 
    144                 url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, ''); 
    145                 if (typeof hash[1] !== 'undefined' && hash[1] !== null) { 
    146                     url += '#' + hash[1]; 
    147                 } 
    148                 return url; 
    149             } 
    150         } 
    151         else { 
    152             if (typeof value !== 'undefined' && value !== null) { 
    153                 var separator = url.indexOf('?') !== -1 ? '&' : '?'; 
    154                 hash = url.split('#'); 
    155                 url = hash[0] + separator + key + '=' + value; 
    156                 if (typeof hash[1] !== 'undefined' && hash[1] !== null) { 
    157                     url += '#' + hash[1]; 
    158                 } 
    159                 return url; 
    160             } 
    161             else { 
    162                 return url; 
    163             } 
    164         } 
    165     } 
    166  
    167     draw(subnet, description) { 
    168         var times = 32 - parseInt(subnet.split('/')[1]); 
    169         var subnet_ips = Math.pow(2, times); 
    170         var shape_size = Math.sqrt(subnet_ips) / this.ips_pixel; 
    171  
    172         var start_num = this.ip2num(subnet.split('/')[0]); 
    173  
    174         var start_xy = d2xy(start_num); 
    175  
    176         var x = start_xy.x / this.ips_pixel; 
    177         var y = start_xy.y / this.ips_pixel; 
    178  
    179         this.svg.append('rect').attr('x', x).attr('y', y).attr('height', shape_size).attr('width', shape_size).style('fill', this.rgbToHex(times * 8, times * 8, times * 8)).style('opacity', 0.3).attr('id', subnet).attr('n', subnet_ips).attr('d', description); 
    180     } 
    181  
    182     loadPrefix(i, url) { 
    183         var self = this; 
    184         $.getJSON( url, function(data) { 
    185             if (data.next !== null) { 
    186                 self.loadPrefix(i, data.next); 
    187                 if (self.data[i] === undefined) { 
    188                     self.data[i] = data.results; 
    189                 } 
    190                 else { 
    191                     self.data[i].concat(data.results); 
    192                 } 
    193                 for (var j = 0; j < data.results.length; j++) { 
    194                     self.draw(data.results[j].network + '/' + data.results[j].prefix_length, data.results[j].description); 
    195                 } 
    196             } 
    197             else { 
    198                 self.loadedPrefixes++; 
    199                 if (self.data[i] == undefined) { 
    200                     self.data[i] = data.results; 
    201                 } 
    202                 else { 
    203                     self.data[i].concat(data.results); 
    204                 } 
    205                 for (var j = 0; j < data.results.length; j++) { 
    206                     self.draw(data.results[j].network + '/' + data.results[j].prefix_length, data.results[j].description); 
    207                 } 
    208                 if (self.loadedPrefixes == 32) { 
    209                     jQuery('rect').tipsy({ 
    210                         gravity: 'w', 
    211                         html: true, 
    212                         title: function () { 
    213                             return this.id + '<br>Number of hosts: ' + $(this).attr('n') + '<br>Network name: ' + $(this).attr('d'); 
    214                         } 
    215                     }); 
    216                     var scale = self.getUrlParam('scale'); 
    217                     var start = String(self.getUrlParam('start')).split(','); 
    218                     if (scale && start) { 
    219                         self.svg.selectAll('rect').attr('transform', 'translate(' + start[0] * -1 * scale + ',' + start[1] * -1 * scale + ') scale(' + scale + ')'); 
    220                     } 
    221                     else { 
    222                         var scale = self.size / self.subnetSize(self.subnet); 
    223                         var start = self.subnetXY(self.subnet); 
    224                         self.svg.selectAll('rect').attr('transform', 'translate(' + (start[0] * -1 * scale - scale/2) + ',' + (start[1] * -1 * scale - scale/2) + ') scale(' + scale + ')'); 
    225                     } 
    226                 } 
    227             } 
    228  
    229         }); 
    230     } 
    231  
    232     load() { 
    233         for (var i = 0; i < 33; i++) { 
    234             this.loadPrefix(i, this.base_url + '?prefix_length=' + i); 
    235         } 
    236     } 
    237  
    238     cidrToRange(cidr) { 
    239        var range = [2]; 
    240        cidr = cidr.split('/'); 
    241        var cidr_1 = parseInt(cidr[1]) 
    242        range[0] = (this.ip2num(cidr[0])) & ((-1 << (32 - cidr_1))); 
    243        var start = this.ip2num(range[0]) 
    244        range[1] = range[0] + Math.pow(2, (32 - cidr_1)) - 1; 
    245        return [range[0]-this.offset, range[1]-this.offset]; 
    246     } 
    247  
    248     calcTopNodes() { 
    249         var res = new Array(); 
    250         for (var i = 0; i < this.data.length; i++) { 
    251             for (var j = 0; j < this.data[i].length; j++) { 
    252                 var node = this.data[i][j]; 
    253                 if (node['@id'] == node.top_level['@id']) { 
    254                     res.push(node); 
    255                 } 
    256             } 
    257         } 
    258         return res; 
    259     } 
    260  
    261     getMaxOfArray(numArray) { 
    262       return Math.max.apply(null, numArray); 
    263     } 
    264  
    265     getMinOfArray(numArray) { 
    266       return Math.min.apply(null, numArray); 
    267     } 
    268 } 
     120}; 
  • nodewatcher/modules/frontend/ip_space/static/ip_space/js/main.js

    r80bd0394c57d rf9a4dab0b40a  
    1 $(document).ready(function () { 
    2     //Create d3 object on #ipspace 
    3     var svgContainer = d3.select('#ipspace'); 
     1var pools_url = $('#api_url').attr('data-url') + '?limit=1000'; 
     2pools_url = 'https://nodes.wlan-si.net/api/v2/pool/ip/?limit=1000'; 
     3var pools_array = []; 
     4window.topLevelPools = []; 
     5window.pools = {}; 
    46 
    5     //Get bootstrap width and match it in height 
    6     var size = svgContainer.node().getBoundingClientRect().width; 
    7     svgContainer.style('height', size + 'px'); 
     7/** 
     8 * Loads the results into an array until we get to the end of next url 
     9 * @param a array into which the data gets loaded 
     10 * @param url which to load 
     11*/ 
     12function loadData(a, url) { 
     13    $.getJSON( url, function( data ) { 
     14        a = a.concat(data['results']); 
     15        if (data['next'] !== null) { 
     16            loadData(a, data['next']); 
     17        } 
     18        else{ 
     19            buildTree(a); 
     20        } 
     21    }); 
     22} 
    823 
    9     //Init vars 
    10     var max_x = 0; 
    11     var max_y = 0; 
    12     var min_x = 65536; 
    13     var min_y = 65536; 
    14     var last_size = 0; 
     24/** 
     25 * Arranges the pools in the array into a tree 
     26 * @param a Array of pools 
     27 */ 
     28function buildTree(a) { 
     29    //Map each pool to id 
     30    a.forEach(function (pool) { 
     31        pools[pool['@id']] = new Pool(pool['@id'], pool['network'], pool['prefix_length'], null, pool['description']); 
     32    }); 
     33    //Add each pool to a parent pool 
     34    a.forEach(function (pool) { 
     35        if (pool['@id'] === pool['top_level']['@id']) { 
     36            pools[pool['@id']].isTopLevel = true; 
     37            topLevelPools.push(pools[pool['@id']]); 
     38        }else{ 
     39            pools[pool['top_level']['@id']].addSubnet(pools[pool['@id']]); 
     40            pools[pool['@id']].parent = pools[pool['top_level']['@id']]; 
     41        } 
     42    }); 
     43} 
    1544 
    16     //For each top level node check what is the min and the max and save it 
    17     $('#topnodes > li').each(function (data) { 
    18         var start_xy = d2xy(Support.ip2num(Support.cidrToRange($(this).attr('cidr'))[0])); 
    19         var size = Support.subnetSize($(this).attr('cidr')); 
    20         console.log(start_xy, size); 
    21  
    22     }); 
    23  
    24     //Convert min and max cords to number 
    25     var start_num = xy2d(min_x, min_y); 
    26     var stop_num = xy2d(max_x + last_size, max_y + last_size); 
    27  
    28     //Calculate the smallest number to fit both min and max 
    29     var ips_needed = stop_num - start_num; 
    30     var mask = 0; 
    31     while (ips_needed > Math.pow(2, mask)) { 
    32         mask++; 
    33     } 
    34     mask = 32 - mask; 
    35  
    36     //Convert starting number to ip 
    37     var start_ip = Support.num2ip(start_num); 
    38     var min_subnet = start_ip + '/' + mask; 
    39  
    40     //Add zoom to fit to list of subnets 
    41     $('#topnodes').prepend('<li id="cidr" cidr="' + min_subnet + '"><a>' + min_subnet + ' (Zoom to fit)</a></li>'); 
    42     var api_url = $('#api_url').data('url'); 
    43  
    44     //Init drawing object and load all the ip pools 
    45     var cidr = new DrawCidr(svgContainer, size, min_subnet, api_url); 
    46     cidr.load(); 
    47 }); 
     45loadData(pools_array, pools_url); 
Note: See TracChangeset for help on using the changeset viewer.