Revision 96d725ac

b/ui/static/snf/js/models.js
330 330
                var removed_from_net = this.vms.remove(model.id);
331 331
                var removed_from_vm = model.networks.remove(this.id);
332 332
                if (removed_from_net) {this.trigger("vm:disconnect", model, this); this.change()};
333
                if (removed_from_vm) {vm.trigger("network:disconnect", this, model); this.change()};
333
                if (removed_from_vm) {model.trigger("network:disconnect", this, model); this.change()};
334 334
                return;
335 335
            }
336 336
            
......
457 457
            // this will dynamicaly change if the server responds that
458 458
            // images get refreshed on different intervals
459 459
            this.stats_update_interval = synnefo.config.STATS_INTERVAL || 5000;
460
            this.stats_available = false;
460 461

  
461 462
            // initialize interval
462 463
            this.init_stats_intervals(this.stats_update_interval);
463 464
            
464
            // clear stats intervals on update
465
            this.bind("remove", _.bind(function(){
466
                try {
467
                    window.clearInterval(this.stats_interval);
468
                } catch (err) {};
469
            }, this));
470
            
471 465
            this.bind("change:progress", _.bind(this.update_building_progress, this));
472 466
            this.update_building_progress();
473 467

  
......
477 471
            this.set({linked_to_nets:this.get("linked_to_nets") || []});
478 472
            this.set({firewalls:this.get("firewalls") || []});
479 473

  
480
            this.action_error = false;
474
            this.bind("change:state", _.bind(function(){if (this.state() == "DESTROY") { this.handle_destroy() }}, this))
481 475
        },
