Revision eae0a59a

b/db/models.py
424 424
            raise VirtualMachine.InvalidActionError(action)
425 425

  
426 426
        # No actions to deleted and no actions beside destroy to suspended vms
427
        if self.deleted or (self.suspended and action not in ["START", "DESTROY"]):
427
        if self.deleted:
428 428
            raise VirtualMachine.InvalidActionError(action)
429 429

  
430 430
        self._action = action
b/ui/static/main.css
558 558
    background-color:#dcdcdc;
559 559
}
560 560

  
561
.machine img {
561
.standard .machine img {
562 562
    float: left;
563 563
    margin: 7px 14px 0;
564 564
}
565 565

  
566
.list .machine img {
567
    margin: 0;
568
}
569

  
566 570
div.ip, div.state {
567 571
    font-size: 9pt;
568 572
    color: #3d3d3d;
b/ui/static/synnefo.js
72 72
    if (serverIDs.length == 1){
73 73
        $("#yes-no h3").text('You are about to ' + action_string + ' vm ' + serverNames[0]);
74 74
    } else if (serverIDs.length > 1){
75
        $("#yes-no h3").text('You are about to ' + action_string + ' ' + serverIDs.length + 'machines');
75
        $("#yes-no h3").text('You are about to ' + action_string + ' ' + serverIDs.length + ' machines');
76 76
    } else {
77 77
        return false;
78 78
    }
......
104 104
    return false;
105 105
}
106 106

  
107
function auto_update_vms(interval) {
108
	update_vms();
109
	setTimeout(auto_update_vms,interval,interval);
110
}
111

  
107 112
// get and show a list of running and terminated machines
108 113
function update_vms() {
109 114
    try{ console.info('updating machines'); } catch(err){}
110
    $(".running").text('');
111
    $(".terminated").text('');
112 115

  
113 116
    $.ajax({
114 117
        url: '/api/v1.0/servers/detail',
......
120 123
                    return false;
121 124
                    },
122 125
        success: function(data, textStatus, jqXHR) {
123
            if ($(".running a.name").length + $(".terminated a.name").length == 0) {
124
            
125
                $.each(data.servers, function(i,server){
126
                    // if the machine is deleted it should not be included in any list
127
                    if (server.status == 'DELETED') {
128
                        return;
129
                    }
130
                    var machine = $("#machine-template").clone().attr("id", server.id).fadeIn("slow");
131
                    machine.find("input[type='checkbox']").attr("id", "input-" + server.id);
132
                    machine.find("input[type='checkbox']").attr("class", server.status);
133
                    machine.find("a.name span.name").text(server.name);
134
                    machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'.png');
135
                    machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'.png');
136
                    machine.find("img.list-logo").attr("title",image_tags[server.imageId]);
137
                    machine.find("span.imagetag").text(image_tags[server.imageId]);
138
    
139
                    machine.find("a.ip span.public").text(String(server.addresses.public.ip.addr).replace(',',' '));            
140
    
141
                    // TODO: handle SHARE_IP, SHARE_IP_NO_CONFIG, DELETE_IP, REBUILD, QUEUE_RESIZE, PREP_RESIZE, RESIZE, VERIFY_RESIZE, PASSWORD, RESCUE
142
                    if (server.status == 'BUILD'){
143
                        machine.find(".status").text('Building');
144
                        machine.appendTo(".running");
145
                    } else if (server.status == 'ACTIVE') {
146
                        machine.find(".status").text('Running');
147
                        machine.appendTo(".running"); 
148
                    } else if (server.status == 'REBOOT' || server.status == 'HARD_REBOOT') {
149
                        machine.find(".status").text('Rebooting');
150
                        machine.appendTo(".running");
151
                    } else if (server.status == 'STOPPED') {
152
                        machine.find(".status").text('Stopped');
153
                        machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'-off.png');
154
                        machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'-off.png');
155
                        machine.appendTo(".terminated");
156
                    } else if (server.status == 'ERROR') {
157
                        machine.find(".status").text('Error');
158
                        machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'-off.png');
159
                        machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'-off.png');
160
                        machine.appendTo(".terminated");
161
                    } 
162
                    else {
163
                        machine.find(".status").text('Unknown');
164
                        machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'-off.png');
165
                        machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'-off.png');
166
                        machine.appendTo(".terminated");
167
                    }
168
                });
169
            }
170
            $("#spinner").hide();
171
            $("div.machine:last-child").find("div.seperator").hide();
