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