482 476

  
483 477
        handle_firewall_change: function() {
......
555 549

  
556 550
        // clear and reinitialize update interval
557 551
        init_stats_intervals: function (interval) {
558
            try {
559
                window.clearInterval(this.stats_interval);
560
            } catch (err){}
561
            //this.stats_interval = window.setInterval(_.bind(this.update_stats, this), interval);
562
            //this.update_stats(true);
552
            this.stats_fetcher = this.get_stats_fetcher(this.stats_update_interval);
553
            this.stats_fetcher.start();
554
            this.update_stats(true);
563 555
        },
564 556
        
557
        get_stats_fetcher: function(timeout) {
558
            var cb = _.bind(function(data){
559
                this.update_stats();
560
            }, this);
561
            var fetcher = new snf.api.updateHandler({'callback': cb, timeout:timeout});
562
            return fetcher;
563
        },
564

  
565 565
        // do the api call
566 566
        update_stats: function(force) {
567 567
            // do not update stats if flag not set
568 568
            if (!this.do_update_stats && !force) {
569 569
                return;
570 570
            }
571
            
571

  
572 572
            // make the api call, execute handle_stats_update on sucess
573 573
            // TODO: onError handler ???
574 574
            stats_url = this.url() + "/stats";
575
            this.sync("GET", this, {url: stats_url, refresh:true, success: _.bind(this.handle_stats_update, this)});
575
            this.sync("GET", this, {
576
                handles_error:true, 
577
                url: stats_url, 
578
                refresh:true, 
579
                success: _.bind(this.handle_stats_update, this),
580
                error: _.bind(this.handle_stats_error)
581
            });
582
        },
583

  
584
        get_stats_image: function(stat, type) {
576 585
        },
577 586
        
587
        _set_stats: function(stats) {
588
            var silent = silent === undefined ? false : silent;
589
            // unavailable stats while building
590
            if (this.get("status") == "BUILD") { 
591
                this.stats_available = false;
592
            } else { this.stats_available = true; }
593

  
594
            if (this.get("status") == "DESTROY") { this.stats_available = false; }
595
            
596
            this.set({stats: stats}, {silent:true});
597
            this.trigger("stats:update", stats);
598
        },
599

  
600
        unbind: function() {
601
            models.VM.__super__.unbind.apply(this, arguments);
602
        },
603

  
604
        handle_stats_error: function() {
605
            stats = {};
606
            _.each(['cpuBar', 'cpuTimeSeries', 'netBar', 'netTimeSeries'], function(k) {
607
                stats[k] = false;
608
            });
609

  
610
            this.set({'stats': stats});
611
        },
612

  
578 613
        // this method gets executed after a successful vm stats api call
579 614
        handle_stats_update: function(data) {
615
            var self = this;
580 616
            // avoid browser caching
617
            
581 618
            if (data.stats && _.size(data.stats) > 0) {
582 619
                var ts = $.now();
583 620
                var stats = data.stats;
621
                var images_loaded = 0;
622
                var images = {};
623

  
624
                function check_images_loaded() {
625
                    images_loaded++;
626

  
627
                    if (images_loaded == 4) {
628
                        self._set_stats(images);
629
                    }
630
                }
584 631
                _.each(['cpuBar', 'cpuTimeSeries', 'netBar', 'netTimeSeries'], function(k) {
632
                    
585 633
                    stats[k] = stats[k] + "?_=" + ts;
634
                    
635
                    var stat = k.slice(0,3);
636
                    var type = k.slice(3,6) == "Bar" ? "bar" : "time";
637
                    var img = $("<img />");
638
                    var val = stats[k];
639
                    
640
                    // load stat image to a temporary dom element
641
                    // update model stats on image load/error events
642
                    img.load(function() {
643
                        images[k] = val;
644
                        check_images_loaded();
645
                    });
646

  
647
                    img.error(function() {
648
                        images[stat + type] = false;
649
                        check_images_loaded();
650
                    });
651

  
652
                    img.attr({'src': stats[k]});
586 653
                })
587 654
                data.stats = stats;
588 655
            }
589
            this.set({'stats': data.stats}, {silent:true});
590
            // trigger the event
591
            this.trigger("stats:update");
592
    
656

  
593 657
            // do we need to change the interval ??
594 658
            if (data.stats.refresh * 1000 != this.stats_update_interval) {
595 659
                this.stats_update_interval = data.stats.refresh * 1000;
596
                this.init_stats_intervals(this.stats_update_interval);
660
                this.stats_fetcher.timeout = this.stats_update_interval;
661
                this.stats_fetcher.stop();
662
                this.stats_fetcher.start();
597 663
            }
598 664
        },
599
        
665

  
600 666
        // helper method that sets the do_update_stats
601 667
        // in the future this method could also make an api call
602 668
        // immediaetly if needed
603 669
        enable_stats_update: function() {
604 670
            this.do_update_stats = true;
605 671
        },
672
        
673
        handle_destroy: function() {
674
            this.stats_fetcher.stop();
675
        },
606 676

  
607 677
        require_reboot: function() {
608 678
            if (this.is_active()) {
......
1064 1134
    models.VM.ACTIVE_STATES = [
1065 1135
        'BUILD', 'REBOOT', 'ACTIVE',
1066 1136
        'BUILD_INIT', 'BUILD_COPY', 'BUILD_FINAL',
1067
        'SHUTDOWN', 'CONNECT', 'DISCONNECT'
1137
        'SHUTDOWN', 'CONNECT', 'DISCONNECT', 'DESTROY'
1068 1138
    ]
1069 1139

  
1070 1140
    models.VM.BUILDING_STATES = [
......
1249 1319
                vm.clear_pending_action();
1250 1320
            })
1251 1321
        },
1322

  
1323
        reset_stats_update: function() {
1324
            this.each(function(vm) {
1325
                vm.do_update_stats = false;
1326
            })
1327
        },
1252 1328
        
1253 1329
        has_meta: function(vm_data) {
1254 1330
            return vm_data.metadata && vm_data.metadata.values
b/ui/static/snf/js/ui/web/ui_icon_view.js
103 103

  
104 104
                if (this.toggler.hasClass("open")) {
105 105
                    this.toggler.removeClass("open");
106
                    this.vm.do_update_stats = false;
106 107
                } else {
107 108
                    this.toggler.addClass("open");
108
                    get_server_stats(this.vm.id);
109
                    this.vm.do_update_stats = true;
109 110
                }
110 111
                
111 112
                var self = this;
......
441 442
            this.net_loading = this.el.find(".network-graph .stat-busy");
442 443
            this.net_error = this.el.find(".network-graph .stat-error");
443 444
            this.net_img = this.el.find(".network-graph .stat-img");
445

  
446
            this.loading = this.el.find(".stat-busy");
447
            this.error = this.el.find(".stat-error");
448
            this.img = this.el.find(".stat-img");
444 449
            
445 450
            // initial state paremeters
446
            this.is_building = (this.vm.get("status") == "BUILD");
447
            this.stats_error = false;
448 451
            this.stats = this.vm.get("stats");
449
            this.loading = false;
450 452

  
451 453
            // timeseries or bar images ?
452 454
            this.stats_type = options.stats_type || "bar";
453
            
454
            // stats undefined so probably not loaded yet
455
            if (this.stats === undefined) {
456
                this.loading = true;
457
            }
458 455

  
459 456
            views.VMStatsView.__super__.initialize.apply(this, arguments);
460 457
            this.set_handlers();
461 458
            this.update_layout();
459

  
460
            this.net_loading.show();
461
            this.net_error.hide();
462
            this.cpu_loading.show();
463
            this.cpu_error.hide();
464

  
465
            this.net_img.hide();
466
            this.cpu_img.hide();
462 467
        },
463 468

  
464 469
        
465 470
        set_handlers: function() {
466 471
            // update view state when vm stats update gets triggered
467 472
            this.vm.bind("stats:update", _.bind(function(){
468
                // update building state
469
                if (this.vm.get("status") == "BUILD") {
470
                    this.is_building = true;
471
                } else {
472
                    this.is_building = false;
473
                }
474
                
475
                // update loading state
476
                this.stats = this.vm.get("stats");
477
                if (this.stats == undefined) {
478
                    this.loading = true
479
                } else {
480
                    this.loading = false;
481
                }
482
                
483 473
                // update the layout
484 474
                this.update_layout();
485 475
            }, this));
486

  
487
            this.vm.bind("stats:error", _.bind(function(){
488
                this.stats_error = true;
489
            }, this))
490

  
491
            this.cpu_img.error(_.bind(function(){
492
                this.stats_error = true;
493
                this.update_layout();
494
            }, this));
495

  
496
            this.net_img.error(_.bind(function(){
497
                this.stats_error = true;
498
                this.update_layout();
499
            }, this));
500 476
        },
501 477
        
502 478
        get_images: function (type) {
......
508 484
        },
509 485

  
510 486
        update_layout: function() {
511
            if (this.stats_error) {
512
                this.net_loading.hide();
513
                this.cpu_loading.hide();
514
                this.net_img.hide();
515
                this.cpu_img.hide();
516
                this.cpu_error.show();
517
                this.net_error.show();
518
                return;
519
            }
487
            if (!this.vm.stats_available) {
488
                this.loading.show();
489
                this.img.hide();
490
                this.error.hide();
491
            } else {
492
                this.loading.hide();
493
                this.stats = this.vm.get("stats");
494
                var images = this.get_images(this.stats_type);
520 495

  
521
            if (this.loading) {
522
                this.net_loading.show();
523
                this.cpu_loading.show();
524
                this.net_img.hide();
525
                this.cpu_img.hide();
526
                this.cpu_error.hide();
527
                this.net_error.hide();
528
                return;
529
            }
496
                if (images.cpu) {
497
                    this.cpu_img.attr({src:images.cpu}).show();
498
                    this.cpu_error.hide();
499
                } else {
500
                    this.cpu_img.hide();
501
                    this.cpu_error.show();
502
                }
530 503

  
531
            this.net_loading.hide();
532
            this.cpu_loading.hide();
533
            this.cpu_error.hide();
534
            this.net_error.hide();
535
            
536
            this.net_img.attr("src", this.get_images(this.stats_type).net);
537
            this.cpu_img.attr("src", this.get_images(this.stats_type).cpu);
538
            this.net_img.show();
539
            this.cpu_img.show();
504
                if (images.net) {
505
                    this.net_img.attr({src:images.net}).show();
506
                    this.net_error.hide();
507
                } else {
508
                    this.net_img.hide();
509
                    this.net_error.show();
510
                }
511
            }
512
            $(window).trigger("resize");
540 513
        }
541 514
    });