172
            // if the terminated list is populated then the seperator must be shown
173
            if ($(".terminated a.name").length > 0) {
174
                $("#mini.seperator").fadeIn("slow");
175
            }
176
            // creating the table in list view, if there are machines to show
177
            if ($("div.list table.list-machines tbody").length > 0) {
178
                $("div.list table.list-machines").dataTable({
179
                    "bInfo": false,
180
                    "bPaginate": false,
181
            		"bAutoWidth": false,
182
            		"bSort": true,    
183
                    "bStateSave": true,
184
                    "sScrollY": "270px",
185
                    "sScrollX": "515px",
186
                    "sScrollXInner": "500px",
187
                    "aoColumnDefs": [
188
                        { "bSortable": false, "aTargets": [ 0 ] }
189
                    ]
190
                });
191
                $("div.list table.list-machines").show();
192
                $("div.list div.actions").show();
193
            }
126
			update_machines_view(data);
194 127
        }
195 128
    });
196 129
    return false;
b/ui/templates/home.html
8 8
    <script src="static/jQueryRotate.js"></script>
9 9
    <script src="static/jquery.dataTables.min.js"></script>
10 10
    <script>
11
        // timeout value from settings.py
11 12
        var TIMEOUT = {{timeout}};
12
        /* These have to be here for the translations to work */
13
        var UPDATE_INTERVAL = {{60000}};
14
        var STATUS_MESSAGES = {
15
            'BUILD'     : '{% trans "Building" %}',
16
            'REBOOT'     : '{% trans "Rebooting" %}',            
17
            'STOPPED'   : '{% trans "Stopped" %}',
18
            'ACTIVE'   : '{% trans "Running" %}',
19
            'ERROR'   : '{% trans "Error" %}'
20
        };
21
        
22
        var ERRORS = {
23
            // error message header
24
            'header' : '{% trans "Error!" %}',
25
            // default
26
            'default' : '{% trans "An error has happened. Our administrators have been notified." %}',
27
            // bad request
28
            '400' : '{% trans "Malformed request." %}',
29
            // not found
30
            '404' : '{% trans "Your request has failed. Resource not found." %}',
31
            // internal server error
32
            '501' : '{% trans "There has been an Internal Error. Our administrators have been notified." %}',
33
            // service unavailable
34
            '503' : '{% trans "This service is unavailable right now, please try again later." %}'
35
        };
36
        
37
        var SUCCESS = {
38
            'header' : '{% trans "Success!" %}',
39
            'default' : '{% trans "Your request has been succefully executed." %}',
40
        };
41
        
13 42
        // ajax error checking  
