Revision 126a01f2

b/snf-cyclades-app/synnefo/app_settings/default/ui.py
117 117
UI_HANDLE_WINDOW_EXCEPTIONS = True
118 118

  
119 119
# A list of os names that support ssh public key assignment
120
UI_SUPPORT_SSH_OS_LIST = ['debian', 'fedora', 'okeanos', 'ubuntu', 'kubuntu', 'centos']
120
UI_SUPPORT_SSH_OS_LIST = ['debian', 'fedora', 'okeanos', 'ubuntu', 'kubuntu',
121
                          'centos', 'archlinux']
121 122

  
122 123
# OS/username map to identify default user name for the specified os
123 124
UI_OS_DEFAULT_USER_MAP = {
......
126 127
    'windows': 'Administrator'
127 128
}
128 129

  
130
##########################
131
# UI NETWORK VIEW SETTINGS
132
##########################
133

  
134
# Available network types for use to choose when creating a private network
135
# If only one set, no select options will be displayed
136
UI_NETWORK_AVAILABLE_NETWORK_TYPES = {'PRIVATE_FILTERED': 'mac-filtering'}
137

  
138
# Suggested private networks to let the user choose from when creating a private
139
# network with dhcp enabled
140
UI_NETWORK_AVAILABLE_SUBNETS = ['10.0.0.1/24', '192.168.1.1/24']
141

  
142
# Whether to display already connected vm's to the network connect overlay
143
UI_NETWORK_ALLOW_DUPLICATE_VM_NICS = False
144

  
145
# Whether to display destroy action on private networks that contain vms. If
146
# set to True, destroy action will only get displayed if user disconnect all
147
# virtual machines from the network.
148
UI_NETWORK_STRICT_DESTROY = False
149

  
129 150

  
130 151
###############
131 152
# UI EXTENSIONS
b/snf-cyclades-app/synnefo/ui/static/snf/css/main.css
21 21
    text-align:center;
22 22
    font-size: 16px;
23 23
    background-position: 0px 35px; 
24
    overflow-y: scroll;
24 25
}
25 26

  
26 27
a, a:hover, a:active, a:focus, div:focus, span:focus, li:focus {
......
598 599
    width: 140px;
599 600
}
600 601

  
601
.overlay-networks-create .form-actions {
602
    float: right;
603
    margin-top: -26px !important;
602
.overlay-networks-create .form-action {
603
  float: left;
604
}
605

  
606
.overlay-networks-create .fixpos {
607
  margin-top: 3px;
608
}
609

  
610
.overlay-networks-create .col-fields.bordered {
611
  border-bottom: 1px solid #CCC;
612
  margin-bottom: 10px;
613
  padding-bottom: 10px;
614
}
615

  
616
.overlay-networks-create .col-fields {
617
  margin-bottom: 10px;
618
}
619

  
620
form .fields-desc {
621
  font-size: 0.8em !important; 
622
  margin: 5px 0;
623
  padding-bottom: 0 !important;
624
}
625

  
626
.overlay-networks-create form select {
627
  padding: 1px;
628
}
629

  
630
.overlay-networks-create #network-create-subnet-custom {
631
  width: 125px;
632
}
633

  
634
.overlay-networks-create .col-fields .form-field {
635
  float: left;
636
  margin-right: 20px;
637
}
638

  
639
.overlay-networks-create .col-fields .right-field {
640
  float: right;
641
  width: 210px;
642
  margin-right: 0px;
643
}
644

  
645
.overlay-networks-create .use-dhcp {
646
  width: auto;
604 647
}
605 648

  
606 649
#wizard #start:hover, #networks-wizard .create:hover {
......
1095 1138
}
1096 1139

  
1097 1140
.error-state .indicator1, .error-state .indicator2, .error-state .indicator3, .error-state .indicator4 {
1098
    background-color: #ff0000;
1141
    background-color: #ff0000 !important;
1099 1142
}
1100 1143

  
1101 1144
.terminated-state .indicator1, .terminated-state .indicator2, .terminated-state .indicator3, .terminated-state .indicator4 {
......
2191 2234
}
2192 2235

  
2193 2236
.network-machine h5 {
2194
    margin-bottom: 26px;
2237
    margin-bottom: 20px;
2195 2238
    margin-top:0px;
2196 2239
}
2197 2240

  
......
2552 2595
    display:none;
2553 2596
}
2554 2597

  
2598
div.network-cont.disable-destroy .actions .destroy {
2599
    display: none !important;
2600
}
2601

  
2602
div.network-cont.pending .actions .action-add {
2603
    display: none;
2604
}
2605

  
2606
div.network-cont.in-error .actions .action-add {
2607
    display: none;
2608
}
2609

  
2555 2610
div.network a.action-network-add {
2556 2611
    display: none;
2557 2612
}
......
2754 2809
    right:0;
2755 2810
}
2756 2811

  
2812
div.network .nic-ip {
2813
  font-size: 0.8em;
2814
}
2815

  
2757 2816
div.network div.display a {
2758 2817
    visibility: visible;
2759 2818
}
......
3030 3089
h5.machine-connect {
3031 3090
    font-size: 75%;
3032 3091
    margin-bottom: 3px;
3092
    height: 23px;
3033 3093
}
3034 3094

  
3035 3095
.machine-connect span {
b/snf-cyclades-app/synnefo/ui/static/snf/js/models.js
56 56
        var baseurl = baseurl || snf.config.api_urls[this.api_type];
57 57
        return baseurl + "/" + this.path;
58 58
    }
59

  
60
    var NIC_REGEX = /^nic-([0-9]+)-([0-9]+)$/
59 61
    
60 62
    // i18n
61 63
    BUILDING_MESSAGES = window.BUILDING_MESSAGES || {'INIT': 'init', 'COPY': '{0}, {1}, {2}', 'FINAL': 'final'};
......
337 339

  
338 340
    });
339 341
    
340
    //network vms list helper