542 515

  
b/ui/static/snf/js/ui/web/ui_main_view.js
676 676
            // FIXME: depricated
677 677
            $(".large-spinner").remove();
678 678

  
679
            storage.vms.reset_pending_actions();
680
            storage.vms.reset_stats_update();
681

  
679 682
            // show current view
680 683
            this.show_view_pane();
681 684
            view.show();
......
706 709
            // trigger view change event
707 710
            this.trigger("view:change", this.current_view.view_id);
708 711
            $(window).trigger("view:change");
709
            storage.vms.reset_pending_actions();
710 712
            return view;
711 713
        },
712 714

  
b/ui/static/snf/js/views.js
207 207
        onClose: function () {},
208 208

  
209 209
        show: function() {
210
            // close opened overlays
210 211
            var hidden = false;
211 212
            _.each(views._overlay_index, function(ovr){
212 213
                if (ovr == this) { return };
......
216 217
                }
217 218
            })
218 219

  
219
            if (hidden) {
220
                delay = 300;
221
            } else {
222
                delay = 0;
223
            }
220
            // do we need to wait for other overlays to close ???
221
            if (hidden) { delay = 300; } else { delay = 0; }
224 222
            window.setTimeout(_.bind(function(){ this.overlay.load() }, this), delay)
225 223
            return this;
226 224
        },

Also available in: Unified diff