14 43
        function ajax_error(jqXHR) {
15 44
            // prepare the error message
16
            $("#error-success h3").text('{% trans "Error!" %}');
17
            // check the error code
18
            switch (jqXHR.status) {
19
                case 400: // YY error/message
20
                    $("#error-success p").text('{% trans "A Bad Request has been made." %}');
21
                    break;
22
                case 404: // YY error/message
23
                    $("#error-success p").text('{% trans "Your request has failed." %}');
24
                    break;
25
                case 501: // XX error/message
26
                    $("#error-success p").text('{% trans "There has been an Internal Error. Our administrators have been notified." %}');
27
                    break;
28
                case 503: // XX error/message
29
                    $("#error-success p").text('{% trans "This service is unavailable right now, please try again later." %}');
30
                    break;
31
                default: // XXYY error/message
32
                    $("#error-success p").text('{% trans "An error has happened. Our administrators have been notified." %}');
33
            }         
45
            $("#error-success h3").text(ERRORS['header']);
46
            
47
            if (ERRORS[jqXHR.status]) {
48
                $("#error-success p").text(ERRORS[jqXHR.status]);
49
            } else {
50
                $("#error-success p").text(ERRORS['default']);   
51
            }
52
            
34 53
            // bring up error notification
35 54
            var triggers = $("a#notification").overlay({
36 55
                // some mask tweaks suitable for modal dialogs
......
53 72
        // ajax success checking
54 73
        function ajax_success() {          
55 74
            // prepare the error message
56
            $("#error-success h3").text('{% trans "Success!" %}');
57
            $("#error-success p").text('{% trans "Your request has been succefully executed." %}');             
75
            $("#error-success h3").text(SUCCESS['header']);
76
            $("#error-success p").text(SUCCESS['default']);             
58 77
            // bring up success notification
59 78
            var triggers = $("a#notification").overlay({
60 79
                // some mask tweaks suitable for modal dialogs
b/ui/templates/list.html
21 21
        <a id="action-disconnect">Disconnect from net</a>
22 22
    </div>
23 23
    <table class="list-template" style="display: none">
24
        <tr id="machine-template">
24
        <tr id="machine-template" class="machine">
25 25
            <td><input type="checkbox" id="node-id" /></td>
26 26
            <td><span class="imagetag"></span><img class="list-logo" src="" width="16" height="16" /></td>
27 27
            <td><a class="name"><span class="name">node.name</span></a></td> 
......
160 160
	return false;
161 161
});
162 162

  
163
// TODO
164
function update_machines_view(data){
165
    /*
166
    Go through the already displayed running servers and remove those not in
167
    the data or are marked as deleted.
168
    */
169
    $('.running .machine').each(function(i,entry) {
170
        var deleted = true;
171
        $.each(data.servers, function(j,server) {
172
            if (server.id == entry.id && ['BUILD','ACTIVE'].indexOf(server.status) >= 0) {
173
                deleted = false;
174
            }
175
        });
176
        if (deleted) {
177
            entry.remove();
178
        }
179
    });
180
    
181
    // Do the same for the terminated ones.
182
    $('.terminated .machine').each(function(i,entry) {
183
        var deleted = true;
184
        $.each(data.servers, function(j,server) {
185
            if (server.id == entry.id && ['STOPPED','ERROR'].indexOf(server.status) >= 0) {
186
                deleted = false;
187
            }
188
        });
189
        if (deleted) {
190
            entry.remove();
191
        }    
192
    });
193
    
194
    /* 
195
    Then go through the servers in the input data. Update existing entries, add
196
    new ones to the list
197
    */    
198
    $.each(data.servers, function(i,server){
199
        // if the machine is deleted it should not be included in any list
200
        if (server.status == 'DELETED') {
201
            return;
202
        }
203
        
204
        existing = $('#'+server.id);
205
        
206
        if (existing.length>1){
207
            existing.remove();
208
            existing = [];
209
        }
210
        
211
        
212
        if (existing.length){ // simply update the values
213
            // TODO
214
        } else { // does not exist, we should create it
215
            var machine = $("#machine-template").clone().attr("id", server.id).fadeIn("slow");
216
            machine.find("input[type='checkbox']").attr("id", "input-" + server.id);
217
            machine.find("input[type='checkbox']").attr("class", server.status);
218
            machine.find("a.name span.name").text(server.name);
219
            machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'.png');
220
            machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'.png');
221
            machine.find("img.list-logo").attr("title",image_tags[server.imageId]);
222
            machine.find("span.imagetag").text(image_tags[server.imageId]);
223
    
224
            machine.find("a.ip span.public").text(String(server.addresses.public.ip.addr).replace(',',' '));            
225
    
226
            if (server.status == 'BUILD'){
227
                machine.find(".status").text('Building');
228
                machine.appendTo(".running");
229
            } else if (server.status == 'ACTIVE') {
230
                machine.find(".status").text('Running');
231
                machine.appendTo(".running"); 
232
            } else if (server.status == 'REBOOT' || server.status == 'HARD_REBOOT') {
233
                machine.find(".status").text('Rebooting');
234
                machine.appendTo(".running");
235
            } else if (server.status == 'STOPPED') {
236
                machine.find(".status").text('Stopped');
237
                machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'-off.png');
238
                machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'-off.png');
239
                machine.appendTo(".terminated");
240
            } else if (server.status == 'ERROR') {
241
                machine.find(".status").text('Error');
242
                machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'-off.png');
243
                machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'-off.png');
244
                machine.appendTo(".terminated");
245
            } 
246
            else {
247
                machine.find(".status").text('Unknown');
248
                machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'-off.png');
249
                machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'-off.png');
250
                machine.appendTo(".terminated");
251
            }
252
        }
253
    });
254
	
255
    // creating the table in list view, if there are machines to show
256
    if ($("div.list table.list-machines tbody").length > 0) {
257
        $("div.list table.list-machines").dataTable({
258
            "bInfo": false,
259
            "bPaginate": false,
260
            "bAutoWidth": false,
261
            "bSort": true,    
262
            "bStateSave": true,
263
            "sScrollY": "270px",
264
            "sScrollX": "515px",
265
            "sScrollXInner": "500px",
266
            "aoColumnDefs": [
267
                { "bSortable": false, "aTargets": [ 0 ] }
268
            ]
269
        });
270
        $("div.list table.list-machines").show();
271
        $("div.list div.actions").show();
272
    }
