root / snf-cyclades-app / synnefo / ui / static / snf / js / neutron.js @ d233867a
History | View | Annotate | Download (12.2 kB)
1 |
;(function(root){
|
---|---|
2 |
// Neutron api models, collections, helpers
|
3 |
|
4 |
// root
|
5 |
var root = root;
|
6 |
|
7 |
// setup namepsaces
|
8 |
var snf = root.synnefo = root.synnefo || {};
|
9 |
var snfmodels = snf.models = snf.models || {}
|
10 |
var models = snfmodels.networks = snfmodels.networks || {};
|
11 |
var storage = snf.storage = snf.storage || {};
|
12 |
var util = snf.util = snf.util || {};
|
13 |
|
14 |
// shortcuts
|
15 |
var bb = root.Backbone;
|
16 |
var slice = Array.prototype.slice
|
17 |
|
18 |
// logging
|
19 |
var logger = new snf.logging.logger("SNF-MODELS"); |
20 |
var debug = _.bind(logger.debug, logger);
|
21 |
|
22 |
// Neutron base model, extending existing synnefo model
|
23 |
models.NetworkModel = snfmodels.Model.extend({ |
24 |
api_type: 'compute' |
25 |
}); |
26 |
|
27 |
// Neutron base collection, common neutron collection params are shared
|
28 |
models.NetworkCollection = snfmodels.Collection.extend({ |
29 |
api_type: 'compute', |
30 |
details: true, |
31 |
noUpdate: true, |
32 |
updateEntries: true |
33 |
}); |
34 |
|
35 |
// Subnet model
|
36 |
models.Subnet = models.NetworkModel.extend(); |
37 |
|
38 |
// Subnet collection
|
39 |
models.Subnets = models.NetworkCollection.extend({ |
40 |
model: models.Subnet,
|
41 |
details: false, |
42 |
path: 'subnets', |
43 |
parse: function(resp) { |
44 |
return resp.subnets
|
45 |
} |
46 |
}); |
47 |
|
48 |
// Network
|
49 |
models.Network = models.NetworkModel.extend({ |
50 |
path: 'networks', |
51 |
|
52 |
// Available network actions.
|
53 |
// connect:
|
54 |
model_actions: {
|
55 |
'connect': [['status', 'is_public'], function() { |
56 |
//TODO: Also check network status
|
57 |
return !this.is_public() && _.contains(['ACTIVE'], this.get('status')); |
58 |
}], |
59 |
'remove': [['status', 'is_public'], function() { |
60 |
//TODO: Also check network status
|
61 |
return !this.is_public() && _.contains(['ACTIVE'], this.get('status')); |
62 |
}] |
63 |
}, |
64 |
|
65 |
proxy_attrs: {
|
66 |
'is_public': [
|
67 |
['router:external', 'public'], function() { |
68 |
return this.get('router:external') || this.get('public') |
69 |
} |
70 |
], |
71 |
'cidr': [
|
72 |
['subnet'], function() { |
73 |
var subnet = this.get('subnet'); |
74 |
if (subnet && subnet.get('cidr')) { |
75 |
return subnet.get('cidr') |
76 |
} else {
|
77 |
return undefined |
78 |
} |
79 |
} |
80 |
], |
81 |
'ext_status': [
|
82 |
['status', 'cidr'], function(st) { |
83 |
if (this.get('ext_status') == 'REMOVING') { |
84 |
return 'REMOVING' |
85 |
} |
86 |
if (this.pending_connections) { |
87 |
return 'CONNECTING' |
88 |
} else if (this.pending_disconnects) { |
89 |
return 'DISCONNECTING' |
90 |
} else {
|
91 |
return this.get('status') |
92 |
} |
93 |
}], |
94 |
'in_progress': [
|
95 |
['ext_status'], function() { |
96 |
return _.contains(['CONNECTING', |
97 |
'DISCONNECTING',
|
98 |
'REMOVING'],
|
99 |
this.get('ext_status')) |
100 |
} |
101 |
] |
102 |
}, |
103 |
|
104 |
storage_attrs: {
|
105 |
'subnets': ['subnets', 'subnet', function(model, attr) { |
106 |
var subnets = model.get(attr);
|
107 |
if (subnets.length) { return subnets[0] } |
108 |
}] |
109 |
}, |
110 |
|
111 |
// call rename api
|
112 |
rename: function(new_name, cb) { |
113 |
this.sync("update", this, { |
114 |
critical: true, |
115 |
data: {
|
116 |
'network': {
|
117 |
'name': new_name
|
118 |
} |
119 |
}, |
120 |
// do the rename after the method succeeds
|
121 |
success: _.bind(function(){ |
122 |
//this.set({name: new_name});
|
123 |
snf.api.trigger("call");
|
124 |
}, this),
|
125 |
complete: cb || function() {} |
126 |
}); |
127 |
}, |
128 |
|
129 |
pending_connections: 0, |
130 |
pending_disconnects: 0, |
131 |
|
132 |
initialize: function() { |
133 |
var self = this; |
134 |
this.subnets = new Backbone.FilteredCollection(undefined, { |
135 |
collection: synnefo.storage.subnets,
|
136 |
collectionFilter: function(m) { |
137 |
return self.id == m.get('network_id') |
138 |
}}); |
139 |
models.Network.__super__.initialize.apply(this, arguments); |
140 |
this.ports = new Backbone.FilteredCollection(undefined, { |
141 |
collection: synnefo.storage.ports,
|
142 |
collectionFilter: function(m) { |
143 |
return self.id == m.get('network_id') |
144 |
} |
145 |
}); |
146 |
this.ports.network = this; |
147 |
this.ports.bind("add", function() { |
148 |
this.pending_connections--;
|
149 |
this.update_connecting_status();
|
150 |
}, this);
|
151 |
this.ports.bind("remove", function() { |
152 |
this.pending_disconnects--;
|
153 |
this.update_connecting_status();
|
154 |
}, this);
|
155 |
this.set({ports: this.ports}); |
156 |
}, |
157 |
|
158 |
update_connecting_status: function() { |
159 |
if (this.pending_connections <= 0) { |
160 |
this.pending_connections = 0; |
161 |
} |
162 |
if (this.pending_disconnects <= 0) { |
163 |
this.pending_disconnects = 0; |
164 |
} |
165 |
this.trigger('change:status', this.get('status')); |
166 |
}, |
167 |
|
168 |
get_nics: function() { |
169 |
return this.nics.models |
170 |
}, |
171 |
|
172 |
is_public: function() { |
173 |
return this.get('router:external') |
174 |
}, |
175 |
|
176 |
pluggable_vms: function() { |
177 |
var vms = synnefo.storage.vms.models;
|
178 |
// TODO: filter out vms
|
179 |
return vms;
|
180 |
}, |
181 |
|
182 |
connect_vm: function(vm, cb) { |
183 |
var self = this; |
184 |
var data = {
|
185 |
port: {
|
186 |
network_id: this.id, |
187 |
device_id: vm.id
|
188 |
} |
189 |
} |
190 |
|
191 |
this.pending_connections++;
|
192 |
this.update_connecting_status();
|
193 |
synnefo.storage.ports.create(data, {complete: cb});
|
194 |
} |
195 |
}); |
196 |
|
197 |
models.CombinedPublicNetwork = models.Network.extend({ |
198 |
defaults: {
|
199 |
'admin_state_up': true, |
200 |
'id': 'snf-combined-public-network', |
201 |
'name': 'Public', |
202 |
'status': 'ACTIVE', |
203 |
'router:external': true, |
204 |
'shared': false, |
205 |
'rename_disabled': true, |
206 |
'subnets': []
|
207 |
}, |
208 |
|
209 |
initialize: function() { |
210 |
models.Network.__super__.initialize.apply(this, arguments); |
211 |
var self = this; |
212 |
this.ports = new Backbone.FilteredCollection(undefined, { |
213 |
collection: synnefo.storage.ports,
|
214 |
collectionFilter: function(m) { |
215 |
return m.get('network') && m.get('network').get('is_public'); |
216 |
} |
217 |
}); |
218 |
this.set({ports: this.ports}); |
219 |
}, |
220 |
|
221 |
}) |
222 |
|
223 |
models.Networks = models.NetworkCollection.extend({ |
224 |
model: models.Network,
|
225 |
path: 'networks', |
226 |
details: true, |
227 |
parse: function(resp) { |
228 |
return resp.networks
|
229 |
}, |
230 |
|
231 |
get_floating_ips_network: function() { |
232 |
return this.filter(function(n) { return n.get('is_public')})[1] |
233 |
}, |
234 |
|
235 |
create: function (name, type, cidr, dhcp, callback) { |
236 |
var quota = synnefo.storage.quotas;
|
237 |
var params = { network: { name:name } }; |
238 |
if (!type) { throw "Network type cannot be empty"; } |
239 |
|
240 |
params.network.type = type; |
241 |
if (cidr) { params.network.cidr = cidr; }
|
242 |
if (dhcp) { params.network.dhcp = dhcp; }
|
243 |
if (dhcp === false) { params.network.dhcp = false; } |
244 |
|
245 |
var cb = function() { |
246 |
callback(); |
247 |
quota.get('cyclades.network.private').increase();
|
248 |
} |
249 |
return this.api_call(this.path, "create", params, cb); |
250 |
} |
251 |
}); |
252 |
|
253 |
models.Port = models.NetworkModel.extend({ |
254 |
|
255 |
path: 'ports', |
256 |
|
257 |
initialize: function() { |
258 |
models.Port.__super__.initialize.apply(this, arguments); |
259 |
this.set({'pending_firewall': null}); |
260 |
}, |
261 |
|
262 |
model_actions: {
|
263 |
'disconnect': [['status', 'network', 'vm'], function() { |
264 |
var network = this.get('network'); |
265 |
if (!network || network.is_public()) {
|
266 |
return false |
267 |
} |
268 |
var status_ok = _.contains(['DOWN', 'ACTIVE', 'CONNECTED'], |
269 |
this.get('status')); |
270 |
var vm_status_ok = this.get('vm') && !this.get('vm').get('busy'); |
271 |
return status_ok && vm_status_ok
|
272 |
}] |
273 |
}, |
274 |
|
275 |
storage_attrs: {
|
276 |
'device_id': ['vms', 'vm'], |
277 |
'network_id': ['networks', 'network'], |
278 |
}, |
279 |
|
280 |
proxy_attrs: {
|
281 |
'firewall_status': [
|
282 |
['vm'], function(vm) { |
283 |
var attachment = vm && vm.get_attachment(this.id); |
284 |
if (!attachment) { return "DISABLED" } |
285 |
return attachment.firewallProfile
|
286 |
} |
287 |
], |
288 |
|
289 |
'firewall_running': [
|
290 |
['firewall_status', 'pending_firewall'], function(status, pending) { |
291 |
var pending = this.get('pending_firewall'); |
292 |
var status = this.get('firewall_status'); |
293 |
if (!pending) { return false } |
294 |
if (status == pending) {
|
295 |
this.set({'pending_firewall': null}); |
296 |
} |
297 |
return status != pending;
|
298 |
} |
299 |
], |
300 |
}, |
301 |
|
302 |
set_firewall: function(value, callback, error, options) { |
303 |
// MOCK CALL
|
304 |
window.setTimeout(_.bind(function() {
|
305 |
var vm = this.get('vm'); |
306 |
var attachments = [];
|
307 |
attachments.push({id: this.id, firewallProfile: value}); |
308 |
vm.set({attachments: attachments});
|
309 |
}, this), 2000); |
310 |
window.setTimeout(_.bind(function() {
|
311 |
callback(); |
312 |
}), 300);
|
313 |
}, |
314 |
|
315 |
disconnect: function(cb) { |
316 |
var network = this.get('network'); |
317 |
network.pending_disconnects++; |
318 |
network.update_connecting_status(); |
319 |
this.destroy({complete: cb, silent: true}); |
320 |
} |
321 |
}); |
322 |
|
323 |
models.Ports = models.NetworkCollection.extend({ |
324 |
model: models.Port,
|
325 |
path: 'ports', |
326 |
details: true, |
327 |
noUpdate: true, |
328 |
updateEntries: true, |
329 |
|
330 |
parse: function(data) { |
331 |
return data.ports;
|
332 |
}, |
333 |
|
334 |
comparator: function(m) { |
335 |
try {
|
336 |
return parseInt(m.get('device_id')); |
337 |
} catch (err) {
|
338 |
return 0 |
339 |
} |
340 |
} |
341 |
}); |
342 |
|
343 |
models.FloatingIP = models.NetworkModel.extend({ |
344 |
path: 'floatingips', |
345 |
storage_attrs: {
|
346 |
'port_id': ['ports', 'port'], |
347 |
'floating_network_id': ['networks', 'network'], |
348 |
}, |
349 |
|
350 |
model_actions: {
|
351 |
'remove': [['status'], function() { |
352 |
var status_ok = _.contains(['DISCONNECTED'], this.get('status')) |
353 |
return status_ok
|
354 |
}], |
355 |
'connect': [['status'], function() { |
356 |
var status_ok = _.contains(['DISCONNECTED'], this.get('status')) |
357 |
return status_ok
|
358 |
}], |
359 |
'disconnect': [['status'], function() { |
360 |
var status_ok = _.contains(['CONNECTED'], this.get('status')) |
361 |
return status_ok
|
362 |
}] |
363 |
}, |
364 |
|
365 |
proxy_attrs: {
|
366 |
'ip': [
|
367 |
['floating_ip_adress'], function() { |
368 |
return this.get('floating_ip_address'); |
369 |
}], |
370 |
|
371 |
'in_progress': [
|
372 |
['status'], function() { |
373 |
return _.contains(['CONNECTING', 'DISCONNECTING', 'REMOVING'], |
374 |
this.get('status')) |
375 |
} |
376 |
], |
377 |
|
378 |
'status': [
|
379 |
['port_id', 'port'], function() { |
380 |
var val = this.get('port_id'); |
381 |
if (!val) {
|
382 |
return 'DISCONNECTED' |
383 |
} else {
|
384 |
if (this.get('port')) { |
385 |
return 'CONNECTED' |
386 |
} else {
|
387 |
return 'CONNECTING' |
388 |
} |
389 |
} |
390 |
} |
391 |
] |
392 |
}, |
393 |
|
394 |
disconnect: function(cb) { |
395 |
// MOCK
|
396 |
var self = this; |
397 |
window.setTimeout(function() {
|
398 |
cb() |
399 |
}, 2000);
|
400 |
window.setTimeout(function() {
|
401 |
self.set({port_id: undefined}); |
402 |
}, 3000);
|
403 |
} |
404 |
}); |
405 |
|
406 |
models.FloatingIPs = models.NetworkCollection.extend({ |
407 |
model: models.FloatingIP,
|
408 |
details: false, |
409 |
path: 'floatingips', |
410 |
parse: function(resp) { |
411 |
return resp.floatingips;
|
412 |
} |
413 |
}); |
414 |
|
415 |
models.Router = models.NetworkModel.extend({ |
416 |
}); |
417 |
|
418 |
models.Routers = models.NetworkCollection.extend({ |
419 |
model: models.Router,
|
420 |
path: 'routers', |
421 |
parse: function(resp) { |
422 |
return resp.routers
|
423 |
} |
424 |
}); |
425 |
|
426 |
snf.storage.floating_ips = new models.FloatingIPs();
|
427 |
snf.storage.routers = new models.Routers();
|
428 |
snf.storage.networks = new models.Networks();
|
429 |
snf.storage.ports = new models.Ports();
|
430 |
snf.storage.subnets = new models.Subnets();
|
431 |
|
432 |
})(this);
|