341
    var NetworkVMSList = function() {
342
        this.initialize = function() {
343
            this.vms = [];
344
            this.pending = [];
345
            this.pending_for_removal = [];
346
        }
347
        
348
        this.add_pending_for_remove = function(vm_id) {
349
            if (this.pending_for_removal.indexOf(vm_id) == -1) {
350
                this.pending_for_removal.push(vm_id);
351
            }
352

  
353
            if (this.pending_for_removal.length) {
354
                this.trigger("pending:remove:add");
355
            }
356
        },
357

  
358
        this.add_pending = function(vm_id) {
359
            if (this.pending.indexOf(vm_id) == -1) {
360
                this.pending[this.pending.length] = vm_id;
361
            }
362

  
363
            if (this.pending.length) {
364
                this.trigger("pending:add");
365
            }
366
        }
367

  
368
        this.check_pending = function() {
369
            var len = this.pending.length;
370
            var args = [this.pending];
371
            this.pending = _.difference(this.pending, this.vms);
372
            if (len != this.pending.length) {
373
                if (this.pending.length == 0) {
374
                    this.trigger("pending:clear");
375
                }
376
            }
377

  
378
            var len = this.pending_for_removal.length;
379
            this.pending_for_removal = _.intersection(this.pending_for_removal, this.vms);
380
            if (this.pending_for_removal.length == 0) {
381
                this.trigger("pending:remove:clear");
382
            }
383

  
384
        }
385

  
386

  
387
        this.add = function(vm_id) {
388
            if (this.vms.indexOf(vm_id) == -1) {
389
                this.vms[this.vms.length] = vm_id;
390
                this.trigger("network:connect", vm_id);
391
                this.check_pending();
392
                return true;
393
            }
394
        }
395

  
396
        this.remove = function(vm_id) {
397
            if (this.vms.indexOf(vm_id) > -1) {
398
                this.vms = _.without(this.vms, vm_id);
399
                this.trigger("network:disconnect", vm_id);
400
                this.check_pending();
401
                return true;
402
            }
403
        }
404

  
405
        this.get = function() {
406
            return this.vms;
407
        }
408

  
409
        this.list = function() {
410
            return storage.vms.filter(_.bind(function(vm){
411
                return this.vms.indexOf(vm.id) > -1;
412
            }, this))
413
        }
414

  
415
        this.initialize();
416
    };
417
    _.extend(NetworkVMSList.prototype, bb.Events);
418
    
419
    // vm networks list helper
420
    var VMNetworksList = function() {
421
        this.initialize = function() {
422
            this.networks = {};
423
            this.network_ids = [];
424
        }
425

  
426
        this.add = function(net_id, data) {
427
            if (!this.networks[net_id]) {
428
                this.networks[net_id] = data || {};
429
                this.network_ids[this.network_ids.length] = net_id;
430
                this.trigger("network:connect", net_id);
431
                return true;
432
            }
433
        }
434

  
435
        this.remove = function(net_id) {
436
            if (this.networks[net_id]) {
437
                delete this.networks[net_id];
438
                this.network_ids = _.without(this.network_ids, net_id);
439
                this.trigger("network:disconnect", net_id);
440
                return true;
441
            }
442
            return false;
443
        }
444

  
445
        this.get = function() {
446
            return this.networks;
447
        }
448

  
449
        this.list = function() {
450
            return storage.networks.filter(_.bind(function(net){
451
                return this.network_ids.indexOf(net.id) > -1;
452
            }, this))
453
        }
454

  
455
        this.initialize();
456
    };
457
    _.extend(VMNetworksList.prototype, bb.Events);
458
        
459 342
    models.ParamsList = function(){this.initialize.apply(this, arguments)};