273
	
274
    $("#spinner").hide();
275
    $("div.machine:last-child").find("div.seperator").hide();
276
    // if the terminated list is populated then the seperator must be shown
277
    if ($(".terminated a.name").length > 0) {
278
        $("#mini.seperator").fadeIn("slow");
279
    }	
280
}
281

  
163 282
update_vms();
164 283

  
165 284
</script>
b/ui/templates/standard.html
38 38
<div id="machines" class="seperator"></div>
39 39

  
40 40
<script>
41
    
41 42
// intercept reboot click 
42 43
$("div.actions a.action-reboot").live('click', function(){
43 44
    var serverID = $(this).parent().parent().attr("id");
......
53 54
    confirm_action('shutdown', shutdown, [serverID], [serverName]);
54 55
    return false;
55 56
});
57

  
56 58
// intercept start click
57 59
$("div.actions a.action-start").live('click', function(){ 
58 60
    var serverID = $(this).parent().parent().attr("id");
......
61 63
    return false;
62 64
});
63 65

  
64
update_vms();
66
// update the servers list
67
function update_machines_view(data){
68
    /*
69
    Go through the already displayed running servers and remove those not in
70
    the data or are marked as deleted.
71
    */
72
    $('.running .machine').each(function(i,entry) {
73
        var deleted = true;
74
        $.each(data.servers, function(j,server) {
75
            if (server.id == entry.id && ['BUILD','ACTIVE'].indexOf(server.status) >= 0) {
76
                deleted = false;
77
            }
78
        });
79
        if (deleted) {
80
            $('#'+entry.id).remove();
81
        }
82
    });
83
    
84
    // Do the same for the terminated ones.
85
    $('.terminated .machine').each(function(i,entry) {
86
        var deleted = true;
87
        $.each(data.servers, function(j,server) {
88
            if (server.id == entry.id && ['STOPPED','ERROR'].indexOf(server.status) >= 0) {
89
                deleted = false;
90
            }
91
        });
92
        if (deleted) {
93
            $('#'+entry.id).remove();
94
        }    
95
    });
96
    
97
    /* 
98
    Then go through the servers in the input data. Update existing entries, add
99
    new ones to the list
100
    */    
101
    $.each(data.servers, function(i,server){
102
        // if the machine is deleted it should not be included in any list
103
        if (server.status == 'DELETED') {
104
            return;
105
        }
106
        
107
        existing = $('#'+server.id);
108
        
109
        if (existing.length>1){
110
            existing.remove();
111
            existing = [];
112
        }
113
        
114
        
115
        if (existing.length){ 
116
            // If the machine already exists in the DOM then simply update it
117
            if (existing.find(".status").text() != STATUS_MESSAGES[server.status]) {
118
                try {console.info(existing.find("a.name span.name").text() + ' from ' + existing.find(".status").text() + ' to ' + STATUS_MESSAGES[server.status]);} catch(err) {}
119
                existing.find(".status").text(STATUS_MESSAGES[server.status]);
120
            }
121
            existing.find("a.name span.name").text(server.name);
122
            existing.find("a.ip span.public").text(String(server.addresses.public.ip.addr).replace(',',' '));
123
        } else {
124
            // If it does not exist, we should create it
125
            var machine = $("#machine-template").clone().attr("id", server.id).fadeIn("slow");
126
            machine.find("a.name span.name").text(server.name);
127
            machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'.png');
128
            machine.find("span.imagetag").text(image_tags[server.imageId]);
129
            machine.find("a.ip span.public").text(String(server.addresses.public.ip.addr).replace(',',' '));            
130
            machine.find(".status").text(STATUS_MESSAGES[server.status]);
131
            
132
            if (['BUILD', 'ACTIVE', 'REBOOT'].indexOf(server.status) >= 0){
133
                machine.appendTo(".running");
134
            } else {
135
                machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'-off.png');
136
                machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'-off.png');            
137
                machine.appendTo(".terminated");
138
            }
139

  
140
        }
141
    });
142

  
143
    $("#spinner").hide();
144
    $("div.machine:last-child").find("div.seperator").hide();
145
    // if the terminated list is populated then the seperator must be shown
146
    if ($(".terminated a.name").length > 0) {
147
        $("#mini.seperator").fadeIn("slow");
148
    }
149

  
150
}
151

  
152
auto_update_vms(UPDATE_INTERVAL);
65 153

  
66 154
</script>

Also available in: Unified diff