Statistics
| Branch: | Tag: | Revision:

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);