460 343
    _.extend(models.ParamsList.prototype, bb.Events, {
461 344

  
......
559 442
    models.Network = models.Model.extend({
560 443
        path: 'networks',
561 444
        has_status: true,
445
        defaults: {'connecting':0},
562 446
        
563 447
        initialize: function() {
564
            this.vms = new NetworkVMSList();
565
            this.vms.bind("pending:add", _.bind(this.handle_pending_connections, this, "add"));
566
            this.vms.bind("pending:clear", _.bind(this.handle_pending_connections, this, "clear"));
567
            this.vms.bind("pending:remove:add", _.bind(this.handle_pending_connections, this, "add"));
568
            this.vms.bind("pending:remove:clear", _.bind(this.handle_pending_connections, this, "clear"));
569

  
570 448
            var ret = models.Network.__super__.initialize.apply(this, arguments);
571

  
572
            storage.vms.bind("change:linked_to_nets", _.bind(this.update_connections, this, "vm:change"));
573
            storage.vms.bind("add", _.bind(this.update_connections, this, "add"));
574
            storage.vms.bind("remove", _.bind(this.update_connections, this, "remove"));
575
            storage.vms.bind("reset", _.bind(this.update_connections, this, "reset"));
576

  
577
            this.bind("change:linked_to", _.bind(this.update_connections, this, "net:change"));
578
            this.update_connections();
579
            this.update_state();
580
            
581 449
            this.set({"actions": new models.ParamsList(this, "actions")});
582

  
450
            this.update_state();
451
            this.bind("change:nics", _.bind(synnefo.storage.nics.update_net_nics, synnefo.storage.nics));
452
            this.bind("change:status", _.bind(this.update_state, this));
583 453
            return ret;
584 454
        },
585 455

  
......
588 458
            attrs.actions = _.clone(this.get("actions").actions);
589 459
            return attrs;
590 460
        },
461
        
462
        set_state: function(val) {
463
            if (val == "PENDING" && this.get("state") == "DESTORY") {
464
                return "DESTROY";
465
            }
466
            return val;
467
        },
591 468

  
592 469
        update_state: function() {
593
            if (this.vms.pending.length) {
470
            if (this.get("connecting") > 0) {
594 471
                this.set({state: "CONNECTING"});
595 472
                return
596 473
            }
597

  
598
            if (this.vms.pending_for_removal.length) {
474
            
475
            if (this.get_nics(function(nic){ return nic.get("removing") == 1}).length > 0) {
599 476
                this.set({state: "DISCONNECTING"});
600 477
                return
601 478
            }   
602 479
            
603
            var firewalling = false;
604
            _.each(this.vms.get(), _.bind(function(vm_id){
605
                var vm = storage.vms.get(vm_id);
606
                if (!vm) { return };
607
                if (!_.isEmpty(vm.pending_firewalls)) {
608
                    this.set({state:"FIREWALLING"});
609
                    firewalling = true;
610
                    return false;
611
                }
612
            },this));
613
            if (firewalling) { return };
480
            if (this.contains_firewalling_nics() > 0) {
481
                this.set({state: "FIREWALLING"});
482
                return
483
            }   
484
            
485
            if (this.get("state") == "DESTROY") { 
486
                this.set({"destroyed":1});
487
            }
488
            
489
            this.set({state:this.get('status')});
490
        },
614 491

  
615
            this.set({state:"NORMAL"});
492
        is_public: function() {
493
            return this.id === "public";
616 494
        },
617 495

  
618
        handle_pending_connections: function(action) {
496
        decrease_connecting: function() {
497
            var conn = this.get("connecting");
498
            if (!conn) { conn = 0 };
499
            if (conn > 0) {
500
                conn--;
501
            }
502
            this.set({"connecting": conn});
619 503
            this.update_state();
620 504
        },
621 505

  
622
        // handle vm/network connections
623
        update_connections: function(action, model) {
624
            
625
            // vm removed disconnect vm from network
626
            if (action == "remove") {
627
                var removed_from_net = this.vms.remove(model.id);
628
                var removed_from_vm = model.networks.remove(this.id);
629
                if (removed_from_net) {this.trigger("vm:disconnect", model, this); this.change()};
630
                if (removed_from_vm) {model.trigger("network:disconnect", this, model); this.change()};
631
                return;
632
            }
633
            
634
            // update links for all vms
635
            var links = this.get("linked_to");
636
            storage.vms.each(_.bind(function(vm) {
637
                var vm_links = vm.get("linked_to") || [];
638
                if (vm_links.indexOf(this.id) > -1) {
639
                    // vm has connection to current network
640
                    if (links.indexOf(vm.id) > -1) {
641
                        // and network has connection to vm, so try
642
                        // to append it
643
                        var add_to_net = this.vms.add(vm.id);
644
                        var index = _.indexOf(vm_links, this.id);
645
                        var add_to_vm = vm.networks.add(this.id, vm.get("linked_to_nets")[index]);
646
                        
647
                        // call only if connection did not existed
648
                        if (add_to_net) {this.trigger("vm:connect", vm, this); this.change()};
649
                        if (add_to_vm) {vm.trigger("network:connect", this, vm); vm.change()};
650
                    } else {
651
                        // no connection, try to remove it
652
                        var removed_from_net = this.vms.remove(vm.id);
653
                        var removed_from_vm = vm.networks.remove(this.id);
654
                        if (removed_from_net) {this.trigger("vm:disconnect", vm, this); this.change()};
655
                        if (removed_from_vm) {vm.trigger("network:disconnect", this, vm); vm.change()};
656
                    }
657
                } else {
658
                    // vm has no connection to current network, try to remove it
659
                    var removed_from_net = this.vms.remove(vm.id);
660
                    var removed_from_vm = vm.networks.remove(this.id);
661
                    if (removed_from_net) {this.trigger("vm:disconnect", vm, this); this.change()};
662
                    if (removed_from_vm) {vm.trigger("network:disconnect", this, vm); vm.change()};
663
                }
664
            },this));
506
        increase_connecting: function() {
507
            var conn = this.get("connecting");
508
            if (!conn) { conn = 0 };
509
            conn++;
510
            this.set({"connecting": conn});
511
            this.update_state();
665 512
        },
666 513

  
667
        is_public: function() {
668
            return this.id == "public";
514
        connected_to: function(vm) {
515
            return this.get('linked_to').indexOf(""+vm.id) > -1;
669 516
        },
670 517

  
671
        contains_vm: function(vm) {
672
            var net_vm_exists = this.vms.get().indexOf(vm.id) > -1;
673
            var vm_net_exists = vm.is_connected_to(this);
674
            return net_vm_exists && vm_net_exists;
518
        connected_with_nic_id: function(nic_id) {
519
            return _.keys(this.get('nics')).indexOf(nic_id) > -1;
675 520
        },
676
        
521

  
522
        get_nics: function(filter) {
523
            var nics = synnefo.storage.nics.filter(function(nic) {
524
                return nic.get('network_id') == this.id;
525
            }, this);
526

  
527
            if (filter) {
528
                return _.filter(nics, filter);
529
            }
530
            return nics;
531
        },
532

  
533
        contains_firewalling_nics: function() {
534
            return this.get_nics(function(n){return n.get('pending_firewall')}).length
535
        },
536

  
677 537
        call: function(action, params, success, error) {
678 538
            if (action == "destroy") {
679 539
                this.set({state:"DESTROY"});
680
                this.get("actions").remove("destroy");
540
                this.get("actions").remove("destroy", params);
681 541
                this.remove(_.bind(function(){
682 542
                    success();
683 543
                }, this), error);
684 544
            }
685 545
            
686 546
            if (action == "disconnect") {
687
                _.each(params, _.bind(function(vm_id) {
688
                    var vm = snf.storage.vms.get(vm_id);
689
                    this.get("actions").remove("disconnect", vm_id);
690
                    if (vm) {
691
                        this.remove_vm(vm, success, error);
547
                if (this.get("state") == "DESTROY") {
548
                    return;
549
                }
550

  
551
                _.each(params, _.bind(function(nic_id) {
552
                    var nic = snf.storage.nics.get(nic_id);
553
                    this.get("actions").remove("disconnect", nic_id);
554
                    if (nic) {
555
                        this.remove_nic(nic, success, error);
692 556
                    }
693 557
                }, this));
694 558
            }
......
700 564
            return this.api_call(this.api_path() + "/action", "create", 
701 565
                                 payload,
702 566
                                 _.bind(function(){
703
                                     this.vms.add_pending(vm.id);
567
                                     //this.vms.add_pending(vm.id);
568
                                     this.increase_connecting();
704 569
                                     if (callback) {callback()}
705 570
                                 },this), error);
706 571
        },
707 572

  
708
        remove_vm: function (vm, callback, error, options) {
709
            var payload = {remove:{serverRef:"" + vm.id}};
573
        remove_nic: function (nic, callback, error, options) {
574
            var payload = {remove:{attachment:"" + nic.get("attachment_id")}};
710 575
            payload._options = options || {};
711 576
            return this.api_call(this.api_path() + "/action", "create", 
712
                                 {remove:{serverRef:"" + vm.id}},
577
                                 payload,
713 578
                                 _.bind(function(){
714
                                     this.vms.add_pending_for_remove(vm.id);
579
                                     nic.set({"removing": 1});
580
                                     nic.get_network().update_state();
581
                                     //this.vms.add_pending_for_remove(vm.id);
715 582
                                     if (callback) {callback()}
716 583
                                 },this), error);
717 584
        },
......
730 597
        },
731 598

  
732 599
        get_connectable_vms: function() {
733
            var servers = this.vms.list();
734 600
            return storage.vms.filter(function(vm){
735
                return servers.indexOf(vm) == -1 && !vm.in_error_state();
601
                return !vm.in_error_state();
736 602
            })
737 603
        },
738 604

  
739 605
        state_message: function() {
740
            if (this.get("state") == "NORMAL" && this.is_public()) {
741
                return "Public network";
606
            if (this.get("state") == "ACTIVE" && !this.is_public()) {
607
                if (this.get("cidr") && this.get("dhcp") == true) {
608
                    return this.get("cidr");
609
                } else {
610
                    return "Private network";
611
                }
612
            }
613
            if (this.get("state") == "ACTIVE" && this.is_public()) {
614
                  return "Public network";
742 615
            }
743 616

  
744 617
            return models.Network.STATES[this.get("state")];
......
755 628
                    this.call(action, with_params, success, error);
756 629
                }, this));
757 630
            }, this));
631
            this.get("actions").reset();
758 632
        }
759 633
    });
760 634
    
761 635
    models.Network.STATES = {
762
        'NORMAL': 'Private network',
636
        'ACTIVE': 'Private network',
763 637
        'CONNECTING': 'Connecting...',
764 638
        'DISCONNECTING': 'Disconnecting...',
765 639
        'FIREWALLING': 'Firewall update...',
766
        'DESTROY': 'Destroying...'
640
        'DESTROY': 'Destroying...',
641
        'PENDING': 'Pending...',
642
        'ERROR': 'Error'
767 643
    }
768 644

  
769 645
    models.Network.STATES_TRANSITIONS = {
770
        'CONNECTING': ['NORMAL'],
771
        'DISCONNECTING': ['NORMAL'],
772
        'FIREWALLING': ['NORMAL']
646
        'CONNECTING': ['ACTIVE'],
647
        'DISCONNECTING': ['ACTIVE'],
648
        'PENDING': ['ACTIVE'],
649
        'FIREWALLING': ['ACTIVE']
773 650
    }
774 651

  
775 652
    // Virtualmachine model
......
778 655
        path: 'servers',
779 656
        has_status: true,
780 657
        initialize: function(params) {
781
            this.networks = new VMNetworksList();
782 658
            
783 659
            this.pending_firewalls = {};
784 660
            
......
807 683
            this.bind("change:progress", _.bind(this.update_building_progress, this));
808 684
            this.update_building_progress();
809 685

  
810
            this.bind("change:firewalls", _.bind(this.handle_firewall_change, this));
811
            
812 686
            // default values
813
            this.set({linked_to_nets:this.get("linked_to_nets") || []});
814
            this.set({firewalls:this.get("firewalls") || []});
815

  
816
            this.bind("change:state", _.bind(function(){if (this.state() == "DESTROY") { this.handle_destroy() }}, this))
817
        },
818

  
819
        handle_firewall_change: function() {
687
            this.bind("change:state", _.bind(function(){
688
                if (this.state() == "DESTROY") { 
689
                    this.handle_destroy() 
690
                }
691
            }, this));
820 692

  
821
        },
822
        
823
        set_linked_to_nets: function(data) {
824
            this.set({"linked_to":_.map(data, function(n){ return n.id})});
825
            return data;
693
            this.bind("change:nics", _.bind(synnefo.storage.nics.update_vm_nics, synnefo.storage.nics));
826 694
        },
827 695

  
828
        is_connected_to: function(net) {
829
            return _.filter(this.networks.list(), function(n){return n.id == net.id}).length > 0;
830
        },
831
        
832 696
        status: function(st) {
833 697
            if (!st) { return this.get("status")}
834 698
            return this.set({status:st});
......
1103 967
            return models.VM.CONNECT_STATES.indexOf(this.state()) > -1;
1104 968
        },
1105 969
        
1106
        set_firewalls: function(data) {
1107
            _.each(data, _.bind(function(val, key){
1108
                if (this.pending_firewalls && this.pending_firewalls[key] && this.pending_firewalls[key] == val) {
1109
                        this.require_reboot();
1110
                        this.remove_pending_firewall(key, val);
1111
                }
1112
            }, this));
1113
            return data;
1114
        },
1115

  
1116
        remove_pending_firewall: function(net_id, value) {
1117
            if (this.pending_firewalls[net_id] == value) {
1118
                delete this.pending_firewalls[net_id];
1119
                storage.networks.get(net_id).update_state();
1120
            }
1121
        },
1122
            
1123 970
        remove_meta: function(key, complete, error) {
1124 971
            var url = this.api_path() + "/meta/" + key;
1125 972
            this.api_call(url, "delete", undefined, complete, error);
......
1139 986
            this.api_call(url, "update", payload, complete, error);
1140 987
        },
1141 988

  
1142
        set_firewall: function(net_id, value, callback, error, options) {
1143
            if (this.get("firewalls") && this.get("firewalls")[net_id] == value) { return }
1144

  
1145
            this.pending_firewalls[net_id] = value;
1146
            this.trigger("change", this, this);
1147
            var payload = {"firewallProfile":{"profile":value}};
1148
            payload._options = _.extend({critical: false}, options);
1149
            
1150
            // reset firewall state on error
1151
            var error_cb = _.bind(function() {
1152
                thi
1153
            }, this);
1154

  
1155
            this.api_call(this.api_path() + "/action", "create", payload, callback, error);
1156
            storage.networks.get(net_id).update_state();
1157
        },
1158 989

  
1159
        firewall_pending: function(net_id) {
1160
            return this.pending_firewalls[net_id] != undefined;
1161
        },
1162
        
1163 990
        // update/get the state of the machine
1164 991
        state: function() {
1165 992
            var args = slice.call(arguments);
......
1241 1068
        get_gui: function() {
1242 1069
            return this.get_meta('GUI');
1243 1070
        },
1071
        
1072
        connected_to: function(net) {
1073
            return this.get('linked_to').indexOf(net.id) > -1;
1074
        },
1244 1075

  
1245
        // get public ip addresses
1246
        // TODO: public network is always the 0 index ???
1247
        get_addresses: function(net_id) {
1248
            var net_id = net_id || "public";
1249
            
1250
            var info = this.get_network_info(net_id);
1251
            if (!info) { return {} };
1252
            addrs = {};
1253
            _.each(info.values, function(addr) {
1254
                addrs["ip" + addr.version] = addr.addr;
1255
            });
1256
            return addrs
1076
        connected_with_nic_id: function(nic_id) {
1077
            return _.keys(this.get('nics')).indexOf(nic_id) > -1;
1257 1078
        },
1258 1079

  
1259
        get_network_info: function(net_id) {
1260
            var net_id = net_id || "public";
1261
            
1262
            if (!this.networks.network_ids.length) { return {} };
1080
        get_nics: function(filter) {
1081
            ret = synnefo.storage.nics.filter(function(nic) {
1082
                return parseInt(nic.get('vm_id')) == this.id;
1083
            }, this);
1263 1084

  
1264
            var addresses = this.networks.get();
1265
            try {
1266
                return _.select(addresses, function(net, key){return key == net_id })[0];
1267
            } catch (err) {
1268
                //this.log.debug("Cannot find network {0}".format(net_id))
1085
            if (filter) {
1086
                return _.filter(ret, filter);
1269 1087
            }
1088

  
1089
            return ret;
1090
        },
1091

  
1092
        get_net_nics: function(net_id) {
1093
            return this.get_nics(function(n){return n.get('network_id') == net_id});
1270 1094
        },
1271 1095

  
1272
        firewall_profile: function(net_id) {
1273
            var net_id = net_id || "public";
1274
            var firewalls = this.get("firewalls");
1275
            return firewalls[net_id];
1096
        get_public_nic: function() {
1097
            return this.get_nics(function(n){ return n.get('network_id') == 'public'})[0];
1276 1098
        },
1277 1099

  
1278
        has_firewall: function(net_id) {
1279
            var net_id = net_id || "public";
1280
            return ["ENABLED","PROTECTED"].indexOf(this.firewall_profile()) > -1;
1100
        get_nic: function(net_id) {
1101
        },
1102

  
1103
        has_firewall: function() {
1104
            var nic = this.get_public_nic();
1105
            if (nic) {
1106
                var profile = nic.get('firewallProfile'); 
1107
                return ['ENABLED', 'PROTECTED'].indexOf(profile) > -1;
1108
            }
1109
            return false;
1110
        },
1111

  
1112
        get_firewall_profile: function() {
1113
            var nic = this.get_public_nic();
1114
            if (nic) {
1115
                return nic.get('firewallProfile');
1116
            }
1117
            return null;
1118
        },
1119

  
1120
        get_addresses: function() {
1121
            var pnic = this.get_public_nic();
1122
            if (!pnic) { return {'ip4': undefined, 'ip6': undefined }};
1123
            return {'ip4': pnic.get('ipv4'), 'ip6': pnic.get('ipv6')};
1281 1124
        },
1282 1125
    
1283 1126
        // get actions that the user can execute
......
1540 1383
        path: 'networks',
1541 1384
        details: true,
1542 1385
        //noUpdate: true,
1543
        defaults: {'linked_to':[]},
1544

  
1386
        defaults: {'nics':[],'linked_to':[]},
1387
        
1545 1388
        parse: function (resp, xhr) {
1546 1389
            // FIXME: depricated global var
1547 1390
            if (!resp) { return []};
......
1550 1393
            return data;
1551 1394
        },
1552 1395

  
1396
        add: function() {
1397
            ret = models.Networks.__super__.add.apply(this, arguments);
1398
            // update nics after each network addition
1399
            ret.each(function(r){
1400
                synnefo.storage.nics.update_net_nics(r);
1401
            });
1402
        },
1403

  
1553 1404
        reset_pending_actions: function() {
1554 1405
            this.each(function(net) {
1555 1406
                net.get("actions").reset();
1556
            })
1407
            });
1557 1408
        },
1558 1409

  
1559 1410
        do_all_pending_actions: function() {
......
1563 1414
        },
1564 1415

  
1565 1416
        parse_net_api_data: function(data) {
1566
            if (data.servers && data.servers.values) {
1567
                data['linked_to'] = data.servers.values;
1417
            // append nic metadata
1418
            // net.get('nics') contains a list of vm/index objects 
1419
            // e.g. {'vm_id':12231, 'index':1}
1420
            // net.get('linked_to') contains a list of vms the network is 
1421
            // connected to e.g. [1001, 1002]
1422
            if (data.attachments && data.attachments.values) {
1423
                data['nics'] = {};
1424
                data['linked_to'] = [];
1425
                _.each(data.attachments.values, function(nic_id){
1426
                  
1427
                  var vm_id = NIC_REGEX.exec(nic_id)[1];
1428
                  var nic_index = parseInt(NIC_REGEX.exec(nic_id)[2]);
1429

  
1430
                  if (vm_id !== undefined && nic_index !== undefined) {
1431
                      data['nics'][nic_id] = {
1432
                          'vm_id': vm_id, 
1433
                          'index': nic_index, 
1434
                          'id': nic_id
1435
                      };
1436
                      if (data['linked_to'].indexOf(vm_id) == -1) {
1437
                        data['linked_to'].push(vm_id);
1438
                      }
1439
                  }
1440
                });
1568 1441
            }
1569 1442
            return data;
1570 1443
        },
1571 1444

  
1572
        create: function (name, callback) {
1573
            return this.api_call(this.path, "create", {network:{name:name}}, callback);
1445
        create: function (name, type, cidr, dhcp, callback) {
1446
            var params = {
1447
                network:{
1448
                    name:name
1449
                }
1450
            };
1451

  
1452
            if (type) {
1453
                params.network.type = type;
1454
            }
1455
            if (cidr) {
1456
                params.network.cidr = cidr;
1457
            }
1458
            if (dhcp) {
1459
                params.network.dhcp = dhcp;
1460
            }
1461

  
1462
            if (dhcp === false) {
1463
                params.network.dhcp = false;
1464
            }
1465
            
1466
            return this.api_call(this.path, "create", params, callback);
1574 1467
        }
1575 1468
    })
1576 1469

  
......
1588 1481
        // api url
1589 1482
        update_unknown_id: function(id, callback) {
1590 1483
            var url = getUrl.call(this) + "/" + id;
1591
            this.api_call(this.path + "/" + id, this.read_method, {_options:{async:true, skip_api_error:true}}, undefined, 
1484
            this.api_call(this.path + "/" + id, this.read_method, {
1485
              _options:{
1486
                async:true, 
1487
                skip_api_error:true}
1488
              }, undefined, 
1592 1489
            _.bind(function() {
1593 1490
                if (!this.get(id)) {
1594 1491
		            if (this.fallback_service) {
......
1783 1680
        path: 'servers',
1784 1681
        details: true,
1785 1682
        copy_image_meta: true,
1786
        
1683

  
1787 1684
        parse: function (resp, xhr) {
1788 1685
            // FIXME: depricated after refactoring
1789 1686
            var data = resp;
......
1791 1688
            data = _.filter(_.map(resp.servers.values, _.bind(this.parse_vm_api_data, this)), function(v){return v});
1792 1689
            return data;
1793 1690
        },
1691

  
1692
        add: function() {
1693
            ret = models.VMS.__super__.add.apply(this, arguments);
1694
            ret.each(function(r){
1695
                synnefo.storage.nics.update_vm_nics(r);
1696
            });
1697
        },
1794 1698
        
1795 1699
        get_reboot_required: function() {
1796 1700
            return this.filter(function(vm){return vm.get("reboot_required") == true})
......
1860 1764
                data['OS'] = data.metadata.values.OS || "okeanos";
1861 1765
            }
1862 1766
            
1767

  
1768
            // network metadata
1863 1769
            data['firewalls'] = {};
1864
            if (data['addresses'] && data['addresses'].values) {
1865
                data['linked_to_nets'] = data['addresses'].values;
1866
                _.each(data['addresses'].values, function(f){
1867
                    if (f['firewallProfile']) {
1868
                        data['firewalls'][f['id']] = f['firewallProfile']
1770
            data['nics'] = {};
1771
            data['linked_to'] = [];
1772

  
1773
            if (data['attachments'] && data['attachments'].values) {
1774
                var nics = data['attachments'].values;
1775
                _.each(nics, function(nic) {
1776
                    var net_id = nic.network_id;
1777
                    var index = parseInt(NIC_REGEX.exec(nic.id)[2]);
1778
                    if (data['linked_to'].indexOf(net_id) == -1) {
1779
                        data['linked_to'].push(net_id);
1869 1780
                    }
1870
                });
1781

  
1782
                    data['nics'][nic.id] = nic;
1783
                })
1871 1784
            }
1872 1785
            
1873 1786
            // if vm has no metadata, no metadata object
......
1894 1807
        }
1895 1808

  
1896 1809
    })
1810
    
1811
    models.NIC = models.Model.extend({
1812
        
1813
        initialize: function() {
1814
            models.NIC.__super__.initialize.apply(this, arguments);
1815
            this.pending_for_firewall = false;
1816
            this.bind("change:firewallProfile", _.bind(this.check_firewall, this));
1817
            this.bind("change:pending_firewall", function(nic) {
1818
                nic.get_network().update_state();
1819
            });
1820
            this.get_vm().bind("remove", function(){
1821
                this.collection.remove(this);
1822
            }, this);
1823
            this.get_network().bind("remove", function(){
1824
                try {
1825
                    this.collection.remove(this);
1826
                } catch (err) {};
1827
            }, this);
1828
        },
1829

  
1830
        get_vm: function() {
1831
            return synnefo.storage.vms.get(parseInt(this.get('vm_id')));
1832
        },
1833

  
1834
        get_network: function() {
1835
            return synnefo.storage.networks.get(this.get('network_id'));
1836
        },
1837

  
1838
        get_v6_address: function() {
1839
            return this.get("ipv6");
1840
        },
1841

  
1842
        get_v4_address: function() {
1843
            return this.get("ipv4");
1844
        },
1845

  
1846
        set_firewall: function(value, callback, error, options) {
1847
            var net_id = this.get('network_id');
1848
            var self = this;
1849

  
1850
            // api call data
1851
            var payload = {"firewallProfile":{"profile":value}};
1852
            payload._options = _.extend({critical: false}, options);
1853
            
1854
            this.set({'pending_firewall': value});
1855
            this.set({'pending_firewall_sending': true});
1856

  
1857
            var success_cb = function() {
1858
                if (callback) {
1859
                    callback();
1860
                }
1861
                self.set({'pending_firewall_sending': false});
1862
            };
1863

  
1864
            var error_cb = function() {
1865
                self.reset_pending_firewall();
1866
            }
1867
            
1868
            this.get_vm().api_call(this.get_vm().api_path() + "/action", "create", payload, success_cb, error_cb);
1869
        },
1870

  
1871
        reset_pending_firewall: function() {
1872
            this.set({'pending_firewall': false});
1873
        },
1874

  
1875
        check_firewall: function() {
1876
            var firewall = this.get('firewallProfile');
1877
            var pending = this.get('pending_firewall');
1878
            this.reset_pending_firewall();
1879
        }
1880
        
1881
    });
1882

  
1883
    models.NICs = models.Collection.extend({
1884
        model: models.NIC,
1885
        
1886
        add_or_update: function(nic_id, data, vm) {
1887
            var params = _.clone(data);
1888
            params.attachment_id = params.id;
1889
            params.id = params.id + '-' + params.network_id;
1890
            params.vm_id = parseInt(NIC_REGEX.exec(nic_id)[1]);
1891

  
1892
            if (!this.get(params.id)) {
1893
                this.add(params);
1894
                var nic = this.get(params.id);
1895
                nic.get_network().decrease_connecting();
1896
                nic.bind("remove", function() {
1897
                    nic.set({"removing": 0});
1898
                    if (this.get_network()) {
1899
                        // network might got removed before nic
1900
                        nic.get_network().update_state();
1901
                    }
1902
                })
1903
            } else {
1904
                this.get(params.id).set(params);
1905
            }
1906
        },
1907
        
1908
        reset_nics: function(nics, filter_attr, filter_val) {
1909
            var nics_to_check = this.filter(function(nic) {
1910
                return nic.get(filter_attr) == filter_val;
1911
            });
1912
            
1913
            _.each(nics_to_check, function(nic) {
1914
                if (nics.indexOf(nic.get('id')) == -1) {
1915
                    this.remove(nic);
1916
                } else {
1917
                }
1918
            }, this);
1919
        },
1920

  
1921
        update_vm_nics: function(vm) {
1922
            var nics = vm.get('nics');
1923
            this.reset_nics(_.map(nics, function(nic, key){
1924
                return key + "-" + nic.network_id;
1925
            }), 'vm_id', vm.id);
1926

  
1927
            _.each(nics, function(val, key) {
1928
                var net = synnefo.storage.networks.get(val.network_id);
1929
                if (net && net.connected_with_nic_id(key) && vm.connected_with_nic_id(key)) {
1930
                    this.add_or_update(key, vm.get('nics')[key], vm);
1931
                }
1932
            }, this);
1933
        },
1934

  
1935
        update_net_nics: function(net) {
1936
            var nics = net.get('nics');
1937
            this.reset_nics(_.map(nics, function(nic, key){
1938
                return key + "-" + net.get('id');
1939
            }), 'network_id', net.id);
1940

  
1941
            _.each(nics, function(val, key) {
1942
                var vm = synnefo.storage.vms.get(val.vm_id);
1943
                if (vm && net.connected_with_nic_id(key) && vm.connected_with_nic_id(key)) {
1944
                    this.add_or_update(key, vm.get('nics')[key], vm);
1945
                }
1946
            }, this);
1947
        }
1948
    });
1897 1949

  
1898 1950
    models.PublicKey = models.Model.extend({
1899 1951
        path: 'keys',
......
1967 2019
    snf.storage.networks = new models.Networks();
1968 2020
    snf.storage.vms = new models.VMS();
1969 2021
    snf.storage.keys = new models.PublicKeys();
2022
    snf.storage.nics = new models.NICs();
1970 2023

  
1971 2024
    //snf.storage.vms.fetch({update:true});
1972 2025
    //snf.storage.images.fetch({update:true});
b/snf-cyclades-app/synnefo/ui/static/snf/js/ui/web/ui_networks_view.js
109 109
            }
110 110

  
111 111
            _.each(this.vms, _.bind(function(vm){
112
                
112 113
                var html = '<li class="vm option options-object vm-{0}">' +
113 114
                           '<div class="options-object-cont">' +
114 115
                           '{2}' + 
......
120 121
                                       snf.ui.helpers.vm_icon_tag(vm, "small", {'class':'os'}),
121 122
                                       _.escape(vm.get_os())
122 123
                                      ))
123
                el.data({vm:vm,vm_id:vm.id})
124
                el.data({vm:vm, vm_id:vm.id})
124 125
                this.list.append(el);
125 126

  
126 127
                vm.bind("remove", function(){ el.remove()})
......
142 143
            this.reset();
143 144
            this.set_subtitle(network.escape("name"));
144 145
            this.vms = vms;
146
            if (!synnefo.config.network_allow_duplicate_vm_nics) {
147
                this.vms = _.filter(this.vms, function(vm) {
148
                    return !vm.connected_to(this.network);
149
                }, this);
150
            }
151

  
145 152
            this.selected = selected;
146 153
            this.cb = callback;
147 154
            this.show();
......
194 201
            this.create_button = this.$("form .form-action.create");
195 202
            this.text = this.$(".network-create-name");
196 203
            this.form = this.$("form");
204

  
205
            this.dhcp_select = this.$("#network-create-dhcp");
206
            this.type_select = this.$("#network-create-type");
207
            this.subnet_select = this.$("#network-create-subnet");
208
            this.subnet_custom = this.$("#network-create-subnet-custom");
209
                
210
            this.dhcp_form = this.$("#network-create-dhcp-fields");
211
            
212
            this.subnet_select.find(".subnet").remove();
213
            _.each(synnefo.config.network_suggested_subnets, function(subnet){
214
                this.subnet_select.append($('<option value='+subnet+' class="subnet">'+subnet+'</option>'));
215
            }, this);
216

  
217
            this.type_select.find(".subnet").remove();
218
            _.each(synnefo.config.network_available_types, function(name, value){
219
                this.type_select.append($('<option value='+value+' class="subnet">'+name+'</option>'));
220
            }, this);
221
            
222
            this.disable_network_type = false;
223
            if (_.keys(synnefo.config.network_available_types).length <= 1) {
224
                this.disable_network_type = true;
225
                this.type_select.closest(".form-field").hide();
226
            }
227

  
228
            this.check_dhcp_form();
197 229
            this.init_handlers();
198 230
        },
199 231

  
232
        check_dhcp_form: function() {
233
            if (this.dhcp_select.is(":checked")) {
234
                this.dhcp_form.show();
235
            } else {
236
                this.dhcp_form.hide();
237
            }
238
            
239
            if (this.subnet_select.val() == "custom") {
240
                this.subnet_custom.show();
241
            } else {
242
                this.subnet_custom.hide();
243
            }
244
        },
245

  
200 246
        init_handlers: function() {
247

  
248
            this.dhcp_select.click(_.bind(function(e){
249
                this.check_dhcp_form();
250
            }, this));
251

  
252
            this.subnet_select.change(_.bind(function(e){
253
                this.check_dhcp_form();
254
                if (this.subnet_custom.is(":visible")) {
255
                    this.subnet_custom.focus();
256
                }
257
            }, this));
258

  
201 259
            this.create_button.click(_.bind(function(e){
202 260
                this.submit();
203 261
            }, this));
......
230 288
                this.text.focus();
231 289
                return false;
232 290
            } else {
233
                return true;
291
                this.text.closest(".form-field").removeClass("error");
234 292
            }
293
            
294
            if (this.dhcp_select.is(":checked")) {
295
                if (this.subnet_select.val() == "custom") {
296
                    var sub = this.subnet_custom.val();
297
                    sub = sub.replace(/^\s+|\s+$/g,"");
298
                    this.subnet_custom.val(sub);
299
                        
300
                    if (!synnefo.util.IP_REGEX.exec(this.subnet_custom.val())) {
301
                        this.subnet_custom.closest(".form-field").prev().addClass("error");
302
                        return false;
303
                    } else {
304
                        this.subnet_custom.closest(".form-field").prev().removeClass("error");
305
                    }
306
                };
307
            }
308

  
309
            return true;
235 310
        },
236 311

  
237 312
        create: function() {
238 313
            this.create_button.addClass("in-progress");
239
            snf.storage.networks.create(this.text.val(), _.bind(function(){
314

  
315
            var name = this.text.val();
316
            var dhcp = this.dhcp_select.is(":checked");
317
            var subnet = null;
318
            var type = this.type_select.val();
319

  
320
            if (this.disable_network_type) { type = null };
321

  
322
            if (dhcp) {
323
                if (this.subnet_select.val() == "custom") {
324
                    subnet = this.subnet_custom.val();
325
                } else if (this.subnet_select.val() == "auto") {
326
                    subnet = null;
327
                } else {
328
                    subnet = this.subnet_select.val();
329
                }
330
                
331
            }
332

  
333
            snf.storage.networks.create(name, type, subnet, dhcp, _.bind(function(){
240 334
                this.hide();
241 335
            }, this));
242 336
        },
......
247 341
            this.text.val("");
248 342
            this.text.show();
249 343
            this.text.focus();
344
            this.subnet_custom.val("");
345
            this.subnet_select.val("auto");
346
            this.dhcp_select.attr("checked", true);
347
            this.type_select.val(_.keys(synnefo.config.network_available_types)[0]);
348
            this.check_dhcp_form();
250 349
        },
251 350

  
252 351
        onOpen: function() {
......
254 353
        }
255 354
    });
256 355

  
257
    views.NetworkVMView = views.View.extend({
356
    views.NetworkNICView = views.View.extend({
258 357

  
259
        initialize: function(vm, parent, firewall_controls, el) {
358
        initialize: function(nic, parent, firewall_controls, el) {
260 359
            this.firewall_controls = firewall_controls || false;
261
            this.vm = vm;
360
            this.nic = nic;
361
            this.vm = nic.get_vm();
262 362
            // parent view di
263 363
            this.parent = parent;
264 364
            // TODO make it better
265
            this.el = el || this.parent.vm(vm);
365
            this.el = el || this.parent.get_nic_view(nic);
266 366

  
267 367
            this.init_layout();
268 368
            this.update_layout();
......
279 379
            
280 380
            this.firewall_view = undefined;
281 381
            if (this.firewall_controls) {
282
                this.firewall_view = new views.FirewallEditView(this.vm, this.parent.network, this);
382
                this.firewall_view = new views.FirewallEditView(this.nic, this.parent.network, this);
283 383
            }
284 384

  
285 385
        },
286 386
        
387
        reset_all_net_actions: function(act_types) {
388
            synnefo.storage.networks.each(function(n){
389
                var actions = n.get('actions');
390
                _.each(act_types, function(type){
391
                    actions.remove_all(type);
392
                })
393
            })
394
        },
395

  
287 396
        init_handlers: function() {
288 397
            if (!this.parent.network.is_public()) {
289 398
                this.disconnect.click(_.bind(function(e){
290 399
                    e.preventDefault();
291
                    this.parent.network.get("actions").add("disconnect", this.vm.id);
400
                    this.reset_all_net_actions(['destroy','disconnect']);
401
                    this.parent.network.get("actions").remove_all("disconnect");
402
                    this.parent.network.get("actions").add("disconnect", this.nic.id);
292 403
                    this.parent.network.get("actions").remove("destroy");
293 404
                }, this));
294 405
                this.cancel.click(_.bind(function(e){
295
                    this.parent.network.get("actions").remove("disconnect", this.vm.id);
406
                    this.parent.network.get("actions").remove("disconnect", this.nic.id);
296 407
                    e.preventDefault()
297 408
                }, this));
409

  
298 410
                this.confirm.click(_.bind(function(e){
299 411
                    e.preventDefault()
300
                    this.disconnect_vm();
412
                    this.disconnect_nic();
301 413
                    this.confirm_el.hide();
302 414
                    this.disconnect.removeClass("selected");
303 415
                }, this));
......
309 421
                }, this));
310 422

  
311 423
                this.$(".remove-icon").click(_.bind(function(){
312
                    this.parent.network.get("actions").add("disconnect", this.vm.id);
424
                    this.reset_all_net_actions(['destroy','disconnect']);
425
                    this.parent.network.get("actions").remove_all("disconnect");
426
                    this.parent.network.get("actions").add("disconnect", this.nic.id);
313 427
                    this.parent.network.get("actions").remove("destroy");
314 428
                }, this));
315 429

  
......
318 432
                }, this));
319 433
                
320 434
                this.parent.network.bind("change:actions", _.bind(function(model, action){
321
                    if (this.parent.network.get("actions").contains("disconnect", this.vm.id)) {
435
                    if (this.parent.network.get("actions").contains("disconnect", this.nic.id)) {
322 436
                        this.confirm_disconnect();
323 437
                    } else {
324 438
                        this.cancel_disconnect();
......
327 441
            }
328 442
            
329 443
            var vm = this.vm;
330
            this.details.click(function(){
444
            this.details.click(function(e){
445
                e.preventDefault();
331 446
                snf.ui.main.show_vm_details(vm);
332 447
            });
333 448

  
......
354 469
            this.$("img.logo").attr("src", ui.helpers.vm_icon_path(this.vm, "medium"));
355 470

  
356 471
            if (this.firewall_view) {
357
                this.$(".ipv4-text").text(this.vm.get_addresses().ip4);
358
                this.$(".ipv6-text").text(this.vm.get_addresses().ip6);
472
                this.$(".ipv4-text").text(this.nic.get_v4_address());
473
                this.$(".ipv6-text").text(this.nic.get_v6_address());
359 474
            }
360 475

  
361 476
            if (this.firewall_view) {
362 477
                this.firewall_view.update_layout();
363 478
            }
479

  
480
            if (!this.firewall_view) {
481
                this.$(".ip4-container").hide();
482
                this.$(".ip6-container").hide();
483
                
484
                if (this.nic.get("ipv4")) {
485
                    this.$(".ipv4-text").text(this.nic.get_v4_address());
486
                    this.$(".ip4-container").show();
487
                    this.$(".machine-connect .content").hide();
488
                } else if (this.nic.get("ipv6")) {
489
                    this.$(".ipv6-text").text(this.nic.get_v6_address());
490
                    this.$(".ip6-container").show();
491
                    this.$(".machine-connect .content").hide();
492
                } else {
493
                    this.$(".machine-connect .content").show();
494
                }
495
            } else {
496
            }
364 497
        },
365 498

  
366
        disconnect_vm: function() {
499
        disconnect_nic: function() {
367 500
            this.$("a.selected").removeClass("selected");
368
            this.parent.network.remove_vm(this.vm);
501
            this.parent.network.remove_nic(this.nic);
369 502
        },
370

  
371
        update_firewall_layout: function() {
372
        }
373

  
374

  
375 503
    })
376 504

  
377 505
    views.NetworkModelRenameView = views.View.extend({
......
448 576
    })
449 577

  
450 578
    views.FirewallEditView = views.View.extend({
451
        initialize: function(vm, network, parent) {
579
        initialize: function(nic, network, parent) {
452 580
            this.parent = parent;
453
            this.vm = vm;
581
            this.vm = nic.get_vm();
582
            this.nic = nic;
454 583
            this.network = network;
455 584
            this.el = this.parent.el;
456 585

  
......
467 596

  
468 597
            this.$(".firewall-content").hide();
469 598
            this.$(".firewall-content input[type=radio]").attr("name", "firewall-opt-for-{0}".format(this.vm.id))
470
            var mode = this.vm.firewall_profile(this.network.id);
599
            var mode = this.vm.get_firewall_profile();
471 600
            this.$(".firewall-content input[value={0}]".format(mode)).attr("checked", true);
472 601

  
473 602
            this.init_handlers();
474 603
            this.update_layout();
604

  
605
            var self = this;
606
            this.nic.bind("change:pending_firewall_sending", function(nic, value) {
607
                if (value) {
608
                    self.apply.addClass("in-progress");       
609
                    self.progress.show();
610
                } else {
611
                    self.apply.removeClass("in-progress");       
612
                    self.progress.hide();
613
                    self.toggler.click();
614
                }
615
            });
616

  
617
            this.nic.bind("change:firewallProfile", function(nic){
618
                self.update_layout();
619
                self.reset_value();
620
            })
621

  
475 622
        },
476 623
        
477 624
        _get_selected: function() {
......
485 632
        },
486 633

  
487 634
        reset_value: function() {
488
            this.inputs.filter("[value={0}]".format(this.vm.firewall_profile(this.network.id))).attr("checked");
635
            this.inputs.filter("[value={0}]".format(
636
              this.nic.get('firewallProfile'))).attr("checked", true);
489 637
        },
490 638

  
491 639
        init_handlers: function() {
......
502 650
            }, this))
503 651
            
504 652
            this.apply.click(_.bind(function(){
505
                this.apply.addClass("in-progress");
506
                
507
                // make the api call
508
                this.vm.set_firewall(this.network.id, this.value(), 
509
                // complete
510
                _.bind(function() {
511
                    // complete callback
512
                    this.apply.removeClass("in-progress");
513
                }, this), 
514
                // error
515
                _.bind(function(){
516
                    this.vm.remove_pending_firewall(this.network.id, this.value());
517
                }, this));
518
                this.hide_firewall();
653
                this.nic.set_firewall(this.value());
519 654
            }, this))
520 655

  
521 656
            this.inputs.change(_.bind(function(){
......
549 684
        },
550 685

  
551 686
        update_layout: function() {
552
            if (this.value() == this.vm.firewall_profile(this.network.id)) {
687
            if (this.value() == this.vm.get_firewall_profile()) {
553 688
                this.apply.hide();
554 689
            } else {
555 690
                this.apply.show();
556 691
            }
557 692

  
558
            profile = this.vm.firewall_profile(this.network.id);
693
            var profile = this.vm.get_firewall_profile();
559 694
            if (this.vm.has_firewall(this.network.id)) {
560 695
                this.$(".firewall-toggle .label span").text("On");
561 696
                this.$(".firewall-toggle .label span").removeClass("firewall-off");
......
567 702
            }
568 703
            
569 704
            this.$("span.checkbox-legends").removeClass("current");
570
            this.inputs.filter("[value={0}]".format(this.vm.firewall_profile(this.network.id))).next().addClass("current");
571

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff