Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / models.js @ bfb11987

History | View | Annotate | Download (84.5 kB)

1 00469232 Kostas Papadimitriou
// Copyright 2011 GRNET S.A. All rights reserved.
2 00469232 Kostas Papadimitriou
// 
3 00469232 Kostas Papadimitriou
// Redistribution and use in source and binary forms, with or
4 00469232 Kostas Papadimitriou
// without modification, are permitted provided that the following
5 00469232 Kostas Papadimitriou
// conditions are met:
6 00469232 Kostas Papadimitriou
// 
7 00469232 Kostas Papadimitriou
//   1. Redistributions of source code must retain the above
8 00469232 Kostas Papadimitriou
//      copyright notice, this list of conditions and the following
9 00469232 Kostas Papadimitriou
//      disclaimer.
10 00469232 Kostas Papadimitriou
// 
11 00469232 Kostas Papadimitriou
//   2. Redistributions in binary form must reproduce the above
12 00469232 Kostas Papadimitriou
//      copyright notice, this list of conditions and the following
13 00469232 Kostas Papadimitriou
//      disclaimer in the documentation and/or other materials
14 00469232 Kostas Papadimitriou
//      provided with the distribution.
15 00469232 Kostas Papadimitriou
// 
16 00469232 Kostas Papadimitriou
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 00469232 Kostas Papadimitriou
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 00469232 Kostas Papadimitriou
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 00469232 Kostas Papadimitriou
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 00469232 Kostas Papadimitriou
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 00469232 Kostas Papadimitriou
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 00469232 Kostas Papadimitriou
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 00469232 Kostas Papadimitriou
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 00469232 Kostas Papadimitriou
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 00469232 Kostas Papadimitriou
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 00469232 Kostas Papadimitriou
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 00469232 Kostas Papadimitriou
// POSSIBILITY OF SUCH DAMAGE.
28 00469232 Kostas Papadimitriou
// 
29 00469232 Kostas Papadimitriou
// The views and conclusions contained in the software and
30 00469232 Kostas Papadimitriou
// documentation are those of the authors and should not be
31 00469232 Kostas Papadimitriou
// interpreted as representing official policies, either expressed
32 00469232 Kostas Papadimitriou
// or implied, of GRNET S.A.
33 00469232 Kostas Papadimitriou
// 
34 00469232 Kostas Papadimitriou
35 8d08f18a Kostas Papadimitriou
;(function(root){
36 8d08f18a Kostas Papadimitriou
    
37 8d08f18a Kostas Papadimitriou
    // root
38 8d08f18a Kostas Papadimitriou
    var root = root;
39 8d08f18a Kostas Papadimitriou
    
40 8d08f18a Kostas Papadimitriou
    // setup namepsaces
41 8d08f18a Kostas Papadimitriou
    var snf = root.synnefo = root.synnefo || {};
42 8d08f18a Kostas Papadimitriou
    var models = snf.models = snf.models || {}
43 8d08f18a Kostas Papadimitriou
    var storage = snf.storage = snf.storage || {};
44 8d08f18a Kostas Papadimitriou
    var util = snf.util = snf.util || {};
45 8d08f18a Kostas Papadimitriou
46 8d08f18a Kostas Papadimitriou
    // shortcuts
47 8d08f18a Kostas Papadimitriou
    var bb = root.Backbone;
48 8d08f18a Kostas Papadimitriou
    var slice = Array.prototype.slice
49 8d08f18a Kostas Papadimitriou
50 8d08f18a Kostas Papadimitriou
    // logging
51 8d08f18a Kostas Papadimitriou
    var logger = new snf.logging.logger("SNF-MODELS");
52 8d08f18a Kostas Papadimitriou
    var debug = _.bind(logger.debug, logger);
53 8d08f18a Kostas Papadimitriou
    
54 8d08f18a Kostas Papadimitriou
    // get url helper
55 c4fff449 Kostas Papadimitriou
    var getUrl = function(baseurl) {
56 47e34b99 Kostas Papadimitriou
        var baseurl = baseurl || snf.config.api_urls[this.api_type];
57 7f16b9b1 Kostas Papadimitriou
        var append = "/";
58 7f16b9b1 Kostas Papadimitriou
        if (baseurl.split("").reverse()[0] == "/") {
59 7f16b9b1 Kostas Papadimitriou
          append = "";
60 7f16b9b1 Kostas Papadimitriou
        }
61 7f16b9b1 Kostas Papadimitriou
        return baseurl + append + this.path;
62 8d08f18a Kostas Papadimitriou
    }
63 126a01f2 Kostas Papadimitriou
64 8d08f18a Kostas Papadimitriou
    // i18n
65 8d08f18a Kostas Papadimitriou
    BUILDING_MESSAGES = window.BUILDING_MESSAGES || {'INIT': 'init', 'COPY': '{0}, {1}, {2}', 'FINAL': 'final'};
66 8d08f18a Kostas Papadimitriou
67 8d08f18a Kostas Papadimitriou
    // Base object for all our models
68 8d08f18a Kostas Papadimitriou
    models.Model = bb.Model.extend({
69 8d08f18a Kostas Papadimitriou
        sync: snf.api.sync,
70 8d08f18a Kostas Papadimitriou
        api: snf.api,
71 47e34b99 Kostas Papadimitriou
        api_type: 'compute',
72 8d08f18a Kostas Papadimitriou
        has_status: false,
73 95ff92b4 Kostas Papadimitriou
        auto_bind: [],
74 95ff92b4 Kostas Papadimitriou
75 8d08f18a Kostas Papadimitriou
76 8d08f18a Kostas Papadimitriou
        initialize: function() {
77 95ff92b4 Kostas Papadimitriou
            var self = this;
78 95ff92b4 Kostas Papadimitriou
            
79 95ff92b4 Kostas Papadimitriou
            this._proxy_model_cache = {};
80 95ff92b4 Kostas Papadimitriou
            _.each(this.auto_bind, function(fname) {
81 95ff92b4 Kostas Papadimitriou
              self[fname] = _.bind(self[fname], self);
82 95ff92b4 Kostas Papadimitriou
            });
83 95ff92b4 Kostas Papadimitriou
84 8d08f18a Kostas Papadimitriou
            if (this.has_status) {
85 8d08f18a Kostas Papadimitriou
                this.bind("change:status", this.handle_remove);
86 8d08f18a Kostas Papadimitriou
                this.handle_remove();
87 8d08f18a Kostas Papadimitriou
            }
88 47e34b99 Kostas Papadimitriou
            
89 258235f4 Kostas Papadimitriou
            this.api_call = _.bind(this.api.call, this);
90 95ff92b4 Kostas Papadimitriou
              
91 95ff92b4 Kostas Papadimitriou
            if (this.proxy_attrs) {
92 95ff92b4 Kostas Papadimitriou
              this.init_proxy_attrs();             
93 95ff92b4 Kostas Papadimitriou
            }
94 95ff92b4 Kostas Papadimitriou
95 95ff92b4 Kostas Papadimitriou
            if (this.storage_attrs) {
96 95ff92b4 Kostas Papadimitriou
              this.init_storage_attrs();
97 95ff92b4 Kostas Papadimitriou
            }
98 95ff92b4 Kostas Papadimitriou
99 95ff92b4 Kostas Papadimitriou
            if (this.model_actions) {
100 95ff92b4 Kostas Papadimitriou
              this.init_model_actions();             
101 95ff92b4 Kostas Papadimitriou
            }
102 95ff92b4 Kostas Papadimitriou
103 df251d55 Kostas Papadimitriou
            models.Model.__super__.initialize.apply(this, arguments);
104 95ff92b4 Kostas Papadimitriou
105 95ff92b4 Kostas Papadimitriou
        },
106 95ff92b4 Kostas Papadimitriou
        
107 95ff92b4 Kostas Papadimitriou
        // Initialize model actions object
108 95ff92b4 Kostas Papadimitriou
        // For each entry in model's model_action object register the relevant 
109 95ff92b4 Kostas Papadimitriou
        // model proxy `can_<actionname>` attributes.
110 95ff92b4 Kostas Papadimitriou
        init_model_actions: function() {
111 95ff92b4 Kostas Papadimitriou
          var actions = _.keys(this.model_actions);
112 95ff92b4 Kostas Papadimitriou
          this.set({
113 95ff92b4 Kostas Papadimitriou
            "actions": new models._ActionsModel({}, {
114 95ff92b4 Kostas Papadimitriou
              actions: actions,
115 95ff92b4 Kostas Papadimitriou
              model: this
116 95ff92b4 Kostas Papadimitriou
            })
117 95ff92b4 Kostas Papadimitriou
          });
118 95ff92b4 Kostas Papadimitriou
          this.actions = this.get("actions");
119 95ff92b4 Kostas Papadimitriou
120 95ff92b4 Kostas Papadimitriou
          _.each(this.model_actions, function(params, key){
121 95ff92b4 Kostas Papadimitriou
            var attr = 'can_' + key;
122 95ff92b4 Kostas Papadimitriou
            if (params.length == 0) { return }
123 95ff92b4 Kostas Papadimitriou
            var deps = params[0];
124 95ff92b4 Kostas Papadimitriou
            var cb = _.bind(params[1], this);
125 95ff92b4 Kostas Papadimitriou
            _.each(deps, function(dep) {
126 95ff92b4 Kostas Papadimitriou
              this._set_proxy_attr(attr, dep, cb);
127 95ff92b4 Kostas Papadimitriou
            }, this);
128 95ff92b4 Kostas Papadimitriou
          }, this);
129 8d08f18a Kostas Papadimitriou
        },
130 95ff92b4 Kostas Papadimitriou
        
131 95ff92b4 Kostas Papadimitriou
        // Initialize proxy storage model attributes. These attribues allows 
132 95ff92b4 Kostas Papadimitriou
        // us to automatically access cross collection associated objects.
133 95ff92b4 Kostas Papadimitriou
        init_storage_attrs: function() {
134 95ff92b4 Kostas Papadimitriou
          _.each(this.storage_attrs, function(params, attr) {
135 95ff92b4 Kostas Papadimitriou
            var store, key, attr_name;
136 95ff92b4 Kostas Papadimitriou
            store = synnefo.storage[params[0]];
137 95ff92b4 Kostas Papadimitriou
            key = params[1];
138 31bc4729 Kostas Papadimitriou
            attr_resolver = params[2];
139 31bc4729 Kostas Papadimitriou
            if (!attr_resolver) {
140 31bc4729 Kostas Papadimitriou
              attr_resolver = function(model, attr) {
141 31bc4729 Kostas Papadimitriou
                return model.get(attr);
142 31bc4729 Kostas Papadimitriou
              }
143 31bc4729 Kostas Papadimitriou
            }
144 95ff92b4 Kostas Papadimitriou
            attr_name = attr;
145 95ff92b4 Kostas Papadimitriou
          
146 95ff92b4 Kostas Papadimitriou
            var resolve_related_instance = function(storage, attr_name, val) {
147 95ff92b4 Kostas Papadimitriou
              var data = {};
148 95ff92b4 Kostas Papadimitriou
149 95ff92b4 Kostas Papadimitriou
              if (!val) { 
150 95ff92b4 Kostas Papadimitriou
                // update with undefined and return
151 95ff92b4 Kostas Papadimitriou
                data[key] = undefined;
152 95ff92b4 Kostas Papadimitriou
                this.set(data);
153 95ff92b4 Kostas Papadimitriou
                return;
154 95ff92b4 Kostas Papadimitriou
              };
155 95ff92b4 Kostas Papadimitriou
            
156 95ff92b4 Kostas Papadimitriou
              // retrieve related object (check if its a Model??)
157 95ff92b4 Kostas Papadimitriou
              var obj = store.get(val);
158 95ff92b4 Kostas Papadimitriou
              
159 95ff92b4 Kostas Papadimitriou
              if (obj) {
160 95ff92b4 Kostas Papadimitriou
                // set related object
161 95ff92b4 Kostas Papadimitriou
                data[attr_name] = obj;
162 95ff92b4 Kostas Papadimitriou
                this.set(data, {silent:true})
163 95ff92b4 Kostas Papadimitriou
                this.trigger("change:" + attr_name, obj);
164 95ff92b4 Kostas Papadimitriou
              } else {
165 95ff92b4 Kostas Papadimitriou
                var self = this;
166 69dac1ba Kostas Papadimitriou
                var retry_to_resolve = function(store, val, key) {
167 69dac1ba Kostas Papadimitriou
                  var retries = 0;
168 69dac1ba Kostas Papadimitriou
                  var retry = window.setInterval(function(){
169 69dac1ba Kostas Papadimitriou
                    retries++;
170 69dac1ba Kostas Papadimitriou
                    if (retries > 200) {
171 69dac1ba Kostas Papadimitriou
                      clearInterval(retry);
172 69dac1ba Kostas Papadimitriou
                    }
173 69dac1ba Kostas Papadimitriou
                    var obj = store.get(val);
174 69dac1ba Kostas Papadimitriou
                    if (obj) {
175 69dac1ba Kostas Papadimitriou
                      data[key] = obj;
176 69dac1ba Kostas Papadimitriou
                      self.set(data, {silent:false});
177 69dac1ba Kostas Papadimitriou
                      clearInterval(retry);
178 69dac1ba Kostas Papadimitriou
                    }
179 69dac1ba Kostas Papadimitriou
                  }, 500);
180 69dac1ba Kostas Papadimitriou
                  return retry
181 69dac1ba Kostas Papadimitriou
                }
182 69dac1ba Kostas Papadimitriou
                retry_to_resolve(store, val, key);
183 95ff92b4 Kostas Papadimitriou
              }
184 95ff92b4 Kostas Papadimitriou
            }
185 31bc4729 Kostas Papadimitriou
            
186 31bc4729 Kostas Papadimitriou
            var self = this;
187 69dac1ba Kostas Papadimitriou
            function init_bindings(instance, store, key, attr, attr_resolver) {
188 69dac1ba Kostas Papadimitriou
              instance.bind('change:' + attr, function(model) {
189 69dac1ba Kostas Papadimitriou
                resolve_related_instance.call(model, store, key, attr_resolver(model, attr));
190 69dac1ba Kostas Papadimitriou
              }, this);
191 69dac1ba Kostas Papadimitriou
192 69dac1ba Kostas Papadimitriou
              instance.bind('add', function(model) {
193 69dac1ba Kostas Papadimitriou
                resolve_related_instance.call(model, store, key, attr_resolver(model, attr));
194 69dac1ba Kostas Papadimitriou
              }, this);
195 69dac1ba Kostas Papadimitriou
            }
196 95ff92b4 Kostas Papadimitriou
197 69dac1ba Kostas Papadimitriou
            init_bindings(this, store, key, attr, attr_resolver);
198 31bc4729 Kostas Papadimitriou
            resolve_related_instance.call(this, store, key, attr_resolver(this, attr));
199 95ff92b4 Kostas Papadimitriou
          }, this);
200 95ff92b4 Kostas Papadimitriou
        },
201 95ff92b4 Kostas Papadimitriou
        
202 95ff92b4 Kostas Papadimitriou
        _proxy_model_cache: {},
203 95ff92b4 Kostas Papadimitriou
        
204 68cc89f6 Kostas Papadimitriou
        _bind_model: function(model, attr, check_attr, cb) {
205 68cc89f6 Kostas Papadimitriou
          var proxy_cache_key = attr + '_' + check_attr;
206 68cc89f6 Kostas Papadimitriou
          if (this._proxy_model_cache[proxy_cache_key]) {
207 68cc89f6 Kostas Papadimitriou
            var proxy = this._proxy_model_cache[proxy_cache_key];
208 68cc89f6 Kostas Papadimitriou
            proxy[0].unbind('change', proxy[1]);
209 95ff92b4 Kostas Papadimitriou
          }
210 89dc40ca Kostas Papadimitriou
          var data = {};
211 68cc89f6 Kostas Papadimitriou
          var changebind = _.bind(function() {
212 68cc89f6 Kostas Papadimitriou
            data[attr] = cb.call(this, this.get(check_attr));
213 68cc89f6 Kostas Papadimitriou
            this.set(data);
214 68cc89f6 Kostas Papadimitriou
          }, this);
215 68cc89f6 Kostas Papadimitriou
          model.bind('change', changebind);
216 68cc89f6 Kostas Papadimitriou
          this._proxy_model_cache[proxy_cache_key] = [model, changebind];
217 68cc89f6 Kostas Papadimitriou
        },
218 68cc89f6 Kostas Papadimitriou
219 68cc89f6 Kostas Papadimitriou
        _bind_attr: function(attr, check_attr, cb) {
220 95ff92b4 Kostas Papadimitriou
          this.bind('change:' + check_attr, function() {
221 95ff92b4 Kostas Papadimitriou
            if (this.get(check_attr) instanceof models.Model) {
222 95ff92b4 Kostas Papadimitriou
              var model = this.get(check_attr);
223 68cc89f6 Kostas Papadimitriou
              this._bind_model(model, attr, check_attr, cb);
224 95ff92b4 Kostas Papadimitriou
            }
225 95ff92b4 Kostas Papadimitriou
            var val = cb.call(this, this.get(check_attr));
226 95ff92b4 Kostas Papadimitriou
            var data = {};
227 95ff92b4 Kostas Papadimitriou
            if (this.get(attr) !== val) {
228 95ff92b4 Kostas Papadimitriou
              data[attr] = val;
229 95ff92b4 Kostas Papadimitriou
              this.set(data);
230 95ff92b4 Kostas Papadimitriou
            }
231 95ff92b4 Kostas Papadimitriou
          }, this);
232 95ff92b4 Kostas Papadimitriou
        },
233 95ff92b4 Kostas Papadimitriou
234 68cc89f6 Kostas Papadimitriou
        _set_proxy_attr: function(attr, check_attr, cb) {
235 68cc89f6 Kostas Papadimitriou
          // initial set
236 68cc89f6 Kostas Papadimitriou
          var data = {};
237 68cc89f6 Kostas Papadimitriou
          data[attr] = cb.call(this, this.get(check_attr));
238 68cc89f6 Kostas Papadimitriou
          if (data[attr] !== undefined) {
239 68cc89f6 Kostas Papadimitriou
            this.set(data, {silent:true});
240 68cc89f6 Kostas Papadimitriou
          }
241 68cc89f6 Kostas Papadimitriou
          if(this.get(check_attr) instanceof models.Model) {
242 68cc89f6 Kostas Papadimitriou
            this._bind_model(this.get(check_attr), attr, check_attr, cb);
243 68cc89f6 Kostas Papadimitriou
          }
244 68cc89f6 Kostas Papadimitriou
          this._bind_attr(attr, check_attr, cb);
245 68cc89f6 Kostas Papadimitriou
        },
246 68cc89f6 Kostas Papadimitriou
247 95ff92b4 Kostas Papadimitriou
        init_proxy_attrs: function() {
248 95ff92b4 Kostas Papadimitriou
          _.each(this.proxy_attrs, function(opts, attr){
249 95ff92b4 Kostas Papadimitriou
            var cb = opts[1];
250 95ff92b4 Kostas Papadimitriou
            _.each(opts[0], function(check_attr){
251 95ff92b4 Kostas Papadimitriou
              this._set_proxy_attr(attr, check_attr, cb)
252 95ff92b4 Kostas Papadimitriou
            }, this);
253 95ff92b4 Kostas Papadimitriou
          }, this);
254 95ff92b4 Kostas Papadimitriou
        },
255 95ff92b4 Kostas Papadimitriou
        
256 8d08f18a Kostas Papadimitriou
        handle_remove: function() {
257 643de8c0 Kostas Papadimitriou
            if (this.get("status") == 'DELETED') {
258 8d08f18a Kostas Papadimitriou
                if (this.collection) {
259 643de8c0 Kostas Papadimitriou
                    try { this.clear_pending_action();} catch (err) {};
260 643de8c0 Kostas Papadimitriou
                    try { this.reset_pending_actions();} catch (err) {};
261 2c9bfad1 Kostas Papadimitriou
                    try { this.stop_stats_update();} catch (err) {};
262 8d08f18a Kostas Papadimitriou
                    this.collection.remove(this.id);
263 8d08f18a Kostas Papadimitriou
                }
264 8d08f18a Kostas Papadimitriou
            }
265 8d08f18a Kostas Papadimitriou
        },
266 8d08f18a Kostas Papadimitriou
        
267 8d08f18a Kostas Papadimitriou
        // custom set method to allow submodels to use
268 8d08f18a Kostas Papadimitriou
        // set_<attr> methods for handling the value of each
269 8d08f18a Kostas Papadimitriou
        // attribute and overriding the default set method
270 8d08f18a Kostas Papadimitriou
        // for specific parameters
271 8d08f18a Kostas Papadimitriou
        set: function(params, options) {
272 8d08f18a Kostas Papadimitriou
            _.each(params, _.bind(function(value, key){
273 8d08f18a Kostas Papadimitriou
                if (this["set_" + key]) {
274 8d08f18a Kostas Papadimitriou
                    params[key] = this["set_" + key](value);
275 8d08f18a Kostas Papadimitriou
                }
276 8d08f18a Kostas Papadimitriou
            }, this))
277 8d08f18a Kostas Papadimitriou
            var ret = bb.Model.prototype.set.call(this, params, options);
278 8d08f18a Kostas Papadimitriou
            return ret;
279 8d08f18a Kostas Papadimitriou
        },
280 8d08f18a Kostas Papadimitriou
281 8d08f18a Kostas Papadimitriou
        url: function(options) {
282 c4fff449 Kostas Papadimitriou
            return getUrl.call(this, this.base_url) + "/" + this.id;
283 8d08f18a Kostas Papadimitriou
        },
284 8d08f18a Kostas Papadimitriou
285 8d08f18a Kostas Papadimitriou
        api_path: function(options) {
286 8d08f18a Kostas Papadimitriou
            return this.path + "/" + this.id;
287 8d08f18a Kostas Papadimitriou
        },
288 8d08f18a Kostas Papadimitriou
289 8d08f18a Kostas Papadimitriou
        parse: function(resp, xhr) {
290 8d08f18a Kostas Papadimitriou
        },
291 8d08f18a Kostas Papadimitriou
292 a429705e Kostas Papadimitriou
        remove: function(complete, error, success) {
293 a429705e Kostas Papadimitriou
            this.api_call(this.api_path(), "delete", undefined, complete, error, success);
294 2506f741 Kostas Papadimitriou
        },
295 2506f741 Kostas Papadimitriou
296 2506f741 Kostas Papadimitriou
        changedKeys: function() {
297 2506f741 Kostas Papadimitriou
            return _.keys(this.changedAttributes() || {});
298 2506f741 Kostas Papadimitriou
        },
299 1e882dd7 Kostas Papadimitriou
            
300 1e882dd7 Kostas Papadimitriou
        // return list of changed attributes that included in passed list
301 1e882dd7 Kostas Papadimitriou
        // argument
302 1e882dd7 Kostas Papadimitriou
        getKeysChanged: function(keys) {
303 1e882dd7 Kostas Papadimitriou
            return _.intersection(keys, this.changedKeys());
304 1e882dd7 Kostas Papadimitriou
        },
305 1e882dd7 Kostas Papadimitriou
        
306 1e882dd7 Kostas Papadimitriou
        // boolean check of keys changed
307 1e882dd7 Kostas Papadimitriou
        keysChanged: function(keys) {
308 1e882dd7 Kostas Papadimitriou
            return this.getKeysChanged(keys).length > 0;
309 1e882dd7 Kostas Papadimitriou
        },
310 2506f741 Kostas Papadimitriou
311 1e882dd7 Kostas Papadimitriou
        // check if any of the passed attribues has changed
312 2506f741 Kostas Papadimitriou
        hasOnlyChange: function(keys) {
313 2506f741 Kostas Papadimitriou
            var ret = false;
314 2506f741 Kostas Papadimitriou
            _.each(keys, _.bind(function(key) {
315 2506f741 Kostas Papadimitriou
                if (this.changedKeys().length == 1 && this.changedKeys().indexOf(key) > -1) { ret = true};
316 2506f741 Kostas Papadimitriou
            }, this));
317 2506f741 Kostas Papadimitriou
            return ret;
318 8d08f18a Kostas Papadimitriou
        }
319 8d08f18a Kostas Papadimitriou
320 8d08f18a Kostas Papadimitriou
    })
321 8d08f18a Kostas Papadimitriou
    
322 8d08f18a Kostas Papadimitriou
    // Base object for all our model collections
323 8d08f18a Kostas Papadimitriou
    models.Collection = bb.Collection.extend({
324 8d08f18a Kostas Papadimitriou
        sync: snf.api.sync,
325 8d08f18a Kostas Papadimitriou
        api: snf.api,
326 47e34b99 Kostas Papadimitriou
        api_type: 'compute',
327 16392650 Kostas Papadimitriou
        supportIncUpdates: true,
328 47e34b99 Kostas Papadimitriou
329 47e34b99 Kostas Papadimitriou
        initialize: function() {
330 47e34b99 Kostas Papadimitriou
            models.Collection.__super__.initialize.apply(this, arguments);
331 258235f4 Kostas Papadimitriou
            this.api_call = _.bind(this.api.call, this);
332 69dac1ba Kostas Papadimitriou
            if (this.sortFields) {
333 69dac1ba Kostas Papadimitriou
              _.each(this.sortFields, function(f) {
334 69dac1ba Kostas Papadimitriou
                this.bind("change:" + f, _.bind(this.resort, this));
335 69dac1ba Kostas Papadimitriou
              }, this);
336 69dac1ba Kostas Papadimitriou
            }
337 69dac1ba Kostas Papadimitriou
        },
338 69dac1ba Kostas Papadimitriou
          
339 69dac1ba Kostas Papadimitriou
        resort: function() {
340 69dac1ba Kostas Papadimitriou
          this.sort();
341 47e34b99 Kostas Papadimitriou
        },
342 47e34b99 Kostas Papadimitriou
343 2cee7cb0 Kostas Papadimitriou
        url: function(options, method) {
344 2cee7cb0 Kostas Papadimitriou
            return getUrl.call(this, this.base_url) + (
345 2cee7cb0 Kostas Papadimitriou
                    options.details || this.details && method != 'create' ? '/detail' : '');
346 8d08f18a Kostas Papadimitriou
        },
347 8d08f18a Kostas Papadimitriou
348 8d08f18a Kostas Papadimitriou
        fetch: function(options) {
349 859a4609 Kostas Papadimitriou
            if (!options) { options = {} };
350 8d08f18a Kostas Papadimitriou
            // default to update
351 8d08f18a Kostas Papadimitriou
            if (!this.noUpdate) {
352 8d08f18a Kostas Papadimitriou
                if (options.update === undefined) { options.update = true };
353 6be6f0b6 Kostas Papadimitriou
                if (!options.removeMissing && options.refresh) { 
354 6be6f0b6 Kostas Papadimitriou
                  options.removeMissing = true;
355 6be6f0b6 Kostas Papadimitriou
                };
356 6be6f0b6 Kostas Papadimitriou
                // for collections which associated models don't support 
357 6be6f0b6 Kostas Papadimitriou
                // deleted state identification through attributes, resolve  
358 6be6f0b6 Kostas Papadimitriou
                // deleted entries by checking for missing objects in fetch 
359 6be6f0b6 Kostas Papadimitriou
                // responses.
360 6be6f0b6 Kostas Papadimitriou
                if (this.updateEntries && options.removeMissing === undefined) {
361 6be6f0b6 Kostas Papadimitriou
                  options.removeMissing = true;
362 6be6f0b6 Kostas Papadimitriou
                }
363 859a4609 Kostas Papadimitriou
            } else {
364 859a4609 Kostas Papadimitriou
                if (options.refresh === undefined) {
365 859a4609 Kostas Papadimitriou
                    options.refresh = true;
366 6be6f0b6 Kostas Papadimitriou
                    if (this.updateEntries) {
367 6be6f0b6 Kostas Papadimitriou
                      options.update = true;
368 6be6f0b6 Kostas Papadimitriou
                      options.removeMissing = true;
369 6be6f0b6 Kostas Papadimitriou
                    }
370 859a4609 Kostas Papadimitriou
                }
371 8d08f18a Kostas Papadimitriou
            }
372 8d08f18a Kostas Papadimitriou
            // custom event foreach fetch
373 8d08f18a Kostas Papadimitriou
            return bb.Collection.prototype.fetch.call(this, options)
374 8d08f18a Kostas Papadimitriou
        },
375 8d08f18a Kostas Papadimitriou
376 859a4609 Kostas Papadimitriou
        create: function(model, options) {
377 859a4609 Kostas Papadimitriou
            var coll = this;
378 859a4609 Kostas Papadimitriou
            options || (options = {});
379 859a4609 Kostas Papadimitriou
            model = this._prepareModel(model, options);
380 859a4609 Kostas Papadimitriou
            if (!model) return false;
381 859a4609 Kostas Papadimitriou
            var success = options.success;
382 859a4609 Kostas Papadimitriou
            options.success = function(nextModel, resp, xhr) {
383 213a8396 Kostas Papadimitriou
                if (coll.add_on_create) {
384 213a8396 Kostas Papadimitriou
                  coll.add(nextModel, options);
385 213a8396 Kostas Papadimitriou
                }
386 859a4609 Kostas Papadimitriou
                if (success) success(nextModel, resp, xhr);
387 859a4609 Kostas Papadimitriou
            };
388 859a4609 Kostas Papadimitriou
            model.save(null, options);
389 859a4609 Kostas Papadimitriou
            return model;
390 859a4609 Kostas Papadimitriou
        },
391 859a4609 Kostas Papadimitriou
392 1cc6e94f Kostas Papadimitriou
        get_fetcher: function(interval, increase, fast, increase_after_calls, max, initial_call, params) {
393 9ce969a7 Kostas Papadimitriou
            var fetch_params = params || {};
394 1cc6e94f Kostas Papadimitriou
            var handler_options = {};
395 258235f4 Kostas Papadimitriou
396 258235f4 Kostas Papadimitriou
            fetch_params.skips_timeouts = true;
397 1cc6e94f Kostas Papadimitriou
            handler_options.interval = interval;
398 1cc6e94f Kostas Papadimitriou
            handler_options.increase = increase;
399 1cc6e94f Kostas Papadimitriou
            handler_options.fast = fast;
400 1cc6e94f Kostas Papadimitriou
            handler_options.increase_after_calls = increase_after_calls;
401 1cc6e94f Kostas Papadimitriou
            handler_options.max= max;
402 258235f4 Kostas Papadimitriou
            handler_options.id = "collection id";
403 1cc6e94f Kostas Papadimitriou
404 8d08f18a Kostas Papadimitriou
            var last_ajax = undefined;
405 258235f4 Kostas Papadimitriou
            var callback = _.bind(function() {
406 9ce969a7 Kostas Papadimitriou
                // clone to avoid referenced objects
407 9ce969a7 Kostas Papadimitriou
                var params = _.clone(fetch_params);
408 8d08f18a Kostas Papadimitriou
                updater._ajax = last_ajax;
409 a89ef0f5 Kostas Papadimitriou
                
410 42fb39fb Kostas Papadimitriou
                // wait for previous request to finish
411 a89ef0f5 Kostas Papadimitriou
                if (last_ajax && last_ajax.readyState < 4 && last_ajax.statusText != "timeout") {
412 a89ef0f5 Kostas Papadimitriou
                    // opera readystate for 304 responses is 0
413 a89ef0f5 Kostas Papadimitriou
                    if (!($.browser.opera && last_ajax.readyState == 0 && last_ajax.status == 304)) {
414 a89ef0f5 Kostas Papadimitriou
                        return;
415 a89ef0f5 Kostas Papadimitriou
                    }
416 8d08f18a Kostas Papadimitriou
                }
417 9ce969a7 Kostas Papadimitriou
                last_ajax = this.fetch(params);
418 8d08f18a Kostas Papadimitriou
            }, this);
419 258235f4 Kostas Papadimitriou
            handler_options.callback = callback;
420 8d08f18a Kostas Papadimitriou
421 258235f4 Kostas Papadimitriou
            var updater = new snf.api.updateHandler(_.clone(_.extend(handler_options, fetch_params)));
422 35855ff5 Kostas Papadimitriou
            snf.api.bind("call", _.throttle(_.bind(function(){ updater.faster(true)}, this)), 1000);
423 8d08f18a Kostas Papadimitriou
            return updater;
424 8d08f18a Kostas Papadimitriou
        }
425 8d08f18a Kostas Papadimitriou
    });
426 8d08f18a Kostas Papadimitriou
    
427 8d08f18a Kostas Papadimitriou
    // Image model
428 8d08f18a Kostas Papadimitriou
    models.Image = models.Model.extend({
429 8d08f18a Kostas Papadimitriou
        path: 'images',
430 8f53cfa3 Kostas Papadimitriou
        
431 8d08f18a Kostas Papadimitriou
        get_size: function() {
432 0dee4086 Kostas Papadimitriou
            return parseInt(this.get('metadata') ? this.get('metadata').size : -1)
433 820ef2f0 Kostas Papadimitriou
        },
434 820ef2f0 Kostas Papadimitriou
435 88d6d677 Kostas Papadimitriou
        get_description: function(escape) {
436 88d6d677 Kostas Papadimitriou
            if (escape == undefined) { escape = true };
437 88d6d677 Kostas Papadimitriou
            if (escape) { return this.escape('description') || "No description available"}
438 88d6d677 Kostas Papadimitriou
            return this.get('description') || "No description available."
439 88d6d677 Kostas Papadimitriou
        },
440 88d6d677 Kostas Papadimitriou
441 948042ca Kostas Papadimitriou
        get_meta: function(key) {
442 0dee4086 Kostas Papadimitriou
            if (this.get('metadata') && this.get('metadata')) {
443 0dee4086 Kostas Papadimitriou
                if (!this.get('metadata')[key]) { return null }
444 0dee4086 Kostas Papadimitriou
                return _.escape(this.get('metadata')[key]);
445 88d6d677 Kostas Papadimitriou
            } else {
446 88d6d677 Kostas Papadimitriou
                return null;
447 88d6d677 Kostas Papadimitriou
            }
448 88d6d677 Kostas Papadimitriou
        },
449 88d6d677 Kostas Papadimitriou
450 88d6d677 Kostas Papadimitriou
        get_meta_keys: function() {
451 0dee4086 Kostas Papadimitriou
            if (this.get('metadata') && this.get('metadata')) {
452 0dee4086 Kostas Papadimitriou
                return _.keys(this.get('metadata'));
453 88d6d677 Kostas Papadimitriou
            } else {
454 88d6d677 Kostas Papadimitriou
                return [];
455 948042ca Kostas Papadimitriou
            }
456 948042ca Kostas Papadimitriou
        },
457 948042ca Kostas Papadimitriou
458 948042ca Kostas Papadimitriou
        get_owner: function() {
459 1faf0b9c Kostas Papadimitriou
            return this.get('owner') || _.keys(synnefo.config.system_images_owners)[0];
460 948042ca Kostas Papadimitriou
        },
461 948042ca Kostas Papadimitriou
462 8f53cfa3 Kostas Papadimitriou
        get_owner_uuid: function() {
463 8f53cfa3 Kostas Papadimitriou
            return this.get('owner_uuid');
464 8f53cfa3 Kostas Papadimitriou
        },
465 8f53cfa3 Kostas Papadimitriou
466 fc6f43c3 Kostas Papadimitriou
        is_system_image: function() {
467 fc6f43c3 Kostas Papadimitriou
          var owner = this.get_owner();
468 fc6f43c3 Kostas Papadimitriou
          return _.include(_.keys(synnefo.config.system_images_owners), owner)
469 fc6f43c3 Kostas Papadimitriou
        },
470 fc6f43c3 Kostas Papadimitriou
471 fc6f43c3 Kostas Papadimitriou
        owned_by: function(user) {
472 fc6f43c3 Kostas Papadimitriou
          if (!user) { user = synnefo.user }
473 afe9ca75 Kostas Papadimitriou
          return user.get_username() == this.get('owner_uuid');
474 fc6f43c3 Kostas Papadimitriou
        },
475 fc6f43c3 Kostas Papadimitriou
476 babfdb9b Kostas Papadimitriou
        display_owner: function() {
477 babfdb9b Kostas Papadimitriou
            var owner = this.get_owner();
478 babfdb9b Kostas Papadimitriou
            if (_.include(_.keys(synnefo.config.system_images_owners), owner)) {
479 babfdb9b Kostas Papadimitriou
                return synnefo.config.system_images_owners[owner];
480 babfdb9b Kostas Papadimitriou
            } else {
481 babfdb9b Kostas Papadimitriou
                return owner;
482 babfdb9b Kostas Papadimitriou
            }
483 babfdb9b Kostas Papadimitriou
        },
484 03639c6d Kostas Papadimitriou
    
485 5a434360 Kostas Papadimitriou
        get_readable_size: function() {
486 03639c6d Kostas Papadimitriou
            if (this.is_deleted()) {
487 03639c6d Kostas Papadimitriou
                return synnefo.config.image_deleted_size_title || '(none)';
488 03639c6d Kostas Papadimitriou
            }
489 03639c6d Kostas Papadimitriou
            return this.get_size() > 0 ? util.readablizeBytes(this.get_size() * 1024 * 1024) : '(none)';
490 5a434360 Kostas Papadimitriou
        },
491 5a434360 Kostas Papadimitriou
492 820ef2f0 Kostas Papadimitriou
        get_os: function() {
493 88d6d677 Kostas Papadimitriou
            return this.get_meta('OS');
494 ccb14ad0 Kostas Papadimitriou
        },
495 ccb14ad0 Kostas Papadimitriou
496 6a0915f7 Kostas Papadimitriou
        get_gui: function() {
497 6a0915f7 Kostas Papadimitriou
            return this.get_meta('GUI');
498 6a0915f7 Kostas Papadimitriou
        },
499 6a0915f7 Kostas Papadimitriou
500 bdfb089f Kostas Papadimitriou
        get_created_users: function() {
501 bdfb089f Kostas Papadimitriou
            try {
502 bdfb089f Kostas Papadimitriou
              var users = this.get_meta('users').split(" ");
503 bdfb089f Kostas Papadimitriou
            } catch (err) { users = null }
504 a6213c91 Kostas Papadimitriou
            if (!users) {
505 a6213c91 Kostas Papadimitriou
                var osfamily = this.get_meta('osfamily');
506 a6213c91 Kostas Papadimitriou
                if (osfamily == 'windows') { 
507 a6213c91 Kostas Papadimitriou
                  users = ['Administrator'];
508 a6213c91 Kostas Papadimitriou
                } else {
509 a6213c91 Kostas Papadimitriou
                  users = ['root'];
510 a6213c91 Kostas Papadimitriou
                }
511 a6213c91 Kostas Papadimitriou
            }
512 bdfb089f Kostas Papadimitriou
            return users;
513 47276ec2 Kostas Papadimitriou
        },
514 47276ec2 Kostas Papadimitriou
515 ccb14ad0 Kostas Papadimitriou
        get_sort_order: function() {
516 0dee4086 Kostas Papadimitriou
            return parseInt(this.get('metadata') ? this.get('metadata').sortorder : -1)
517 47276ec2 Kostas Papadimitriou
        },
518 2cee7cb0 Kostas Papadimitriou
519 2cee7cb0 Kostas Papadimitriou
        get_vm: function() {
520 2cee7cb0 Kostas Papadimitriou
            var vm_id = this.get("serverRef");
521 2cee7cb0 Kostas Papadimitriou
            var vm = undefined;
522 2cee7cb0 Kostas Papadimitriou
            vm = storage.vms.get(vm_id);
523 2cee7cb0 Kostas Papadimitriou
            return vm;
524 2cee7cb0 Kostas Papadimitriou
        },
525 948042ca Kostas Papadimitriou
526 948042ca Kostas Papadimitriou
        is_public: function() {
527 77baab80 Kostas Papadimitriou
            return this.get('is_public') == undefined ? true : this.get('is_public');
528 948042ca Kostas Papadimitriou
        },
529 03639c6d Kostas Papadimitriou
530 03639c6d Kostas Papadimitriou
        is_deleted: function() {
531 03639c6d Kostas Papadimitriou
            return this.get('status') == "DELETED"
532 03639c6d Kostas Papadimitriou
        },
533 47276ec2 Kostas Papadimitriou
        
534 bdfb089f Kostas Papadimitriou
        ssh_keys_paths: function() {
535 bdfb089f Kostas Papadimitriou
            return _.map(this.get_created_users(), function(username) {
536 bdfb089f Kostas Papadimitriou
                prepend = '';
537 bdfb089f Kostas Papadimitriou
                if (username != 'root') {
538 bdfb089f Kostas Papadimitriou
                    prepend = '/home'
539 bdfb089f Kostas Papadimitriou
                }
540 5d9ac244 Kostas Papadimitriou
                return {'user': username, 'path': '{1}/{0}/.ssh/authorized_keys'.format(username, 
541 5d9ac244 Kostas Papadimitriou
                                                             prepend)};
542 bdfb089f Kostas Papadimitriou
            });
543 47276ec2 Kostas Papadimitriou
        },
544 47276ec2 Kostas Papadimitriou
545 47276ec2 Kostas Papadimitriou
        _supports_ssh: function() {
546 47276ec2 Kostas Papadimitriou
            if (synnefo.config.support_ssh_os_list.indexOf(this.get_os()) > -1) {
547 47276ec2 Kostas Papadimitriou
                return true;
548 47276ec2 Kostas Papadimitriou
            }
549 d3e4bca7 Kostas Papadimitriou
            if (this.get_meta('osfamily') == 'linux') {
550 d3e4bca7 Kostas Papadimitriou
              return true;
551 d3e4bca7 Kostas Papadimitriou
            }
552 47276ec2 Kostas Papadimitriou
            return false;
553 47276ec2 Kostas Papadimitriou
        },
554 47276ec2 Kostas Papadimitriou
555 47276ec2 Kostas Papadimitriou
        supports: function(feature) {
556 47276ec2 Kostas Papadimitriou
            if (feature == "ssh") {
557 47276ec2 Kostas Papadimitriou
                return this._supports_ssh()
558 47276ec2 Kostas Papadimitriou
            }
559 47276ec2 Kostas Papadimitriou
            return false;
560 47276ec2 Kostas Papadimitriou
        },
561 47276ec2 Kostas Papadimitriou
562 47276ec2 Kostas Papadimitriou
        personality_data_for_keys: function(keys) {
563 5d9ac244 Kostas Papadimitriou
            return _.map(this.ssh_keys_paths(), function(pathinfo) {
564 bdfb089f Kostas Papadimitriou
                var contents = '';
565 bdfb089f Kostas Papadimitriou
                _.each(keys, function(key){
566 bdfb089f Kostas Papadimitriou
                    contents = contents + key.get("content") + "\n"
567 bdfb089f Kostas Papadimitriou
                });
568 bdfb089f Kostas Papadimitriou
                contents = $.base64.encode(contents);
569 bdfb089f Kostas Papadimitriou
570 bdfb089f Kostas Papadimitriou
                return {
571 5d9ac244 Kostas Papadimitriou
                    path: pathinfo.path,
572 5d9ac244 Kostas Papadimitriou
                    contents: contents,
573 5d9ac244 Kostas Papadimitriou
                    mode: 0600,
574 8b14f29d Kostas Papadimitriou
                    owner: pathinfo.user
575 bdfb089f Kostas Papadimitriou
                }
576 47276ec2 Kostas Papadimitriou
            });
577 8d08f18a Kostas Papadimitriou
        }
578 8d08f18a Kostas Papadimitriou
    });
579 8d08f18a Kostas Papadimitriou
580 8d08f18a Kostas Papadimitriou
    // Flavor model
581 8d08f18a Kostas Papadimitriou
    models.Flavor = models.Model.extend({
582 8d08f18a Kostas Papadimitriou
        path: 'flavors',
583 8d08f18a Kostas Papadimitriou
584 8d08f18a Kostas Papadimitriou
        details_string: function() {
585 8d08f18a Kostas Papadimitriou
            return "{0} CPU, {1}MB, {2}GB".format(this.get('cpu'), this.get('ram'), this.get('disk'));
586 820ef2f0 Kostas Papadimitriou
        },
587 820ef2f0 Kostas Papadimitriou
588 820ef2f0 Kostas Papadimitriou
        get_disk_size: function() {
589 9c8f31ad Kostas Papadimitriou
            return parseInt(this.get("disk") * 1024)
590 d965e6dc Kostas Papadimitriou
        },
591 d965e6dc Kostas Papadimitriou
592 7ac49c2e Kostas Papadimitriou
        get_ram_size: function() {
593 7ac49c2e Kostas Papadimitriou
            return parseInt(this.get("ram"))
594 7ac49c2e Kostas Papadimitriou
        },
595 7ac49c2e Kostas Papadimitriou
596 d965e6dc Kostas Papadimitriou
        get_disk_template_info: function() {
597 d965e6dc Kostas Papadimitriou
            var info = snf.config.flavors_disk_templates_info[this.get("disk_template")];
598 d965e6dc Kostas Papadimitriou
            if (!info) {
599 d965e6dc Kostas Papadimitriou
                info = { name: this.get("disk_template"), description:'' };
600 d965e6dc Kostas Papadimitriou
            }
601 d965e6dc Kostas Papadimitriou
            return info
602 7ac49c2e Kostas Papadimitriou
        },
603 7ac49c2e Kostas Papadimitriou
604 7ac49c2e Kostas Papadimitriou
        disk_to_bytes: function() {
605 7ac49c2e Kostas Papadimitriou
            return parseInt(this.get("disk")) * 1024 * 1024 * 1024;
606 7ac49c2e Kostas Papadimitriou
        },
607 7ac49c2e Kostas Papadimitriou
608 7ac49c2e Kostas Papadimitriou
        ram_to_bytes: function() {
609 7ac49c2e Kostas Papadimitriou
            return parseInt(this.get("ram")) * 1024 * 1024;
610 7ac49c2e Kostas Papadimitriou
        },
611 820ef2f0 Kostas Papadimitriou
612 8d08f18a Kostas Papadimitriou
    });
613 8d08f18a Kostas Papadimitriou
    
614 101e6604 Kostas Papadimitriou
    models.ParamsList = function(){this.initialize.apply(this, arguments)};
615 101e6604 Kostas Papadimitriou
    _.extend(models.ParamsList.prototype, bb.Events, {
616 101e6604 Kostas Papadimitriou
617 101e6604 Kostas Papadimitriou
        initialize: function(parent, param_name) {
618 101e6604 Kostas Papadimitriou
            this.parent = parent;
619 101e6604 Kostas Papadimitriou
            this.actions = {};
620 101e6604 Kostas Papadimitriou
            this.param_name = param_name;
621 101e6604 Kostas Papadimitriou
            this.length = 0;
622 101e6604 Kostas Papadimitriou
        },
623 101e6604 Kostas Papadimitriou
        
624 101e6604 Kostas Papadimitriou
        has_action: function(action) {
625 101e6604 Kostas Papadimitriou
            return this.actions[action] ? true : false;
626 101e6604 Kostas Papadimitriou
        },
627 101e6604 Kostas Papadimitriou
            
628 101e6604 Kostas Papadimitriou
        _parse_params: function(arguments) {
629 101e6604 Kostas Papadimitriou
            if (arguments.length <= 1) {
630 101e6604 Kostas Papadimitriou
                return [];
631 101e6604 Kostas Papadimitriou
            }
632 101e6604 Kostas Papadimitriou
633 101e6604 Kostas Papadimitriou
            var args = _.toArray(arguments);
634 101e6604 Kostas Papadimitriou
            return args.splice(1);
635 101e6604 Kostas Papadimitriou
        },
636 101e6604 Kostas Papadimitriou
637 101e6604 Kostas Papadimitriou
        contains: function(action, params) {
638 101e6604 Kostas Papadimitriou
            params = this._parse_params(arguments);
639 101e6604 Kostas Papadimitriou
            var has_action = this.has_action(action);
640 101e6604 Kostas Papadimitriou
            if (!has_action) { return false };
641 101e6604 Kostas Papadimitriou
642 101e6604 Kostas Papadimitriou
            var paramsEqual = false;
643 101e6604 Kostas Papadimitriou
            _.each(this.actions[action], function(action_params) {
644 101e6604 Kostas Papadimitriou
                if (_.isEqual(action_params, params)) {
645 101e6604 Kostas Papadimitriou
                    paramsEqual = true;
646 101e6604 Kostas Papadimitriou
                }
647 101e6604 Kostas Papadimitriou
            });
648 101e6604 Kostas Papadimitriou
                
649 101e6604 Kostas Papadimitriou
            return paramsEqual;
650 101e6604 Kostas Papadimitriou
        },
651 101e6604 Kostas Papadimitriou
        
652 101e6604 Kostas Papadimitriou
        is_empty: function() {
653 101e6604 Kostas Papadimitriou
            return _.isEmpty(this.actions);
654 101e6604 Kostas Papadimitriou
        },
655 101e6604 Kostas Papadimitriou
656 101e6604 Kostas Papadimitriou
        add: function(action, params) {
657 101e6604 Kostas Papadimitriou
            params = this._parse_params(arguments);
658 101e6604 Kostas Papadimitriou
            if (this.contains.apply(this, arguments)) { return this };
659 101e6604 Kostas Papadimitriou
            var isnew = false
660 101e6604 Kostas Papadimitriou
            if (!this.has_action(action)) {
661 101e6604 Kostas Papadimitriou
                this.actions[action] = [];
662 101e6604 Kostas Papadimitriou
                isnew = true;
663 101e6604 Kostas Papadimitriou
            };
664 101e6604 Kostas Papadimitriou
665 101e6604 Kostas Papadimitriou
            this.actions[action].push(params);
666 101e6604 Kostas Papadimitriou
            this.parent.trigger("change:" + this.param_name, this.parent, this);
667 101e6604 Kostas Papadimitriou
            if (isnew) {
668 101e6604 Kostas Papadimitriou
                this.trigger("add", action, params);
669 101e6604 Kostas Papadimitriou
            } else {
670 101e6604 Kostas Papadimitriou
                this.trigger("change", action, params);
671 101e6604 Kostas Papadimitriou
            }
672 101e6604 Kostas Papadimitriou
            return this;
673 101e6604 Kostas Papadimitriou
        },
674 101e6604 Kostas Papadimitriou
        
675 101e6604 Kostas Papadimitriou
        remove_all: function(action) {
676 101e6604 Kostas Papadimitriou
            if (this.has_action(action)) {
677 101e6604 Kostas Papadimitriou
                delete this.actions[action];
678 101e6604 Kostas Papadimitriou
                this.parent.trigger("change:" + this.param_name, this.parent, this);
679 101e6604 Kostas Papadimitriou
                this.trigger("remove", action);
680 101e6604 Kostas Papadimitriou
            }
681 101e6604 Kostas Papadimitriou
            return this;
682 101e6604 Kostas Papadimitriou
        },
683 101e6604 Kostas Papadimitriou
684 101e6604 Kostas Papadimitriou
        reset: function() {
685 101e6604 Kostas Papadimitriou
            this.actions = {};
686 101e6604 Kostas Papadimitriou
            this.parent.trigger("change:" + this.param_name, this.parent, this);
687 101e6604 Kostas Papadimitriou
            this.trigger("reset");
688 101e6604 Kostas Papadimitriou
            this.trigger("remove");
689 101e6604 Kostas Papadimitriou
        },
690 101e6604 Kostas Papadimitriou
691 101e6604 Kostas Papadimitriou
        remove: function(action, params) {
692 101e6604 Kostas Papadimitriou
            params = this._parse_params(arguments);
693 101e6604 Kostas Papadimitriou
            if (!this.has_action(action)) { return this };
694 101e6604 Kostas Papadimitriou
            var index = -1;
695 101e6604 Kostas Papadimitriou
            _.each(this.actions[action], _.bind(function(action_params) {
696 101e6604 Kostas Papadimitriou
                if (_.isEqual(action_params, params)) {
697 101e6604 Kostas Papadimitriou
                    index = this.actions[action].indexOf(action_params);
698 101e6604 Kostas Papadimitriou
                }
699 101e6604 Kostas Papadimitriou
            }, this));
700 101e6604 Kostas Papadimitriou
            
701 101e6604 Kostas Papadimitriou
            if (index > -1) {
702 101e6604 Kostas Papadimitriou
                this.actions[action].splice(index, 1);
703 101e6604 Kostas Papadimitriou
                if (_.isEmpty(this.actions[action])) {
704 101e6604 Kostas Papadimitriou
                    delete this.actions[action];
705 101e6604 Kostas Papadimitriou
                }
706 101e6604 Kostas Papadimitriou
                this.parent.trigger("change:" + this.param_name, this.parent, this);
707 101e6604 Kostas Papadimitriou
                this.trigger("remove", action, params);
708 101e6604 Kostas Papadimitriou
            }
709 101e6604 Kostas Papadimitriou
        }
710 101e6604 Kostas Papadimitriou
711 101e6604 Kostas Papadimitriou
    });
712 8d08f18a Kostas Papadimitriou
713 8d08f18a Kostas Papadimitriou
    // Virtualmachine model
714 8d08f18a Kostas Papadimitriou
    models.VM = models.Model.extend({
715 8d08f18a Kostas Papadimitriou
716 8d08f18a Kostas Papadimitriou
        path: 'servers',
717 8d08f18a Kostas Papadimitriou
        has_status: true,
718 45b964d3 Kostas Papadimitriou
        proxy_attrs: {
719 45b964d3 Kostas Papadimitriou
          'busy': [
720 45b964d3 Kostas Papadimitriou
            ['status', 'state'], function() {
721 ba7421ce Kostas Papadimitriou
              return !_.contains(['ACTIVE', 'STOPPED'], this.get('status'));
722 45b964d3 Kostas Papadimitriou
            }
723 3cac4a52 Kostas Papadimitriou
          ]
724 45b964d3 Kostas Papadimitriou
        },
725 45b964d3 Kostas Papadimitriou
726 8d08f18a Kostas Papadimitriou
        initialize: function(params) {
727 365af933 Kostas Papadimitriou
            var self = this;
728 365af933 Kostas Papadimitriou
            this.ports = new Backbone.FilteredCollection(undefined, {
729 365af933 Kostas Papadimitriou
              collection: synnefo.storage.ports,
730 365af933 Kostas Papadimitriou
              collectionFilter: function(m) {
731 365af933 Kostas Papadimitriou
                return self.id == m.get('device_id')
732 365af933 Kostas Papadimitriou
            }});
733 365af933 Kostas Papadimitriou
734 8d08f18a Kostas Papadimitriou
            this.pending_firewalls = {};
735 8d08f18a Kostas Papadimitriou
            
736 8d08f18a Kostas Papadimitriou
            models.VM.__super__.initialize.apply(this, arguments);
737 8d08f18a Kostas Papadimitriou
738 365af933 Kostas Papadimitriou
739 8d08f18a Kostas Papadimitriou
            this.set({state: params.status || "ERROR"});
740 8d08f18a Kostas Papadimitriou
            this.log = new snf.logging.logger("VM " + this.id);
741 8d08f18a Kostas Papadimitriou
            this.pending_action = undefined;
742 8d08f18a Kostas Papadimitriou
            
743 8d08f18a Kostas Papadimitriou
            // init stats parameter
744 8d08f18a Kostas Papadimitriou
            this.set({'stats': undefined}, {silent: true});
745 8d08f18a Kostas Papadimitriou
            // defaults to not update the stats
746 8d08f18a Kostas Papadimitriou
            // each view should handle this vm attribute 
747 8d08f18a Kostas Papadimitriou
            // depending on if it displays stat images or not
748 8d08f18a Kostas Papadimitriou
            this.do_update_stats = false;
749 8d08f18a Kostas Papadimitriou
            
750 8d08f18a Kostas Papadimitriou
            // interval time
751 8d08f18a Kostas Papadimitriou
            // this will dynamicaly change if the server responds that
752 8d08f18a Kostas Papadimitriou
            // images get refreshed on different intervals
753 8d08f18a Kostas Papadimitriou
            this.stats_update_interval = synnefo.config.STATS_INTERVAL || 5000;
754 96d725ac Kostas Papadimitriou
            this.stats_available = false;
755 8d08f18a Kostas Papadimitriou
756 8d08f18a Kostas Papadimitriou
            // initialize interval
757 8d08f18a Kostas Papadimitriou
            this.init_stats_intervals(this.stats_update_interval);
758 8d08f18a Kostas Papadimitriou
            
759 1e882dd7 Kostas Papadimitriou
            // handle progress message on instance change
760 1e882dd7 Kostas Papadimitriou
            this.bind("change", _.bind(this.update_status_message, this));
761 a3ac649e Kostas Papadimitriou
            this.bind("change:task_state", _.bind(this.update_status, this));
762 1e882dd7 Kostas Papadimitriou
            // force update of progress message
763 1e882dd7 Kostas Papadimitriou
            this.update_status_message(true);
764 1e882dd7 Kostas Papadimitriou
            
765 8d08f18a Kostas Papadimitriou
            // default values
766 126a01f2 Kostas Papadimitriou
            this.bind("change:state", _.bind(function(){
767 126a01f2 Kostas Papadimitriou
                if (this.state() == "DESTROY") { 
768 126a01f2 Kostas Papadimitriou
                    this.handle_destroy() 
769 126a01f2 Kostas Papadimitriou
                }
770 126a01f2 Kostas Papadimitriou
            }, this));
771 8d08f18a Kostas Papadimitriou
772 8d08f18a Kostas Papadimitriou
        },
773 3cac4a52 Kostas Papadimitriou
          
774 3cac4a52 Kostas Papadimitriou
        has_public_ip: function() {
775 3cac4a52 Kostas Papadimitriou
          return this.ports.filter(function(port) {
776 3cac4a52 Kostas Papadimitriou
            return port.get("network") && 
777 3cac4a52 Kostas Papadimitriou
                   port.get("network").get("is_public") && 
778 3cac4a52 Kostas Papadimitriou
                   port.get("ips").length > 0;
779 3cac4a52 Kostas Papadimitriou
          }).length > 0;
780 3cac4a52 Kostas Papadimitriou
        },
781 3cac4a52 Kostas Papadimitriou
782 3cac4a52 Kostas Papadimitriou
        has_public_ipv6: function() {
783 3cac4a52 Kostas Papadimitriou
          return this.has_ip_version("v6", true);
784 3cac4a52 Kostas Papadimitriou
        },
785 3cac4a52 Kostas Papadimitriou
786 3cac4a52 Kostas Papadimitriou
        has_public_ipv4: function() {
787 3cac4a52 Kostas Papadimitriou
          return this.has_ip_version("v4", true);
788 3cac4a52 Kostas Papadimitriou
        },
789 3cac4a52 Kostas Papadimitriou
        
790 3cac4a52 Kostas Papadimitriou
        has_ip_version: function(ver, public) {
791 3cac4a52 Kostas Papadimitriou
          var found = false;
792 3cac4a52 Kostas Papadimitriou
          this.ports.each(function(port) {
793 3cac4a52 Kostas Papadimitriou
            if (found) { return }
794 3cac4a52 Kostas Papadimitriou
            if (public !== undefined) {
795 3cac4a52 Kostas Papadimitriou
              if (port.get("network") && 
796 3cac4a52 Kostas Papadimitriou
                  port.get("network").get("is_public") != public) {
797 3cac4a52 Kostas Papadimitriou
                return
798 3cac4a52 Kostas Papadimitriou
              }
799 3cac4a52 Kostas Papadimitriou
            }
800 3cac4a52 Kostas Papadimitriou
            port.get('ips').each(function(ip) {
801 3cac4a52 Kostas Papadimitriou
              if (found) { return }
802 3cac4a52 Kostas Papadimitriou
              if (ip.get("type") == ver) {
803 3cac4a52 Kostas Papadimitriou
                found = true
804 3cac4a52 Kostas Papadimitriou
              }
805 3cac4a52 Kostas Papadimitriou
            })
806 3cac4a52 Kostas Papadimitriou
          }, this)
807 3cac4a52 Kostas Papadimitriou
          return found;
808 3cac4a52 Kostas Papadimitriou
        },
809 8d08f18a Kostas Papadimitriou
810 8d08f18a Kostas Papadimitriou
        status: function(st) {
811 8d08f18a Kostas Papadimitriou
            if (!st) { return this.get("status")}
812 8d08f18a Kostas Papadimitriou
            return this.set({status:st});
813 8d08f18a Kostas Papadimitriou
        },
814 a3ac649e Kostas Papadimitriou
        
815 a3ac649e Kostas Papadimitriou
        update_status: function() {
816 a3ac649e Kostas Papadimitriou
            this.set_status(this.get('status'));
817 a3ac649e Kostas Papadimitriou
        },
818 8d08f18a Kostas Papadimitriou
819 8d08f18a Kostas Papadimitriou
        set_status: function(st) {
820 8d08f18a Kostas Papadimitriou
            var new_state = this.state_for_api_status(st);
821 8d08f18a Kostas Papadimitriou
            var transition = false;
822 8d08f18a Kostas Papadimitriou
823 8d08f18a Kostas Papadimitriou
            if (this.state() != new_state) {
824 8d08f18a Kostas Papadimitriou
                if (models.VM.STATES_TRANSITIONS[this.state()]) {
825 8d08f18a Kostas Papadimitriou
                    transition = this.state();
826 8d08f18a Kostas Papadimitriou
                }
827 8d08f18a Kostas Papadimitriou
            }
828 8d08f18a Kostas Papadimitriou
            
829 8d08f18a Kostas Papadimitriou
            // call it silently to avoid double change trigger
830 a3ac649e Kostas Papadimitriou
            var state = this.state_for_api_status(st);
831 a3ac649e Kostas Papadimitriou
            this.set({'state': state}, {silent: true});
832 8d08f18a Kostas Papadimitriou
            
833 8d08f18a Kostas Papadimitriou
            // trigger transition
834 572dbe3d Kostas Papadimitriou
            if (transition && models.VM.TRANSITION_STATES.indexOf(new_state) == -1) { 
835 572dbe3d Kostas Papadimitriou
                this.trigger("transition", {from:transition, to:new_state}) 
836 572dbe3d Kostas Papadimitriou
            };
837 8d08f18a Kostas Papadimitriou
            return st;
838 8d08f18a Kostas Papadimitriou
        },
839 1e882dd7 Kostas Papadimitriou
            
840 1e882dd7 Kostas Papadimitriou
        get_diagnostics: function(success) {
841 1e882dd7 Kostas Papadimitriou
            this.__make_api_call(this.get_diagnostics_url(),
842 1e882dd7 Kostas Papadimitriou
                                 "read", // create so that sync later uses POST to make the call
843 1e882dd7 Kostas Papadimitriou
                                 null, // payload
844 1e882dd7 Kostas Papadimitriou
                                 function(data) {
845 1e882dd7 Kostas Papadimitriou
                                     success(data);
846 1e882dd7 Kostas Papadimitriou
                                 },  
847 1e882dd7 Kostas Papadimitriou
                                 null, 'diagnostics');
848 1e882dd7 Kostas Papadimitriou
        },
849 8d08f18a Kostas Papadimitriou
850 1e882dd7 Kostas Papadimitriou
        has_diagnostics: function() {
851 1e882dd7 Kostas Papadimitriou
            return this.get("diagnostics") && this.get("diagnostics").length;
852 1e882dd7 Kostas Papadimitriou
        },
853 1e882dd7 Kostas Papadimitriou
854 1e882dd7 Kostas Papadimitriou
        get_progress_info: function() {
855 1e882dd7 Kostas Papadimitriou
            // details about progress message
856 1e882dd7 Kostas Papadimitriou
            // contains a list of diagnostic messages
857 1e882dd7 Kostas Papadimitriou
            return this.get("status_messages");
858 1e882dd7 Kostas Papadimitriou
        },
859 1e882dd7 Kostas Papadimitriou
860 1e882dd7 Kostas Papadimitriou
        get_status_message: function() {
861 1e882dd7 Kostas Papadimitriou
            return this.get('status_message');
862 1e882dd7 Kostas Papadimitriou
        },
863 1e882dd7 Kostas Papadimitriou
        
864 1e882dd7 Kostas Papadimitriou
        // extract status message from diagnostics
865 1e882dd7 Kostas Papadimitriou
        status_message_from_diagnostics: function(diagnostics) {
866 1e882dd7 Kostas Papadimitriou
            var valid_sources_map = synnefo.config.diagnostics_status_messages_map;
867 1e882dd7 Kostas Papadimitriou
            var valid_sources = valid_sources_map[this.get('status')];
868 1e882dd7 Kostas Papadimitriou
            if (!valid_sources) { return null };
869 1e882dd7 Kostas Papadimitriou
            
870 1e882dd7 Kostas Papadimitriou
            // filter messsages based on diagnostic source
871 1e882dd7 Kostas Papadimitriou
            var messages = _.filter(diagnostics, function(diag) {
872 1e882dd7 Kostas Papadimitriou
                return valid_sources.indexOf(diag.source) > -1;
873 1e882dd7 Kostas Papadimitriou
            });
874 1e882dd7 Kostas Papadimitriou
875 1e882dd7 Kostas Papadimitriou
            var msg = messages[0];
876 1e882dd7 Kostas Papadimitriou
            if (msg) {
877 1e882dd7 Kostas Papadimitriou
              var message = msg.message;
878 1e882dd7 Kostas Papadimitriou
              var message_tpl = snf.config.diagnostic_messages_tpls[msg.source];
879 1e882dd7 Kostas Papadimitriou
880 1e882dd7 Kostas Papadimitriou
              if (message_tpl) {
881 1e882dd7 Kostas Papadimitriou
                  message = message_tpl.replace('MESSAGE', msg.message);
882 1e882dd7 Kostas Papadimitriou
              }
883 1e882dd7 Kostas Papadimitriou
              return message;
884 1e882dd7 Kostas Papadimitriou
            }
885 1e882dd7 Kostas Papadimitriou
            
886 1e882dd7 Kostas Papadimitriou
            // no message to display, but vm in build state, display
887 1e882dd7 Kostas Papadimitriou
            // finalizing message.
888 1e882dd7 Kostas Papadimitriou
            if (this.is_building() == 'BUILD') {
889 1e882dd7 Kostas Papadimitriou
                return synnefo.config.BUILDING_MESSAGES['FINAL'];
890 1e882dd7 Kostas Papadimitriou
            }
891 1e882dd7 Kostas Papadimitriou
            return null;
892 1e882dd7 Kostas Papadimitriou
        },
893 1e882dd7 Kostas Papadimitriou
894 1e882dd7 Kostas Papadimitriou
        update_status_message: function(force) {
895 1e882dd7 Kostas Papadimitriou
            // update only if one of the specified attributes has changed
896 1e882dd7 Kostas Papadimitriou
            if (
897 1e882dd7 Kostas Papadimitriou
              !this.keysChanged(['diagnostics', 'progress', 'status', 'state'])
898 1e882dd7 Kostas Papadimitriou
                && !force
899 1e882dd7 Kostas Papadimitriou
            ) { return };
900 1e882dd7 Kostas Papadimitriou
            
901 1e882dd7 Kostas Papadimitriou
            // if user requested to destroy the vm set the appropriate 
902 1e882dd7 Kostas Papadimitriou
            // message.
903 1e882dd7 Kostas Papadimitriou
            if (this.get('state') == "DESTROY") { 
904 1e882dd7 Kostas Papadimitriou
                message = "Terminating..."
905 1e882dd7 Kostas Papadimitriou
                this.set({status_message: message})
906 1e882dd7 Kostas Papadimitriou
                return;
907 1e882dd7 Kostas Papadimitriou
            }
908 1e882dd7 Kostas Papadimitriou
            
909 1e882dd7 Kostas Papadimitriou
            // set error message, if vm has diagnostic message display it as
910 1e882dd7 Kostas Papadimitriou
            // progress message
911 1e882dd7 Kostas Papadimitriou
            if (this.in_error_state()) {
912 1e882dd7 Kostas Papadimitriou
                var d = this.get('diagnostics');
913 1e882dd7 Kostas Papadimitriou
                if (d && d.length) {
914 1e882dd7 Kostas Papadimitriou
                    var message = this.status_message_from_diagnostics(d);
915 1e882dd7 Kostas Papadimitriou
                    this.set({status_message: message});
916 1e882dd7 Kostas Papadimitriou
                } else {
917 1e882dd7 Kostas Papadimitriou
                    this.set({status_message: null});
918 8d08f18a Kostas Papadimitriou
                }
919 1e882dd7 Kostas Papadimitriou
                return;
920 1e882dd7 Kostas Papadimitriou
            }
921 1e882dd7 Kostas Papadimitriou
            
922 1e882dd7 Kostas Papadimitriou
            // identify building status message
923 1e882dd7 Kostas Papadimitriou
            if (this.is_building()) {
924 1e882dd7 Kostas Papadimitriou
                var self = this;
925 1e882dd7 Kostas Papadimitriou
                var success = function(msg) {
926 1e882dd7 Kostas Papadimitriou
                    self.set({status_message: msg});
927 8d08f18a Kostas Papadimitriou
                }
928 1e882dd7 Kostas Papadimitriou
                this.get_building_status_message(success);
929 1e882dd7 Kostas Papadimitriou
                return;
930 1e882dd7 Kostas Papadimitriou
            }
931 1e882dd7 Kostas Papadimitriou
932 1e882dd7 Kostas Papadimitriou
            this.set({status_message:null});
933 1e882dd7 Kostas Papadimitriou
        },
934 1e882dd7 Kostas Papadimitriou
            
935 1e882dd7 Kostas Papadimitriou
        // get building status message. Asynchronous function since it requires
936 1e882dd7 Kostas Papadimitriou
        // access to vm image.
937 1e882dd7 Kostas Papadimitriou
        get_building_status_message: function(callback) {
938 1e882dd7 Kostas Papadimitriou
            // no progress is set, vm is in initial build status
939 1e882dd7 Kostas Papadimitriou
            var progress = this.get("progress");
940 1e882dd7 Kostas Papadimitriou
            if (progress == 0 || !progress) {
941 1e882dd7 Kostas Papadimitriou
                return callback(BUILDING_MESSAGES['INIT']);
942 1e882dd7 Kostas Papadimitriou
            }
943 1e882dd7 Kostas Papadimitriou
            
944 1e882dd7 Kostas Papadimitriou
            // vm has copy progress, display copy percentage
945 1e882dd7 Kostas Papadimitriou
            if (progress > 0 && progress <= 99) {
946 1e882dd7 Kostas Papadimitriou
                this.get_copy_details(true, undefined, _.bind(
947 1e882dd7 Kostas Papadimitriou
                    function(details){
948 1e882dd7 Kostas Papadimitriou
                        callback(BUILDING_MESSAGES['COPY'].format(details.copy, 
949 1e882dd7 Kostas Papadimitriou
                                                           details.size, 
950 1e882dd7 Kostas Papadimitriou
                                                           details.progress));
951 1e882dd7 Kostas Papadimitriou
                }, this));
952 1e882dd7 Kostas Papadimitriou
                return;
953 1e882dd7 Kostas Papadimitriou
            }
954 1e882dd7 Kostas Papadimitriou
955 1e882dd7 Kostas Papadimitriou
            // copy finished display FINAL message or identify status message
956 1e882dd7 Kostas Papadimitriou
            // from diagnostics.
957 1e882dd7 Kostas Papadimitriou
            if (progress >= 100) {
958 1e882dd7 Kostas Papadimitriou
                if (!this.has_diagnostics()) {
959 1e882dd7 Kostas Papadimitriou
                        callback(BUILDING_MESSAGES['FINAL']);
960 1e882dd7 Kostas Papadimitriou
                } else {
961 1e882dd7 Kostas Papadimitriou
                        var d = this.get("diagnostics");
962 1e882dd7 Kostas Papadimitriou
                        var msg = this.status_message_from_diagnostics(d);
963 1e882dd7 Kostas Papadimitriou
                        if (msg) {
964 1e882dd7 Kostas Papadimitriou
                              callback(msg);
965 1e882dd7 Kostas Papadimitriou
                        }
966 8d08f18a Kostas Papadimitriou
                }
967 8d08f18a Kostas Papadimitriou
            }
968 8d08f18a Kostas Papadimitriou
        },
969 8d08f18a Kostas Papadimitriou
970 c45bed88 Kostas Papadimitriou
        get_copy_details: function(human, image, callback) {
971 8d08f18a Kostas Papadimitriou
            var human = human || false;
972 c45bed88 Kostas Papadimitriou
            var image = image || this.get_image(_.bind(function(image){
973 c45bed88 Kostas Papadimitriou
                var progress = this.get('progress');
974 c45bed88 Kostas Papadimitriou
                var size = image.get_size();
975 c45bed88 Kostas Papadimitriou
                var size_copied = (size * progress / 100).toFixed(2);
976 c45bed88 Kostas Papadimitriou
                
977 c45bed88 Kostas Papadimitriou
                if (human) {
978 c45bed88 Kostas Papadimitriou
                    size = util.readablizeBytes(size*1024*1024);
979 c45bed88 Kostas Papadimitriou
                    size_copied = util.readablizeBytes(size_copied*1024*1024);
980 c45bed88 Kostas Papadimitriou
                }
981 8d08f18a Kostas Papadimitriou
982 c45bed88 Kostas Papadimitriou
                callback({'progress': progress, 'size': size, 'copy': size_copied})
983 c45bed88 Kostas Papadimitriou
            }, this));
984 8d08f18a Kostas Papadimitriou
        },
985 8d08f18a Kostas Papadimitriou
986 1f7ea2f5 Kostas Papadimitriou
        start_stats_update: function(force_if_empty) {
987 2c9bfad1 Kostas Papadimitriou
            var prev_state = this.do_update_stats;
988 2c9bfad1 Kostas Papadimitriou
989 2c9bfad1 Kostas Papadimitriou
            this.do_update_stats = true;
990 1f7ea2f5 Kostas Papadimitriou
            
991 2c9bfad1 Kostas Papadimitriou
            // fetcher initialized ??
992 2c9bfad1 Kostas Papadimitriou
            if (!this.stats_fetcher) {
993 2c9bfad1 Kostas Papadimitriou
                this.init_stats_intervals();
994 2c9bfad1 Kostas Papadimitriou
            }
995 2c9bfad1 Kostas Papadimitriou
996 1f7ea2f5 Kostas Papadimitriou
997 2c9bfad1 Kostas Papadimitriou
            // fetcher running ???
998 2c9bfad1 Kostas Papadimitriou
            if (!this.stats_fetcher.running || !prev_state) {
999 2c9bfad1 Kostas Papadimitriou
                this.stats_fetcher.start();
1000 2c9bfad1 Kostas Papadimitriou
            }
1001 1f7ea2f5 Kostas Papadimitriou
1002 1f7ea2f5 Kostas Papadimitriou
            if (force_if_empty && this.get("stats") == undefined) {
1003 1f7ea2f5 Kostas Papadimitriou
                this.update_stats(true);
1004 1f7ea2f5 Kostas Papadimitriou
            }
1005 2c9bfad1 Kostas Papadimitriou
        },
1006 2c9bfad1 Kostas Papadimitriou
1007 2c9bfad1 Kostas Papadimitriou
        stop_stats_update: function(stop_calls) {
1008 2c9bfad1 Kostas Papadimitriou
            this.do_update_stats = false;
1009 2c9bfad1 Kostas Papadimitriou
1010 2c9bfad1 Kostas Papadimitriou
            if (stop_calls) {
1011 2c9bfad1 Kostas Papadimitriou
                this.stats_fetcher.stop();
1012 2c9bfad1 Kostas Papadimitriou
            }
1013 2c9bfad1 Kostas Papadimitriou
        },
1014 2c9bfad1 Kostas Papadimitriou
1015 8d08f18a Kostas Papadimitriou
        // clear and reinitialize update interval
1016 8d08f18a Kostas Papadimitriou
        init_stats_intervals: function (interval) {
1017 96d725ac Kostas Papadimitriou
            this.stats_fetcher = this.get_stats_fetcher(this.stats_update_interval);
1018 96d725ac Kostas Papadimitriou
            this.stats_fetcher.start();
1019 8d08f18a Kostas Papadimitriou
        },
1020 8d08f18a Kostas Papadimitriou
        
1021 96d725ac Kostas Papadimitriou
        get_stats_fetcher: function(timeout) {
1022 96d725ac Kostas Papadimitriou
            var cb = _.bind(function(data){
1023 96d725ac Kostas Papadimitriou
                this.update_stats();
1024 96d725ac Kostas Papadimitriou
            }, this);
1025 258235f4 Kostas Papadimitriou
            var fetcher = new snf.api.updateHandler({'callback': cb, interval: timeout, id:'stats'});
1026 96d725ac Kostas Papadimitriou
            return fetcher;
1027 96d725ac Kostas Papadimitriou
        },
1028 96d725ac Kostas Papadimitriou
1029 8d08f18a Kostas Papadimitriou
        // do the api call
1030 8d08f18a Kostas Papadimitriou
        update_stats: function(force) {
1031 8d08f18a Kostas Papadimitriou
            // do not update stats if flag not set
1032 1f7ea2f5 Kostas Papadimitriou
            if ((!this.do_update_stats && !force) || this.updating_stats) {
1033 8d08f18a Kostas Papadimitriou
                return;
1034 8d08f18a Kostas Papadimitriou
            }
1035 96d725ac Kostas Papadimitriou
1036 8d08f18a Kostas Papadimitriou
            // make the api call, execute handle_stats_update on sucess
1037 8d08f18a Kostas Papadimitriou
            // TODO: onError handler ???
1038 8d08f18a Kostas Papadimitriou
            stats_url = this.url() + "/stats";
1039 1f7ea2f5 Kostas Papadimitriou
            this.updating_stats = true;
1040 258235f4 Kostas Papadimitriou
            this.sync("read", this, {
1041 96d725ac Kostas Papadimitriou
                handles_error:true, 
1042 96d725ac Kostas Papadimitriou
                url: stats_url, 
1043 96d725ac Kostas Papadimitriou
                refresh:true, 
1044 96d725ac Kostas Papadimitriou
                success: _.bind(this.handle_stats_update, this),
1045 ec511098 Kostas Papadimitriou
                error: _.bind(this.handle_stats_error, this),
1046 1f7ea2f5 Kostas Papadimitriou
                complete: _.bind(function(){this.updating_stats = false;}, this),
1047 ec511098 Kostas Papadimitriou
                critical: false,
1048 0375f6c5 Kostas Papadimitriou
                log_error: false,
1049 0375f6c5 Kostas Papadimitriou
                skips_timeouts: true
1050 96d725ac Kostas Papadimitriou
            });
1051 96d725ac Kostas Papadimitriou
        },
1052 96d725ac Kostas Papadimitriou
1053 45b964d3 Kostas Papadimitriou
        get_attachment: function(id) {
1054 45b964d3 Kostas Papadimitriou
          var attachment = undefined;
1055 45b964d3 Kostas Papadimitriou
          _.each(this.get("attachments"), function(a) {
1056 45b964d3 Kostas Papadimitriou
            if (a.id == id) {
1057 45b964d3 Kostas Papadimitriou
              attachment = a;
1058 45b964d3 Kostas Papadimitriou
            }
1059 45b964d3 Kostas Papadimitriou
          });
1060 45b964d3 Kostas Papadimitriou
          return attachment
1061 8d08f18a Kostas Papadimitriou
        },
1062 45b964d3 Kostas Papadimitriou
1063 96d725ac Kostas Papadimitriou
        _set_stats: function(stats) {
1064 96d725ac Kostas Papadimitriou
            var silent = silent === undefined ? false : silent;
1065 96d725ac Kostas Papadimitriou
            // unavailable stats while building
1066 96d725ac Kostas Papadimitriou
            if (this.get("status") == "BUILD") { 
1067 96d725ac Kostas Papadimitriou
                this.stats_available = false;
1068 96d725ac Kostas Papadimitriou
            } else { this.stats_available = true; }
1069 96d725ac Kostas Papadimitriou
1070 96d725ac Kostas Papadimitriou
            if (this.get("status") == "DESTROY") { this.stats_available = false; }
1071 96d725ac Kostas Papadimitriou
            
1072 96d725ac Kostas Papadimitriou
            this.set({stats: stats}, {silent:true});
1073 96d725ac Kostas Papadimitriou
            this.trigger("stats:update", stats);
1074 96d725ac Kostas Papadimitriou
        },
1075 96d725ac Kostas Papadimitriou
1076 96d725ac Kostas Papadimitriou
        unbind: function() {
1077 96d725ac Kostas Papadimitriou
            models.VM.__super__.unbind.apply(this, arguments);
1078 96d725ac Kostas Papadimitriou
        },
1079 a37c5497 Kostas Papadimitriou
        
1080 a37c5497 Kostas Papadimitriou
        can_connect: function() {
1081 a37c5497 Kostas Papadimitriou
          return _.contains(["ACTIVE", "STOPPED"], this.get("status"))
1082 a37c5497 Kostas Papadimitriou
        },
1083 96d725ac Kostas Papadimitriou
1084 69dac1ba Kostas Papadimitriou
        can_disconnect: function() {
1085 69dac1ba Kostas Papadimitriou
          return _.contains(["ACTIVE", "STOPPED"], this.get("status"))
1086 69dac1ba Kostas Papadimitriou
        },
1087 69dac1ba Kostas Papadimitriou
1088 ab3df8df Kostas Papadimitriou
        can_resize: function() {
1089 ab3df8df Kostas Papadimitriou
          return this.get('status') == 'STOPPED';
1090 ab3df8df Kostas Papadimitriou
        },
1091 ab3df8df Kostas Papadimitriou
1092 96d725ac Kostas Papadimitriou
        handle_stats_error: function() {
1093 96d725ac Kostas Papadimitriou
            stats = {};
1094 96d725ac Kostas Papadimitriou
            _.each(['cpuBar', 'cpuTimeSeries', 'netBar', 'netTimeSeries'], function(k) {
1095 96d725ac Kostas Papadimitriou
                stats[k] = false;
1096 96d725ac Kostas Papadimitriou
            });
1097 96d725ac Kostas Papadimitriou
1098 96d725ac Kostas Papadimitriou
            this.set({'stats': stats});
1099 96d725ac Kostas Papadimitriou
        },
1100 96d725ac Kostas Papadimitriou
1101 8d08f18a Kostas Papadimitriou
        // this method gets executed after a successful vm stats api call
1102 8d08f18a Kostas Papadimitriou
        handle_stats_update: function(data) {
1103 96d725ac Kostas Papadimitriou
            var self = this;
1104 8d08f18a Kostas Papadimitriou
            // avoid browser caching
1105 96d725ac Kostas Papadimitriou
            
1106 8d08f18a Kostas Papadimitriou
            if (data.stats && _.size(data.stats) > 0) {
1107 8d08f18a Kostas Papadimitriou
                var ts = $.now();
1108 8d08f18a Kostas Papadimitriou
                var stats = data.stats;
1109 96d725ac Kostas Papadimitriou
                var images_loaded = 0;
1110 96d725ac Kostas Papadimitriou
                var images = {};
1111 96d725ac Kostas Papadimitriou
1112 96d725ac Kostas Papadimitriou
                function check_images_loaded() {
1113 96d725ac Kostas Papadimitriou
                    images_loaded++;
1114 96d725ac Kostas Papadimitriou
1115 96d725ac Kostas Papadimitriou
                    if (images_loaded == 4) {
1116 96d725ac Kostas Papadimitriou
                        self._set_stats(images);
1117 96d725ac Kostas Papadimitriou
                    }
1118 96d725ac Kostas Papadimitriou
                }
1119 8d08f18a Kostas Papadimitriou
                _.each(['cpuBar', 'cpuTimeSeries', 'netBar', 'netTimeSeries'], function(k) {
1120 96d725ac Kostas Papadimitriou
                    
1121 8d08f18a Kostas Papadimitriou
                    stats[k] = stats[k] + "?_=" + ts;
1122 96d725ac Kostas Papadimitriou
                    
1123 96d725ac Kostas Papadimitriou
                    var stat = k.slice(0,3);
1124 96d725ac Kostas Papadimitriou
                    var type = k.slice(3,6) == "Bar" ? "bar" : "time";
1125 96d725ac Kostas Papadimitriou
                    var img = $("<img />");
1126 96d725ac Kostas Papadimitriou
                    var val = stats[k];
1127 96d725ac Kostas Papadimitriou
                    
1128 96d725ac Kostas Papadimitriou
                    // load stat image to a temporary dom element
1129 96d725ac Kostas Papadimitriou
                    // update model stats on image load/error events
1130 96d725ac Kostas Papadimitriou
                    img.load(function() {
1131 96d725ac Kostas Papadimitriou
                        images[k] = val;
1132 96d725ac Kostas Papadimitriou
                        check_images_loaded();
1133 96d725ac Kostas Papadimitriou
                    });
1134 96d725ac Kostas Papadimitriou
1135 96d725ac Kostas Papadimitriou
                    img.error(function() {
1136 96d725ac Kostas Papadimitriou
                        images[stat + type] = false;
1137 96d725ac Kostas Papadimitriou
                        check_images_loaded();
1138 96d725ac Kostas Papadimitriou
                    });
1139 96d725ac Kostas Papadimitriou
1140 96d725ac Kostas Papadimitriou
                    img.attr({'src': stats[k]});
1141 8d08f18a Kostas Papadimitriou
                })
1142 8d08f18a Kostas Papadimitriou
                data.stats = stats;
1143 8d08f18a Kostas Papadimitriou
            }
1144 96d725ac Kostas Papadimitriou
1145 8d08f18a Kostas Papadimitriou
            // do we need to change the interval ??
1146 8d08f18a Kostas Papadimitriou
            if (data.stats.refresh * 1000 != this.stats_update_interval) {
1147 8d08f18a Kostas Papadimitriou
                this.stats_update_interval = data.stats.refresh * 1000;
1148 1cc6e94f Kostas Papadimitriou
                this.stats_fetcher.interval = this.stats_update_interval;
1149 1cc6e94f Kostas Papadimitriou
                this.stats_fetcher.maximum_interval = this.stats_update_interval;
1150 96d725ac Kostas Papadimitriou
                this.stats_fetcher.stop();
1151 2c9bfad1 Kostas Papadimitriou
                this.stats_fetcher.start(false);
1152 8d08f18a Kostas Papadimitriou
            }
1153 8d08f18a Kostas Papadimitriou
        },
1154 96d725ac Kostas Papadimitriou
1155 8d08f18a Kostas Papadimitriou
        // helper method that sets the do_update_stats
1156 8d08f18a Kostas Papadimitriou
        // in the future this method could also make an api call
1157 8d08f18a Kostas Papadimitriou
        // immediaetly if needed
1158 8d08f18a Kostas Papadimitriou
        enable_stats_update: function() {
1159 8d08f18a Kostas Papadimitriou
            this.do_update_stats = true;
1160 8d08f18a Kostas Papadimitriou
        },
1161 96d725ac Kostas Papadimitriou
        
1162 96d725ac Kostas Papadimitriou
        handle_destroy: function() {
1163 96d725ac Kostas Papadimitriou
            this.stats_fetcher.stop();
1164 96d725ac Kostas Papadimitriou
        },
1165 122850c5 Kostas Papadimitriou
1166 122850c5 Kostas Papadimitriou
        require_reboot: function() {
1167 122850c5 Kostas Papadimitriou
            if (this.is_active()) {
1168 122850c5 Kostas Papadimitriou
                this.set({'reboot_required': true});
1169 122850c5 Kostas Papadimitriou
            }
1170 122850c5 Kostas Papadimitriou
        },
1171 8d08f18a Kostas Papadimitriou
        
1172 8d08f18a Kostas Papadimitriou
        set_pending_action: function(data) {
1173 8d08f18a Kostas Papadimitriou
            this.pending_action = data;
1174 8d08f18a Kostas Papadimitriou
            return data;
1175 8d08f18a Kostas Papadimitriou
        },
1176 8d08f18a Kostas Papadimitriou
1177 8d08f18a Kostas Papadimitriou
        // machine has pending action
1178 8d08f18a Kostas Papadimitriou
        update_pending_action: function(action, force) {
1179 8d08f18a Kostas Papadimitriou
            this.set({pending_action: action});
1180 8d08f18a Kostas Papadimitriou
        },
1181 8d08f18a Kostas Papadimitriou
1182 8d08f18a Kostas Papadimitriou
        clear_pending_action: function() {
1183 8d08f18a Kostas Papadimitriou
            this.set({pending_action: undefined});
1184 8d08f18a Kostas Papadimitriou
        },
1185 8d08f18a Kostas Papadimitriou
1186 8d08f18a Kostas Papadimitriou
        has_pending_action: function() {
1187 8d08f18a Kostas Papadimitriou
            return this.get("pending_action") ? this.get("pending_action") : false;
1188 8d08f18a Kostas Papadimitriou
        },
1189 8d08f18a Kostas Papadimitriou
        
1190 8d08f18a Kostas Papadimitriou
        // machine is active
1191 8d08f18a Kostas Papadimitriou
        is_active: function() {
1192 8d08f18a Kostas Papadimitriou
            return models.VM.ACTIVE_STATES.indexOf(this.state()) > -1;
1193 8d08f18a Kostas Papadimitriou
        },
1194 8d08f18a Kostas Papadimitriou
        
1195 122850c5 Kostas Papadimitriou
        // machine is building 
1196 8d08f18a Kostas Papadimitriou
        is_building: function() {
1197 8d08f18a Kostas Papadimitriou
            return models.VM.BUILDING_STATES.indexOf(this.state()) > -1;
1198 8d08f18a Kostas Papadimitriou
        },
1199 3162bebd Kostas Papadimitriou
        
1200 828f802d Kostas Papadimitriou
        is_rebooting: function() {
1201 828f802d Kostas Papadimitriou
            return this.state() == 'REBOOT';
1202 828f802d Kostas Papadimitriou
        },
1203 828f802d Kostas Papadimitriou
1204 3162bebd Kostas Papadimitriou
        in_error_state: function() {
1205 3162bebd Kostas Papadimitriou
            return this.state() === "ERROR"
1206 3162bebd Kostas Papadimitriou
        },
1207 8d08f18a Kostas Papadimitriou
1208 8d08f18a Kostas Papadimitriou
        // user can connect to machine
1209 8d08f18a Kostas Papadimitriou
        is_connectable: function() {
1210 8d08f18a Kostas Papadimitriou
            return models.VM.CONNECT_STATES.indexOf(this.state()) > -1;
1211 8d08f18a Kostas Papadimitriou
        },
1212 8d08f18a Kostas Papadimitriou
        
1213 8d08f18a Kostas Papadimitriou
        remove_meta: function(key, complete, error) {
1214 d5fd0d3c Kostas Papadimitriou
            var url = this.api_path() + "/metadata/" + key;
1215 258235f4 Kostas Papadimitriou
            this.api_call(url, "delete", undefined, complete, error);
1216 8d08f18a Kostas Papadimitriou
        },
1217 8d08f18a Kostas Papadimitriou
1218 8d08f18a Kostas Papadimitriou
        save_meta: function(meta, complete, error) {
1219 d5fd0d3c Kostas Papadimitriou
            var url = this.api_path() + "/metadata/" + meta.key;
1220 8d08f18a Kostas Papadimitriou
            var payload = {meta:{}};
1221 8d08f18a Kostas Papadimitriou
            payload.meta[meta.key] = meta.value;
1222 9ffd10ce Kostas Papadimitriou
            payload._options = {
1223 9ffd10ce Kostas Papadimitriou
                critical:false, 
1224 9ffd10ce Kostas Papadimitriou
                error_params: {
1225 9ffd10ce Kostas Papadimitriou
                    title: "Machine metadata error",
1226 9ffd10ce Kostas Papadimitriou
                    extra_details: {"Machine id": this.id}
1227 9ffd10ce Kostas Papadimitriou
            }};
1228 8d08f18a Kostas Papadimitriou
1229 258235f4 Kostas Papadimitriou
            this.api_call(url, "update", payload, complete, error);
1230 8d08f18a Kostas Papadimitriou
        },
1231 8d08f18a Kostas Papadimitriou
1232 8d08f18a Kostas Papadimitriou
1233 8d08f18a Kostas Papadimitriou
        // update/get the state of the machine
1234 8d08f18a Kostas Papadimitriou
        state: function() {
1235 8d08f18a Kostas Papadimitriou
            var args = slice.call(arguments);
1236 8d08f18a Kostas Papadimitriou
                
1237 8d08f18a Kostas Papadimitriou
            if (args.length > 0 && models.VM.STATES.indexOf(args[0]) > -1) {
1238 8d08f18a Kostas Papadimitriou
                this.set({'state': args[0]});
1239 8d08f18a Kostas Papadimitriou
            }
1240 8d08f18a Kostas Papadimitriou
1241 8d08f18a Kostas Papadimitriou
            return this.get('state');
1242 8d08f18a Kostas Papadimitriou
        },
1243 8d08f18a Kostas Papadimitriou
        
1244 8d08f18a Kostas Papadimitriou
        // get the state that the api status corresponds to
1245 8d08f18a Kostas Papadimitriou
        state_for_api_status: function(status) {
1246 8d08f18a Kostas Papadimitriou
            return this.state_transition(this.state(), status);
1247 8d08f18a Kostas Papadimitriou
        },
1248 8d08f18a Kostas Papadimitriou
        
1249 8d08f18a Kostas Papadimitriou
        // get transition state for the corresponging api status
1250 8d08f18a Kostas Papadimitriou
        state_transition: function(state, new_status) {
1251 8d08f18a Kostas Papadimitriou
            var statuses = models.VM.STATES_TRANSITIONS[state];
1252 8d08f18a Kostas Papadimitriou
            if (statuses) {
1253 8d08f18a Kostas Papadimitriou
                if (statuses.indexOf(new_status) > -1) {
1254 8d08f18a Kostas Papadimitriou
                    return new_status;
1255 8d08f18a Kostas Papadimitriou
                } else {
1256 8d08f18a Kostas Papadimitriou
                    return state;
1257 8d08f18a Kostas Papadimitriou
                }
1258 8d08f18a Kostas Papadimitriou
            } else {
1259 8d08f18a Kostas Papadimitriou
                return new_status;
1260 8d08f18a Kostas Papadimitriou
            }
1261 8d08f18a Kostas Papadimitriou
        },
1262 8d08f18a Kostas Papadimitriou
        
1263 8d08f18a Kostas Papadimitriou
        // the current vm state is a transition state
1264 8d08f18a Kostas Papadimitriou
        in_transition: function() {
1265 8d08f18a Kostas Papadimitriou
            return models.VM.TRANSITION_STATES.indexOf(this.state()) > -1 || 
1266 8d08f18a Kostas Papadimitriou
                models.VM.TRANSITION_STATES.indexOf(this.get('status')) > -1;
1267 8d08f18a Kostas Papadimitriou
        },
1268 8d08f18a Kostas Papadimitriou
        
1269 8d08f18a Kostas Papadimitriou
        // get image object
1270 c45bed88 Kostas Papadimitriou
        get_image: function(callback) {
1271 cde8cde3 Kostas Papadimitriou
            if (callback == undefined) { callback = function(){} }
1272 0dee4086 Kostas Papadimitriou
            var image = storage.images.get(this.get('image'));
1273 bedfe884 Kostas Papadimitriou
            if (!image) {
1274 0dee4086 Kostas Papadimitriou
                storage.images.update_unknown_id(this.get('image'), callback);
1275 c45bed88 Kostas Papadimitriou
                return;
1276 bedfe884 Kostas Papadimitriou
            }
1277 c45bed88 Kostas Papadimitriou
            callback(image);
1278 bedfe884 Kostas Papadimitriou
            return image;
1279 8d08f18a Kostas Papadimitriou
        },
1280 8d08f18a Kostas Papadimitriou
        
1281 8d08f18a Kostas Papadimitriou
        // get flavor object
1282 8d08f18a Kostas Papadimitriou
        get_flavor: function() {
1283 0dee4086 Kostas Papadimitriou
            var flv = storage.flavors.get(this.get('flavor'));
1284 bedfe884 Kostas Papadimitriou
            if (!flv) {
1285 0dee4086 Kostas Papadimitriou
                storage.flavors.update_unknown_id(this.get('flavor'));
1286 0dee4086 Kostas Papadimitriou
                flv = storage.flavors.get(this.get('flavor'));
1287 bedfe884 Kostas Papadimitriou
            }
1288 bedfe884 Kostas Papadimitriou
            return flv;
1289 8d08f18a Kostas Papadimitriou
        },
1290 8d08f18a Kostas Papadimitriou
1291 ab3df8df Kostas Papadimitriou
        get_resize_flavors: function() {
1292 ab3df8df Kostas Papadimitriou
          var vm_flavor = this.get_flavor();
1293 ab3df8df Kostas Papadimitriou
          var flavors = synnefo.storage.flavors.filter(function(f){
1294 ab3df8df Kostas Papadimitriou
              return f.get('disk_template') ==
1295 ab3df8df Kostas Papadimitriou
              vm_flavor.get('disk_template') && f.get('disk') ==
1296 ab3df8df Kostas Papadimitriou
              vm_flavor.get('disk');
1297 ab3df8df Kostas Papadimitriou
          });
1298 ab3df8df Kostas Papadimitriou
          return flavors;
1299 ab3df8df Kostas Papadimitriou
        },
1300 ab3df8df Kostas Papadimitriou
1301 ab3df8df Kostas Papadimitriou
        get_flavor_quotas: function() {
1302 ab3df8df Kostas Papadimitriou
          var flavor = this.get_flavor();
1303 ab3df8df Kostas Papadimitriou
          return {
1304 ab3df8df Kostas Papadimitriou
            cpu: flavor.get('cpu') + 1, 
1305 ab3df8df Kostas Papadimitriou
            ram: flavor.get_ram_size() + 1, 
1306 ab3df8df Kostas Papadimitriou
            disk:flavor.get_disk_size() + 1
1307 ab3df8df Kostas Papadimitriou
          }
1308 ab3df8df Kostas Papadimitriou
        },
1309 ab3df8df Kostas Papadimitriou
1310 cde8cde3 Kostas Papadimitriou
        get_meta: function(key, deflt) {
1311 0dee4086 Kostas Papadimitriou
            if (this.get('metadata') && this.get('metadata')) {
1312 0dee4086 Kostas Papadimitriou
                if (!this.get('metadata')[key]) { return deflt }
1313 0dee4086 Kostas Papadimitriou
                return _.escape(this.get('metadata')[key]);
1314 88d6d677 Kostas Papadimitriou
            } else {
1315 cde8cde3 Kostas Papadimitriou
                return deflt;
1316 88d6d677 Kostas Papadimitriou
            }
1317 88d6d677 Kostas Papadimitriou
        },
1318 88d6d677 Kostas Papadimitriou
1319 88d6d677 Kostas Papadimitriou
        get_meta_keys: function() {
1320 0dee4086 Kostas Papadimitriou
            if (this.get('metadata') && this.get('metadata')) {
1321 0dee4086 Kostas Papadimitriou
                return _.keys(this.get('metadata'));
1322 88d6d677 Kostas Papadimitriou
            } else {
1323 88d6d677 Kostas Papadimitriou
                return [];
1324 8d08f18a Kostas Papadimitriou
            }
1325 8d08f18a Kostas Papadimitriou
        },
1326 8d08f18a Kostas Papadimitriou
        
1327 8d08f18a Kostas Papadimitriou
        // get metadata OS value
1328 8d08f18a Kostas Papadimitriou
        get_os: function() {
1329 cde8cde3 Kostas Papadimitriou
            var image = this.get_image();
1330 cde8cde3 Kostas Papadimitriou
            return this.get_meta('OS') || (image ? 
1331 cde8cde3 Kostas Papadimitriou
                                            image.get_os() || "okeanos" : "okeanos");
1332 8d08f18a Kostas Papadimitriou
        },
1333 258235f4 Kostas Papadimitriou
1334 43ec1206 Kostas Papadimitriou
        get_gui: function() {
1335 43ec1206 Kostas Papadimitriou
            return this.get_meta('GUI');
1336 43ec1206 Kostas Papadimitriou
        },
1337 126a01f2 Kostas Papadimitriou
        
1338 3796f345 Kostas Papadimitriou
        get_hostname: function() {
1339 3e323ae8 Kostas Papadimitriou
          var hostname = this.get_meta('hostname') || this.get('fqdn');
1340 3796f345 Kostas Papadimitriou
          if (!hostname) {
1341 f5e97e7f Kostas Papadimitriou
            if (synnefo.config.vm_hostname_format) {
1342 f5e97e7f Kostas Papadimitriou
              hostname = synnefo.config.vm_hostname_format.format(this.id);
1343 f5e97e7f Kostas Papadimitriou
            } else {
1344 3e323ae8 Kostas Papadimitriou
              hostname = 'unknown';
1345 f5e97e7f Kostas Papadimitriou
            }
1346 3796f345 Kostas Papadimitriou
          }
1347 3796f345 Kostas Papadimitriou
          return hostname;
1348 3796f345 Kostas Papadimitriou
        },
1349 3796f345 Kostas Papadimitriou
1350 8d08f18a Kostas Papadimitriou
        // get actions that the user can execute
1351 8d08f18a Kostas Papadimitriou
        // depending on the vm state/status
1352 8d08f18a Kostas Papadimitriou
        get_available_actions: function() {
1353 8d08f18a Kostas Papadimitriou
            return models.VM.AVAILABLE_ACTIONS[this.state()];
1354 8d08f18a Kostas Papadimitriou
        },
1355 8d08f18a Kostas Papadimitriou
1356 8d08f18a Kostas Papadimitriou
        set_profile: function(profile, net_id) {
1357 8d08f18a Kostas Papadimitriou
        },
1358 8d08f18a Kostas Papadimitriou
        
1359 8d08f18a Kostas Papadimitriou
        // call rename api
1360 8d08f18a Kostas Papadimitriou
        rename: function(new_name) {
1361 8d08f18a Kostas Papadimitriou
            //this.set({'name': new_name});
1362 8d08f18a Kostas Papadimitriou
            this.sync("update", this, {
1363 9ffd10ce Kostas Papadimitriou
                critical: true,
1364 8d08f18a Kostas Papadimitriou
                data: {
1365 8d08f18a Kostas Papadimitriou
                    'server': {
1366 8d08f18a Kostas Papadimitriou
                        'name': new_name
1367 8d08f18a Kostas Papadimitriou
                    }
1368 8d08f18a Kostas Papadimitriou
                }, 
1369 8d08f18a Kostas Papadimitriou
                success: _.bind(function(){
1370 8d08f18a Kostas Papadimitriou
                    snf.api.trigger("call");
1371 8d08f18a Kostas Papadimitriou
                }, this)
1372 8d08f18a Kostas Papadimitriou
            });
1373 8d08f18a Kostas Papadimitriou
        },
1374 8d08f18a Kostas Papadimitriou
        
1375 8d08f18a Kostas Papadimitriou
        get_console_url: function(data) {
1376 8d08f18a Kostas Papadimitriou
            var url_params = {
1377 8d08f18a Kostas Papadimitriou
                machine: this.get("name"),
1378 d7d154c9 Kostas Papadimitriou
                host_ip: this.get_hostname(),
1379 d7d154c9 Kostas Papadimitriou
                host_ip_v6: this.get_hostname(),
1380 8d08f18a Kostas Papadimitriou
                host: data.host,
1381 8d08f18a Kostas Papadimitriou
                port: data.port,
1382 8d08f18a Kostas Papadimitriou
                password: data.password
1383 8d08f18a Kostas Papadimitriou
            }
1384 0c2166b9 Kostas Papadimitriou
            return synnefo.config.ui_console_url + '?' + $.param(url_params);
1385 8d08f18a Kostas Papadimitriou
        },
1386 e4330db2 Kostas Papadimitriou
        
1387 e4330db2 Kostas Papadimitriou
        set_firewall: function(nic, value, success_cb, error_cb) {
1388 e4330db2 Kostas Papadimitriou
          var success = function() { success_cb() }
1389 e4330db2 Kostas Papadimitriou
          var error = function() { error_cb() }
1390 e4330db2 Kostas Papadimitriou
          var data = {'nic': nic.id, 'profile': value, 'display': true};
1391 e4330db2 Kostas Papadimitriou
          var url = this.url() + "/action";
1392 e4330db2 Kostas Papadimitriou
          //var params = {skip_api_error: false, display: true};
1393 e4330db2 Kostas Papadimitriou
          this.call('firewallProfile', success, error, data);
1394 e4330db2 Kostas Papadimitriou
        },
1395 e4330db2 Kostas Papadimitriou
1396 45b964d3 Kostas Papadimitriou
        connect_floating_ip: function(ip, cb) {
1397 69dac1ba Kostas Papadimitriou
          this.set({'status': 'CONNECTING'});
1398 02effd9c Kostas Papadimitriou
          synnefo.storage.ports.create({
1399 02effd9c Kostas Papadimitriou
            port: {
1400 02effd9c Kostas Papadimitriou
              network_id: ip.get('floating_network_id'),
1401 02effd9c Kostas Papadimitriou
              device_id: this.id,
1402 02effd9c Kostas Papadimitriou
              fixed_ips: [{'ip_address': ip.get('floating_ip_address')}]
1403 02effd9c Kostas Papadimitriou
            }
1404 02effd9c Kostas Papadimitriou
          }, {complete: cb, skip_api_error: false})
1405 45b964d3 Kostas Papadimitriou
        },
1406 8d08f18a Kostas Papadimitriou
1407 8d08f18a Kostas Papadimitriou
        // action helper
1408 738a9b18 Kostas Papadimitriou
        call: function(action_name, success, error, params) {
1409 8d08f18a Kostas Papadimitriou
            var id_param = [this.id];
1410 738a9b18 Kostas Papadimitriou
            
1411 738a9b18 Kostas Papadimitriou
            params = params || {};
1412 8d08f18a Kostas Papadimitriou
            success = success || function() {};
1413 8d08f18a Kostas Papadimitriou
            error = error || function() {};
1414 8d08f18a Kostas Papadimitriou
1415 8d08f18a Kostas Papadimitriou
            var self = this;
1416 8d08f18a Kostas Papadimitriou
1417 8d08f18a Kostas Papadimitriou
            switch(action_name) {
1418 8d08f18a Kostas Papadimitriou
                case 'start':
1419 8d08f18a Kostas Papadimitriou
                    this.__make_api_call(this.get_action_url(), // vm actions url
1420 8d08f18a Kostas Papadimitriou
                                         "create", // create so that sync later uses POST to make the call
1421 8d08f18a Kostas Papadimitriou
                                         {start:{}}, // payload
1422 8d08f18a Kostas Papadimitriou
                                         function() {
1423 8d08f18a Kostas Papadimitriou
                                             // set state after successful call
1424 8d08f18a Kostas Papadimitriou
                                             self.state("START"); 
1425 8d08f18a Kostas Papadimitriou
                                             success.apply(this, arguments);
1426 8d08f18a Kostas Papadimitriou
                                             snf.api.trigger("call");
1427 8d08f18a Kostas Papadimitriou
                                         },  
1428 738a9b18 Kostas Papadimitriou
                                         error, 'start', params);
1429 8d08f18a Kostas Papadimitriou
                    break;
1430 8d08f18a Kostas Papadimitriou
                case 'reboot':
1431 8d08f18a Kostas Papadimitriou
                    this.__make_api_call(this.get_action_url(), // vm actions url
1432 8d08f18a Kostas Papadimitriou
                                         "create", // create so that sync later uses POST to make the call
1433 bbae3e45 Christos Stavrakakis
                                         {reboot:{}}, // payload
1434 8d08f18a Kostas Papadimitriou
                                         function() {
1435 8d08f18a Kostas Papadimitriou
                                             // set state after successful call
1436 8d08f18a Kostas Papadimitriou
                                             self.state("REBOOT"); 
1437 8d08f18a Kostas Papadimitriou
                                             success.apply(this, arguments)
1438 8d08f18a Kostas Papadimitriou
                                             snf.api.trigger("call");
1439 122850c5 Kostas Papadimitriou
                                             self.set({'reboot_required': false});
1440 8d08f18a Kostas Papadimitriou
                                         },
1441 738a9b18 Kostas Papadimitriou
                                         error, 'reboot', params);
1442 8d08f18a Kostas Papadimitriou
                    break;
1443 8d08f18a Kostas Papadimitriou
                case 'shutdown':
1444 8d08f18a Kostas Papadimitriou
                    this.__make_api_call(this.get_action_url(), // vm actions url
1445 8d08f18a Kostas Papadimitriou
                                         "create", // create so that sync later uses POST to make the call
1446 8d08f18a Kostas Papadimitriou
                                         {shutdown:{}}, // payload
1447 8d08f18a Kostas Papadimitriou
                                         function() {
1448 8d08f18a Kostas Papadimitriou
                                             // set state after successful call
1449 8d08f18a Kostas Papadimitriou
                                             self.state("SHUTDOWN"); 
1450 8d08f18a Kostas Papadimitriou
                                             success.apply(this, arguments)
1451 8d08f18a Kostas Papadimitriou
                                             snf.api.trigger("call");
1452 8d08f18a Kostas Papadimitriou
                                         },  
1453 738a9b18 Kostas Papadimitriou
                                         error, 'shutdown', params);
1454 8d08f18a Kostas Papadimitriou
                    break;
1455 8d08f18a Kostas Papadimitriou
                case 'console':
1456 1fc7640d Kostas Papadimitriou
                    this.__make_api_call(this.url() + "/action", "create", 
1457 1fc7640d Kostas Papadimitriou
                                         {'console': {'type':'vnc'}}, 
1458 1fc7640d Kostas Papadimitriou
                                         function(data) {
1459 8d08f18a Kostas Papadimitriou
                        var cons_data = data.console;
1460 8d08f18a Kostas Papadimitriou
                        success.apply(this, [cons_data]);
1461 738a9b18 Kostas Papadimitriou
                    }, undefined, 'console', params)
1462 8d08f18a Kostas Papadimitriou
                    break;
1463 8d08f18a Kostas Papadimitriou
                case 'destroy':
1464 8d08f18a Kostas Papadimitriou
                    this.__make_api_call(this.url(), // vm actions url
1465 8d08f18a Kostas Papadimitriou
                                         "delete", // create so that sync later uses POST to make the call
1466 8d08f18a Kostas Papadimitriou
                                         undefined, // payload
1467 8d08f18a Kostas Papadimitriou
                                         function() {
1468 8d08f18a Kostas Papadimitriou
                                             // set state after successful call
1469 8d08f18a Kostas Papadimitriou
                                             self.state('DESTROY');
1470 b14e3b9e Kostas Papadimitriou
                                             success.apply(this, arguments);
1471 426e1fb9 Kostas Papadimitriou
                                             synnefo.storage.quotas.get('cyclades.vm').decrease();
1472 b14e3b9e Kostas Papadimitriou
1473 8d08f18a Kostas Papadimitriou
                                         },  
1474 738a9b18 Kostas Papadimitriou
                                         error, 'destroy', params);
1475 8d08f18a Kostas Papadimitriou
                    break;
1476 ab3df8df Kostas Papadimitriou
                case 'resize':
1477 ab3df8df Kostas Papadimitriou
                    this.__make_api_call(this.get_action_url(), // vm actions url
1478 ab3df8df Kostas Papadimitriou
                                         "create", // create so that sync later uses POST to make the call
1479 ab3df8df Kostas Papadimitriou
                                         {resize: {flavorRef:params.flavor}}, // payload
1480 ab3df8df Kostas Papadimitriou
                                         function() {
1481 a3ac649e Kostas Papadimitriou
                                             self.state('RESIZE');
1482 a3ac649e Kostas Papadimitriou
                                             success.apply(this, arguments);
1483 ab3df8df Kostas Papadimitriou
                                             snf.api.trigger("call");
1484 ab3df8df Kostas Papadimitriou
                                         },  
1485 ab3df8df Kostas Papadimitriou
                                         error, 'resize', params);
1486 ab3df8df Kostas Papadimitriou
                    break;
1487 ab3df8df Kostas Papadimitriou
                case 'destroy':
1488 ab3df8df Kostas Papadimitriou
                    this.__make_api_call(this.url(), // vm actions url
1489 ab3df8df Kostas Papadimitriou
                                         "delete", // create so that sync later uses POST to make the call
1490 ab3df8df Kostas Papadimitriou
                                         undefined, // payload
1491 ab3df8df Kostas Papadimitriou
                                         function() {
1492 ab3df8df Kostas Papadimitriou
                                             // set state after successful call
1493 ab3df8df Kostas Papadimitriou
                                             self.state('DESTROY');
1494 ab3df8df Kostas Papadimitriou
                                             success.apply(this, arguments);
1495 ab3df8df Kostas Papadimitriou
                                             synnefo.storage.quotas.get('cyclades.vm').decrease();
1496 ab3df8df Kostas Papadimitriou
1497 ab3df8df Kostas Papadimitriou
                                         },  
1498 ab3df8df Kostas Papadimitriou
                                         error, 'destroy', params);
1499 ab3df8df Kostas Papadimitriou
                    break;
1500 e4330db2 Kostas Papadimitriou
                case 'firewallProfile':
1501 e4330db2 Kostas Papadimitriou
                    this.__make_api_call(this.get_action_url(), // vm actions url
1502 e4330db2 Kostas Papadimitriou
                                         "create",
1503 e4330db2 Kostas Papadimitriou
                                         {firewallProfile:{nic:params.nic, profile:params.profile}}, // payload
1504 e4330db2 Kostas Papadimitriou
                                         function() {
1505 e4330db2 Kostas Papadimitriou
                                             success.apply(this, arguments);
1506 e4330db2 Kostas Papadimitriou
                                             snf.api.trigger("call");
1507 e4330db2 Kostas Papadimitriou
                                         },  
1508 e4330db2 Kostas Papadimitriou
                                         error, 'start', params);
1509 e4330db2 Kostas Papadimitriou
                    break;
1510 8d08f18a Kostas Papadimitriou
                default:
1511 8d08f18a Kostas Papadimitriou
                    throw "Invalid VM action ("+action_name+")";
1512 8d08f18a Kostas Papadimitriou
            }
1513 8d08f18a Kostas Papadimitriou
        },
1514 8d08f18a Kostas Papadimitriou
        
1515 1fc7640d Kostas Papadimitriou
        __make_api_call: function(url, method, data, success, error, action, 
1516 1fc7640d Kostas Papadimitriou
                                  extra_params) {
1517 8d08f18a Kostas Papadimitriou
            var self = this;
1518 8d08f18a Kostas Papadimitriou
            error = error || function(){};
1519 8d08f18a Kostas Papadimitriou
            success = success || function(){};
1520 8d08f18a Kostas Papadimitriou
1521 8d08f18a Kostas Papadimitriou
            var params = {
1522 8d08f18a Kostas Papadimitriou
                url: url,
1523 8d08f18a Kostas Papadimitriou
                data: data,
1524 1fc7640d Kostas Papadimitriou
                success: function() { 
1525 1fc7640d Kostas Papadimitriou
                  self.handle_action_succeed.apply(self, arguments); 
1526 1fc7640d Kostas Papadimitriou
                  success.apply(this, arguments)
1527 1fc7640d Kostas Papadimitriou
                },
1528 45b964d3 Kostas Papadimitriou
                error: function() { 
1529 45b964d3 Kostas Papadimitriou
                  self.handle_action_fail.apply(self, arguments);
1530 45b964d3 Kostas Papadimitriou
                  error.apply(this, arguments)
1531 45b964d3 Kostas Papadimitriou
                },
1532 edd1d565 Kostas Papadimitriou
                error_params: { ns: "Machines actions", 
1533 9ffd10ce Kostas Papadimitriou
                                title: "'" + this.get("name") + "'" + " " + action + " failed", 
1534 45b964d3 Kostas Papadimitriou
                                extra_details: {
1535 45b964d3 Kostas Papadimitriou
                                  'Machine ID': this.id, 
1536 45b964d3 Kostas Papadimitriou
                                  'URL': url, 
1537 45b964d3 Kostas Papadimitriou
                                  'Action': action || "undefined" },
1538 6a3a5bf7 Kostas Papadimitriou
                                allow_reload: false
1539 6a3a5bf7 Kostas Papadimitriou
                              },
1540 9ce969a7 Kostas Papadimitriou
                display: false,
1541 9ce969a7 Kostas Papadimitriou
                critical: false
1542 8d08f18a Kostas Papadimitriou
            }
1543 1fc7640d Kostas Papadimitriou
            _.extend(params, extra_params);
1544 8d08f18a Kostas Papadimitriou
            this.sync(method, this, params);
1545 8d08f18a Kostas Papadimitriou
        },
1546 8d08f18a Kostas Papadimitriou
1547 8d08f18a Kostas Papadimitriou
        handle_action_succeed: function() {
1548 8d08f18a Kostas Papadimitriou
            this.trigger("action:success", arguments);
1549 8d08f18a Kostas Papadimitriou
        },
1550 6a3a5bf7 Kostas Papadimitriou
        
1551 6a3a5bf7 Kostas Papadimitriou
        reset_action_error: function() {
1552 6a3a5bf7 Kostas Papadimitriou
            this.action_error = false;
1553 6a3a5bf7 Kostas Papadimitriou
            this.trigger("action:fail:reset", this.action_error);
1554 6a3a5bf7 Kostas Papadimitriou
        },
1555 8d08f18a Kostas Papadimitriou
1556 8d08f18a Kostas Papadimitriou
        handle_action_fail: function() {
1557 6a3a5bf7 Kostas Papadimitriou
            this.action_error = arguments;
1558 8d08f18a Kostas Papadimitriou
            this.trigger("action:fail", arguments);
1559 8d08f18a Kostas Papadimitriou
        },
1560 8d08f18a Kostas Papadimitriou
1561 8d08f18a Kostas Papadimitriou
        get_action_url: function(name) {
1562 8d08f18a Kostas Papadimitriou
            return this.url() + "/action";
1563 1c922789 Kostas Papadimitriou
        },
1564 1c922789 Kostas Papadimitriou
1565 1e882dd7 Kostas Papadimitriou
        get_diagnostics_url: function() {
1566 1e882dd7 Kostas Papadimitriou
            return this.url() + "/diagnostics";
1567 1e882dd7 Kostas Papadimitriou
        },
1568 1e882dd7 Kostas Papadimitriou
1569 a6213c91 Kostas Papadimitriou
        get_users: function() {
1570 a6213c91 Kostas Papadimitriou
            var image;
1571 a6213c91 Kostas Papadimitriou
            var users = [];
1572 a6213c91 Kostas Papadimitriou
            try {
1573 a6213c91 Kostas Papadimitriou
              var users = this.get_meta('users').split(" ");
1574 a6213c91 Kostas Papadimitriou
            } catch (err) { users = null }
1575 a6213c91 Kostas Papadimitriou
            if (!users) {
1576 a6213c91 Kostas Papadimitriou
              image = this.get_image();
1577 a6213c91 Kostas Papadimitriou
              if (image) {
1578 a6213c91 Kostas Papadimitriou
                  users = image.get_created_users();
1579 a6213c91 Kostas Papadimitriou
              }
1580 a6213c91 Kostas Papadimitriou
            }
1581 a6213c91 Kostas Papadimitriou
            return users;
1582 a6213c91 Kostas Papadimitriou
        },
1583 a6213c91 Kostas Papadimitriou
1584 1c922789 Kostas Papadimitriou
        get_connection_info: function(host_os, success, error) {
1585 0c2166b9 Kostas Papadimitriou
            var url = synnefo.config.ui_connect_url;
1586 a6213c91 Kostas Papadimitriou
            var users = this.get_users();
1587 a6213c91 Kostas Papadimitriou
1588 1c922789 Kostas Papadimitriou
            params = {
1589 d7d154c9 Kostas Papadimitriou
                ip_address: this.get_hostname(),
1590 3796f345 Kostas Papadimitriou
                hostname: this.get_hostname(),
1591 1c922789 Kostas Papadimitriou
                os: this.get_os(),
1592 1c922789 Kostas Papadimitriou
                host_os: host_os,
1593 1c922789 Kostas Papadimitriou
                srv: this.id
1594 1c922789 Kostas Papadimitriou
            }
1595 a6213c91 Kostas Papadimitriou
            
1596 a6213c91 Kostas Papadimitriou
            if (users.length) { 
1597 a6213c91 Kostas Papadimitriou
                params['username'] = _.last(users)
1598 a6213c91 Kostas Papadimitriou
            }
1599 1c922789 Kostas Papadimitriou
1600 1c922789 Kostas Papadimitriou
            url = url + "?" + $.param(params);
1601 1c922789 Kostas Papadimitriou
1602 1c922789 Kostas Papadimitriou
            var ajax = snf.api.sync("read", undefined, { url: url, 
1603 1c922789 Kostas Papadimitriou
                                                         error:error, 
1604 1c922789 Kostas Papadimitriou
                                                         success:success, 
1605 1c922789 Kostas Papadimitriou
                                                         handles_error:1});
1606 8d08f18a Kostas Papadimitriou
        }
1607 d7d154c9 Kostas Papadimitriou
    });
1608 8d08f18a Kostas Papadimitriou
    
1609 8d08f18a Kostas Papadimitriou
    models.VM.ACTIONS = [
1610 8d08f18a Kostas Papadimitriou
        'start',
1611 8d08f18a Kostas Papadimitriou
        'shutdown',
1612 8d08f18a Kostas Papadimitriou
        'reboot',
1613 0f7214b3 Kostas Papadimitriou
        'console',
1614 a3ac649e Kostas Papadimitriou
        'destroy',
1615 a3ac649e Kostas Papadimitriou
        'resize'
1616 8d08f18a Kostas Papadimitriou
    ]
1617 8d08f18a Kostas Papadimitriou
1618 a3ac649e Kostas Papadimitriou
    models.VM.TASK_STATE_STATUS_MAP = {
1619 a3ac649e Kostas Papadimitriou
      'BULDING': 'BUILD',
1620 a3ac649e Kostas Papadimitriou
      'REBOOTING': 'REBOOT',
1621 a3ac649e Kostas Papadimitriou
      'STOPPING': 'SHUTDOWN',
1622 a3ac649e Kostas Papadimitriou
      'STARTING': 'START',
1623 a3ac649e Kostas Papadimitriou
      'RESIZING': 'RESIZE',
1624 a3ac649e Kostas Papadimitriou
      'CONNECTING': 'CONNECT',
1625 a3ac649e Kostas Papadimitriou
      'DISCONNECTING': 'DISCONNECT',
1626 a3ac649e Kostas Papadimitriou
      'DESTROYING': 'DESTROY'
1627 a3ac649e Kostas Papadimitriou
    }
1628 a3ac649e Kostas Papadimitriou
1629 8d08f18a Kostas Papadimitriou
    models.VM.AVAILABLE_ACTIONS = {
1630 d632e425 Kostas Papadimitriou
        'UNKNWON'       : ['destroy'],
1631 d632e425 Kostas Papadimitriou
        'BUILD'         : ['destroy'],
1632 d632e425 Kostas Papadimitriou
        'REBOOT'        : ['destroy'],
1633 13925182 Kostas Papadimitriou
        'STOPPED'       : ['start', 'destroy', 'resize'],
1634 13925182 Kostas Papadimitriou
        'ACTIVE'        : ['shutdown', 'destroy', 'reboot', 'console', 'resize'],
1635 8d08f18a Kostas Papadimitriou
        'ERROR'         : ['destroy'],
1636 d632e425 Kostas Papadimitriou
        'DELETED'       : ['destroy'],
1637 d632e425 Kostas Papadimitriou
        'DESTROY'       : ['destroy'],
1638 d632e425 Kostas Papadimitriou
        'SHUTDOWN'      : ['destroy'],
1639 d632e425 Kostas Papadimitriou
        'START'         : ['destroy'],
1640 d632e425 Kostas Papadimitriou
        'CONNECT'       : ['destroy'],
1641 d632e425 Kostas Papadimitriou
        'DISCONNECT'    : ['destroy'],
1642 d632e425 Kostas Papadimitriou
        'RESIZE'        : ['destroy']
1643 8d08f18a Kostas Papadimitriou
    }
1644 13925182 Kostas Papadimitriou
    
1645 13925182 Kostas Papadimitriou
    models.VM.AVAILABLE_ACTIONS_INACTIVE = {
1646 13925182 Kostas Papadimitriou
      'resize': ['ACTIVE']
1647 13925182 Kostas Papadimitriou
    }
1648 8d08f18a Kostas Papadimitriou
1649 8d08f18a Kostas Papadimitriou
    // api status values
1650 8d08f18a Kostas Papadimitriou
    models.VM.STATUSES = [
1651 8d08f18a Kostas Papadimitriou
        'UNKNWON',
1652 8d08f18a Kostas Papadimitriou
        'BUILD',
1653 8d08f18a Kostas Papadimitriou
        'REBOOT',
1654 8d08f18a Kostas Papadimitriou
        'STOPPED',
1655 8d08f18a Kostas Papadimitriou
        'ACTIVE',
1656 8d08f18a Kostas Papadimitriou
        'ERROR',
1657 a3ac649e Kostas Papadimitriou
        'DELETED',
1658 a3ac649e Kostas Papadimitriou
        'RESIZE'
1659 8d08f18a Kostas Papadimitriou
    ]
1660 8d08f18a Kostas Papadimitriou
1661 8d08f18a Kostas Papadimitriou
    // api status values
1662 8d08f18a Kostas Papadimitriou
    models.VM.CONNECT_STATES = [
1663 8d08f18a Kostas Papadimitriou
        'ACTIVE',
1664 8d08f18a Kostas Papadimitriou
        'REBOOT',
1665 df12e032 Kostas Papadimitriou
        'SHUTDOWN'
1666 8d08f18a Kostas Papadimitriou
    ]
1667 8d08f18a Kostas Papadimitriou
1668 8d08f18a Kostas Papadimitriou
    // vm states
1669 8d08f18a Kostas Papadimitriou
    models.VM.STATES = models.VM.STATUSES.concat([
1670 8d08f18a Kostas Papadimitriou
        'DESTROY',
1671 8d08f18a Kostas Papadimitriou
        'SHUTDOWN',
1672 8d08f18a Kostas Papadimitriou
        'START',
1673 8d08f18a Kostas Papadimitriou
        'CONNECT',
1674 8d08f18a Kostas Papadimitriou
        'DISCONNECT',
1675 a3ac649e Kostas Papadimitriou
        'FIREWALL',
1676 a3ac649e Kostas Papadimitriou
        'RESIZE'
1677 8d08f18a Kostas Papadimitriou
    ]);
1678 8d08f18a Kostas Papadimitriou
    
1679 8d08f18a Kostas Papadimitriou
    models.VM.STATES_TRANSITIONS = {
1680 643de8c0 Kostas Papadimitriou
        'DESTROY' : ['DELETED'],
1681 8d08f18a Kostas Papadimitriou
        'SHUTDOWN': ['ERROR', 'STOPPED', 'DESTROY'],
1682 8d08f18a Kostas Papadimitriou
        'STOPPED': ['ERROR', 'ACTIVE', 'DESTROY'],
1683 8d08f18a Kostas Papadimitriou
        'ACTIVE': ['ERROR', 'STOPPED', 'REBOOT', 'SHUTDOWN', 'DESTROY'],
1684 8d08f18a Kostas Papadimitriou
        'START': ['ERROR', 'ACTIVE', 'DESTROY'],
1685 8d08f18a Kostas Papadimitriou
        'REBOOT': ['ERROR', 'ACTIVE', 'STOPPED', 'DESTROY'],
1686 8d08f18a Kostas Papadimitriou
        'BUILD': ['ERROR', 'ACTIVE', 'DESTROY'],
1687 a3ac649e Kostas Papadimitriou
        'RESIZE': ['ERROR', 'STOPPED']
1688 8d08f18a Kostas Papadimitriou
    }
1689 8d08f18a Kostas Papadimitriou
1690 8d08f18a Kostas Papadimitriou
    models.VM.TRANSITION_STATES = [
1691 8d08f18a Kostas Papadimitriou
        'DESTROY',
1692 8d08f18a Kostas Papadimitriou
        'SHUTDOWN',
1693 8d08f18a Kostas Papadimitriou
        'START',
1694 8d08f18a Kostas Papadimitriou
        'REBOOT',
1695 a3ac649e Kostas Papadimitriou
        'BUILD',
1696 a3ac649e Kostas Papadimitriou
        'RESIZE'
1697 8d08f18a Kostas Papadimitriou
    ]
1698 8d08f18a Kostas Papadimitriou
1699 8d08f18a Kostas Papadimitriou
    models.VM.ACTIVE_STATES = [
1700 8d08f18a Kostas Papadimitriou
        'BUILD', 'REBOOT', 'ACTIVE',
1701 4e365467 Kostas Papadimitriou
        'SHUTDOWN', 'CONNECT', 'DISCONNECT'
1702 8d08f18a Kostas Papadimitriou
    ]
1703 8d08f18a Kostas Papadimitriou
1704 8d08f18a Kostas Papadimitriou
    models.VM.BUILDING_STATES = [
1705 a3ac649e Kostas Papadimitriou
        'BUILD'
1706 8d08f18a Kostas Papadimitriou
    ]
1707 8d08f18a Kostas Papadimitriou
1708 8d08f18a Kostas Papadimitriou
    models.Images = models.Collection.extend({
1709 8d08f18a Kostas Papadimitriou
        model: models.Image,
1710 8d08f18a Kostas Papadimitriou
        path: 'images',
1711 8d08f18a Kostas Papadimitriou
        details: true,
1712 8d08f18a Kostas Papadimitriou
        noUpdate: true,
1713 16392650 Kostas Papadimitriou
        supportIncUpdates: false,
1714 8d08f18a Kostas Papadimitriou
        meta_keys_as_attrs: ["OS", "description", "kernel", "size", "GUI"],
1715 88d6d677 Kostas Papadimitriou
        meta_labels: {},
1716 258235f4 Kostas Papadimitriou
        read_method: 'read',
1717 8d08f18a Kostas Papadimitriou
1718 bedfe884 Kostas Papadimitriou
        // update collection model with id passed
1719 1420aae4 Kostas Papadimitriou
        // making a direct call to the image
1720 bedfe884 Kostas Papadimitriou
        // api url
1721 c45bed88 Kostas Papadimitriou
        update_unknown_id: function(id, callback) {
1722 bedfe884 Kostas Papadimitriou
            var url = getUrl.call(this) + "/" + id;
1723 126a01f2 Kostas Papadimitriou
            this.api_call(this.path + "/" + id, this.read_method, {
1724 126a01f2 Kostas Papadimitriou
              _options:{
1725 126a01f2 Kostas Papadimitriou
                async:true, 
1726 126a01f2 Kostas Papadimitriou
                skip_api_error:true}
1727 126a01f2 Kostas Papadimitriou
              }, undefined, 
1728 bedfe884 Kostas Papadimitriou
            _.bind(function() {
1729 327f0d58 Kostas Papadimitriou
                if (!this.get(id)) {
1730 d7612b6e Kostas Papadimitriou
                            if (this.fallback_service) {
1731 d7612b6e Kostas Papadimitriou
                        // if current service has fallback_service attribute set
1732 d7612b6e Kostas Papadimitriou
                        // use this service to retrieve the missing image model
1733 d7612b6e Kostas Papadimitriou
                        var tmpservice = new this.fallback_service();
1734 d7612b6e Kostas Papadimitriou
                        tmpservice.update_unknown_id(id, _.bind(function(img){
1735 d7612b6e Kostas Papadimitriou
                            img.attributes.status = "DELETED";
1736 d7612b6e Kostas Papadimitriou
                            this.add(img.attributes);
1737 d7612b6e Kostas Papadimitriou
                            callback(this.get(id));
1738 d7612b6e Kostas Papadimitriou
                        }, this));
1739 d7612b6e Kostas Papadimitriou
                    } else {
1740 03639c6d Kostas Papadimitriou
                        var title = synnefo.config.image_deleted_title || 'Deleted';
1741 d7612b6e Kostas Papadimitriou
                        // else add a dummy DELETED state image entry
1742 03639c6d Kostas Papadimitriou
                        this.add({id:id, name:title, size:-1, 
1743 d7612b6e Kostas Papadimitriou
                                  progress:100, status:"DELETED"});
1744 d7612b6e Kostas Papadimitriou
                        callback(this.get(id));
1745 d7612b6e Kostas Papadimitriou
                    }   
1746 d7612b6e Kostas Papadimitriou
                } else {
1747 d7612b6e Kostas Papadimitriou
                    callback(this.get(id));
1748 327f0d58 Kostas Papadimitriou
                }
1749 258235f4 Kostas Papadimitriou
            }, this), _.bind(function(image, msg, xhr) {
1750 f70c8d47 Kostas Papadimitriou
                if (!image) {
1751 03639c6d Kostas Papadimitriou
                    var title = synnefo.config.image_deleted_title || 'Deleted';
1752 03639c6d Kostas Papadimitriou
                    this.add({id:id, name:title, size:-1, 
1753 f70c8d47 Kostas Papadimitriou
                              progress:100, status:"DELETED"});
1754 f70c8d47 Kostas Papadimitriou
                    callback(this.get(id));
1755 f70c8d47 Kostas Papadimitriou
                    return;
1756 f70c8d47 Kostas Papadimitriou
                }
1757 258235f4 Kostas Papadimitriou
                var img_data = this._read_image_from_request(image, msg, xhr);
1758 258235f4 Kostas Papadimitriou
                this.add(img_data);
1759 c45bed88 Kostas Papadimitriou
                callback(this.get(id));
1760 bedfe884 Kostas Papadimitriou
            }, this));
1761 bedfe884 Kostas Papadimitriou
        },
1762 bedfe884 Kostas Papadimitriou
1763 258235f4 Kostas Papadimitriou
        _read_image_from_request: function(image, msg, xhr) {
1764 258235f4 Kostas Papadimitriou
            return image.image;
1765 258235f4 Kostas Papadimitriou
        },
1766 258235f4 Kostas Papadimitriou
1767 8d08f18a Kostas Papadimitriou
        parse: function (resp, xhr) {
1768 0dee4086 Kostas Papadimitriou
            var parsed = _.map(resp.images, _.bind(this.parse_meta, this));
1769 8f53cfa3 Kostas Papadimitriou
            parsed = this.fill_owners(parsed);
1770 8f53cfa3 Kostas Papadimitriou
            return parsed;
1771 8f53cfa3 Kostas Papadimitriou
        },
1772 8f53cfa3 Kostas Papadimitriou
1773 8f53cfa3 Kostas Papadimitriou
        fill_owners: function(images) {
1774 8f53cfa3 Kostas Papadimitriou
            // do translate uuid->displayname if needed
1775 8f53cfa3 Kostas Papadimitriou
            // store display name in owner attribute for compatibility
1776 8f53cfa3 Kostas Papadimitriou
            var uuids = [];
1777 8f53cfa3 Kostas Papadimitriou
1778 8f53cfa3 Kostas Papadimitriou
            var images = _.map(images, function(img, index) {
1779 8f53cfa3 Kostas Papadimitriou
                if (synnefo.config.translate_uuids) {
1780 8f53cfa3 Kostas Papadimitriou
                    uuids.push(img['owner']);
1781 8f53cfa3 Kostas Papadimitriou
                }
1782 8f53cfa3 Kostas Papadimitriou
                img['owner_uuid'] = img['owner'];
1783 8f53cfa3 Kostas Papadimitriou
                return img;
1784 8f53cfa3 Kostas Papadimitriou
            });
1785 8f53cfa3 Kostas Papadimitriou
            
1786 8f53cfa3 Kostas Papadimitriou
            if (uuids.length > 0) {
1787 8f53cfa3 Kostas Papadimitriou
                var handle_results = function(data) {
1788 8f53cfa3 Kostas Papadimitriou
                    _.each(images, function (img) {
1789 8f53cfa3 Kostas Papadimitriou
                        img['owner'] = data.uuid_catalog[img['owner_uuid']];
1790 8f53cfa3 Kostas Papadimitriou
                    });
1791 8f53cfa3 Kostas Papadimitriou
                }
1792 8f53cfa3 Kostas Papadimitriou
                // notice the async false
1793 8f53cfa3 Kostas Papadimitriou
                var uuid_map = this.translate_uuids(uuids, false, 
1794 8f53cfa3 Kostas Papadimitriou
                                                    handle_results)
1795 8f53cfa3 Kostas Papadimitriou
            }
1796 8f53cfa3 Kostas Papadimitriou
            return images;
1797 8f53cfa3 Kostas Papadimitriou
        },
1798 8f53cfa3 Kostas Papadimitriou
1799 8f53cfa3 Kostas Papadimitriou
        translate_uuids: function(uuids, async, cb) {
1800 8f53cfa3 Kostas Papadimitriou
            var url = synnefo.config.user_catalog_url;
1801 8f53cfa3 Kostas Papadimitriou
            var data = JSON.stringify({'uuids': uuids});
1802 8f53cfa3 Kostas Papadimitriou
          
1803 8f53cfa3 Kostas Papadimitriou
            // post to user_catalogs api
1804 8f53cfa3 Kostas Papadimitriou
            snf.api.sync('create', undefined, {
1805 8f53cfa3 Kostas Papadimitriou
                url: url,
1806 8f53cfa3 Kostas Papadimitriou
                data: data,
1807 8f53cfa3 Kostas Papadimitriou
                async: async,
1808 8f53cfa3 Kostas Papadimitriou
                success:  cb
1809 8f53cfa3 Kostas Papadimitriou
            });
1810 8d08f18a Kostas Papadimitriou
        },
1811 8d08f18a Kostas Papadimitriou
1812 8d08f18a Kostas Papadimitriou
        get_meta_key: function(img, key) {
1813 0dee4086 Kostas Papadimitriou
            if (img.metadata && img.metadata && img.metadata[key]) {
1814 0dee4086 Kostas Papadimitriou
                return _.escape(img.metadata[key]);
1815 8d08f18a Kostas Papadimitriou
            }
1816 8d08f18a Kostas Papadimitriou
            return undefined;
1817 8d08f18a Kostas Papadimitriou
        },
1818 8d08f18a Kostas Papadimitriou
1819 ccb14ad0 Kostas Papadimitriou
        comparator: function(img) {
1820 ccb14ad0 Kostas Papadimitriou
            return -img.get_sort_order("sortorder") || 1000 * img.id;
1821 ccb14ad0 Kostas Papadimitriou
        },
1822 ccb14ad0 Kostas Papadimitriou
1823 8d08f18a Kostas Papadimitriou
        parse_meta: function(img) {
1824 8d08f18a Kostas Papadimitriou
            _.each(this.meta_keys_as_attrs, _.bind(function(key){
1825 258235f4 Kostas Papadimitriou
                if (img[key]) { return };
1826 2a5ae934 Kostas Papadimitriou
                img[key] = this.get_meta_key(img, key) || "";
1827 8d08f18a Kostas Papadimitriou
            }, this));
1828 8d08f18a Kostas Papadimitriou
            return img;
1829 bedfe884 Kostas Papadimitriou
        },
1830 bedfe884 Kostas Papadimitriou
1831 bedfe884 Kostas Papadimitriou
        active: function() {
1832 bedfe884 Kostas Papadimitriou
            return this.filter(function(img){return img.get('status') != "DELETED"});
1833 2cee7cb0 Kostas Papadimitriou
        },
1834 2cee7cb0 Kostas Papadimitriou
1835 2cee7cb0 Kostas Papadimitriou
        predefined: function() {
1836 2cee7cb0 Kostas Papadimitriou
            return _.filter(this.active(), function(i) { return !i.get("serverRef")});
1837 948042ca Kostas Papadimitriou
        },
1838 948042ca Kostas Papadimitriou
        
1839 948042ca Kostas Papadimitriou
        fetch_for_type: function(type, complete, error) {
1840 948042ca Kostas Papadimitriou
            this.fetch({update:true, 
1841 948042ca Kostas Papadimitriou
                        success: complete, 
1842 948042ca Kostas Papadimitriou
                        error: error, 
1843 948042ca Kostas Papadimitriou
                        skip_api_error: true });
1844 948042ca Kostas Papadimitriou
        },
1845 948042ca Kostas Papadimitriou
        
1846 948042ca Kostas Papadimitriou
        get_images_for_type: function(type) {
1847 948042ca Kostas Papadimitriou
            if (this['get_{0}_images'.format(type)]) {
1848 948042ca Kostas Papadimitriou
                return this['get_{0}_images'.format(type)]();
1849 948042ca Kostas Papadimitriou
            }
1850 948042ca Kostas Papadimitriou
1851 948042ca Kostas Papadimitriou
            return this.active();
1852 948042ca Kostas Papadimitriou
        },
1853 948042ca Kostas Papadimitriou
1854 948042ca Kostas Papadimitriou
        update_images_for_type: function(type, onStart, onComplete, onError, force_load) {
1855 948042ca Kostas Papadimitriou
            var load = false;
1856 948042ca Kostas Papadimitriou
            error = onError || function() {};
1857 948042ca Kostas Papadimitriou
            function complete(collection) { 
1858 948042ca Kostas Papadimitriou
                onComplete(collection.get_images_for_type(type)); 
1859 948042ca Kostas Papadimitriou
            }
1860 948042ca Kostas Papadimitriou
            
1861 948042ca Kostas Papadimitriou
            // do we need to fetch/update current collection entries
1862 948042ca Kostas Papadimitriou
            if (load) {
1863 948042ca Kostas Papadimitriou
                onStart();
1864 948042ca Kostas Papadimitriou
                this.fetch_for_type(type, complete, error);
1865 948042ca Kostas Papadimitriou
            } else {
1866 948042ca Kostas Papadimitriou
                // fallback to complete
1867 948042ca Kostas Papadimitriou
                complete(this);
1868 948042ca Kostas Papadimitriou
            }
1869 8d08f18a Kostas Papadimitriou
        }
1870 8d08f18a Kostas Papadimitriou
    })
1871 8d08f18a Kostas Papadimitriou
1872 8d08f18a Kostas Papadimitriou
    models.Flavors = models.Collection.extend({
1873 8d08f18a Kostas Papadimitriou
        model: models.Flavor,
1874 8d08f18a Kostas Papadimitriou
        path: 'flavors',
1875 8d08f18a Kostas Papadimitriou
        details: true,
1876 8d08f18a Kostas Papadimitriou
        noUpdate: true,
1877 16392650 Kostas Papadimitriou
        supportIncUpdates: false,
1878 bedfe884 Kostas Papadimitriou
        // update collection model with id passed
1879 bedfe884 Kostas Papadimitriou
        // making a direct call to the flavor
1880 bedfe884 Kostas Papadimitriou
        // api url
1881 c45bed88 Kostas Papadimitriou
        update_unknown_id: function(id, callback) {
1882 bedfe884 Kostas Papadimitriou
            var url = getUrl.call(this) + "/" + id;
1883 258235f4 Kostas Papadimitriou
            this.api_call(this.path + "/" + id, "read", {_options:{async:false, skip_api_error:true}}, undefined, 
1884 bedfe884 Kostas Papadimitriou
            _.bind(function() {
1885 9555268a Kostas Papadimitriou
                this.add({id:id, cpu:"Unknown", ram:"Unknown", disk:"Unknown", name: "Unknown", status:"DELETED"})
1886 bedfe884 Kostas Papadimitriou
            }, this), _.bind(function(flv) {
1887 bedfe884 Kostas Papadimitriou
                if (!flv.flavor.status) { flv.flavor.status = "DELETED" };
1888 bedfe884 Kostas Papadimitriou
                this.add(flv.flavor);
1889 bedfe884 Kostas Papadimitriou
            }, this));
1890 bedfe884 Kostas Papadimitriou
        },
1891 8d08f18a Kostas Papadimitriou
1892 8d08f18a Kostas Papadimitriou
        parse: function (resp, xhr) {
1893 29fef7b9 Christos Stavrakakis
            return _.map(resp.flavors, function(o) {
1894 29fef7b9 Christos Stavrakakis
              o.cpu = o['vcpus'];
1895 29fef7b9 Christos Stavrakakis
              o.disk_template = o['SNF:disk_template'];
1896 29fef7b9 Christos Stavrakakis
              return o
1897 29fef7b9 Christos Stavrakakis
            });
1898 8d08f18a Kostas Papadimitriou
        },
1899 8d08f18a Kostas Papadimitriou
1900 ccb14ad0 Kostas Papadimitriou
        comparator: function(flv) {
1901 ccb14ad0 Kostas Papadimitriou
            return flv.get("disk") * flv.get("cpu") * flv.get("ram");
1902 ccb14ad0 Kostas Papadimitriou
        },
1903 ab3df8df Kostas Papadimitriou
          
1904 ab3df8df Kostas Papadimitriou
        unavailable_values_for_quotas: function(quotas, flavors, extra) {
1905 7ac49c2e Kostas Papadimitriou
            var flavors = flavors || this.active();
1906 7ac49c2e Kostas Papadimitriou
            var index = {cpu:[], disk:[], ram:[]};
1907 ab3df8df Kostas Papadimitriou
            var extra = extra == undefined ? {cpu:0, disk:0, ram:0} : extra;
1908 7ac49c2e Kostas Papadimitriou
            
1909 7ac49c2e Kostas Papadimitriou
            _.each(flavors, function(el) {
1910 7ac49c2e Kostas Papadimitriou
1911 ab3df8df Kostas Papadimitriou
                var disk_available = quotas['disk'] + extra.disk;
1912 7ac49c2e Kostas Papadimitriou
                var disk_size = el.get_disk_size();
1913 7ac49c2e Kostas Papadimitriou
                if (index.disk.indexOf(disk_size) == -1) {
1914 7ac49c2e Kostas Papadimitriou
                  var disk = el.disk_to_bytes();
1915 7ac49c2e Kostas Papadimitriou
                  if (disk > disk_available) {
1916 7ac49c2e Kostas Papadimitriou
                    index.disk.push(disk_size);
1917 7ac49c2e Kostas Papadimitriou
                  }
1918 7ac49c2e Kostas Papadimitriou
                }
1919 ab3df8df Kostas Papadimitriou
                
1920 ab3df8df Kostas Papadimitriou
                var ram_available = quotas['ram'] + extra.ram * 1024 * 1024;
1921 7ac49c2e Kostas Papadimitriou
                var ram_size = el.get_ram_size();
1922 2d35cfcd Kostas Papadimitriou
                if (index.ram.indexOf(ram_size) == -1) {
1923 7ac49c2e Kostas Papadimitriou
                  var ram = el.ram_to_bytes();
1924 7ac49c2e Kostas Papadimitriou
                  if (ram > ram_available) {
1925 7ac49c2e Kostas Papadimitriou
                    index.ram.push(el.get('ram'))
1926 7ac49c2e Kostas Papadimitriou
                  }
1927 7ac49c2e Kostas Papadimitriou
                }
1928 7ac49c2e Kostas Papadimitriou
1929 7ac49c2e Kostas Papadimitriou
                var cpu = el.get('cpu');
1930 ab3df8df Kostas Papadimitriou
                var cpu_available = quotas['cpu'] + extra.cpu;
1931 ab3df8df Kostas Papadimitriou
                if (index.cpu.indexOf(cpu) == -1) {
1932 7ac49c2e Kostas Papadimitriou
                  if (cpu > cpu_available) {
1933 7ac49c2e Kostas Papadimitriou
                    index.cpu.push(el.get('cpu'))
1934 7ac49c2e Kostas Papadimitriou
                  }
1935 7ac49c2e Kostas Papadimitriou
                }
1936 7ac49c2e Kostas Papadimitriou
            });
1937 7ac49c2e Kostas Papadimitriou
            return index;
1938 7ac49c2e Kostas Papadimitriou
        },
1939 7ac49c2e Kostas Papadimitriou
1940 820ef2f0 Kostas Papadimitriou
        unavailable_values_for_image: function(img, flavors) {
1941 820ef2f0 Kostas Papadimitriou
            var flavors = flavors || this.active();
1942 820ef2f0 Kostas Papadimitriou
            var size = img.get_size();
1943 820ef2f0 Kostas Papadimitriou
            
1944 820ef2f0 Kostas Papadimitriou
            var index = {cpu:[], disk:[], ram:[]};
1945 820ef2f0 Kostas Papadimitriou
1946 820ef2f0 Kostas Papadimitriou
            _.each(this.active(), function(el) {
1947 820ef2f0 Kostas Papadimitriou
                var img_size = size;
1948 820ef2f0 Kostas Papadimitriou
                var flv_size = el.get_disk_size();
1949 820ef2f0 Kostas Papadimitriou
                if (flv_size < img_size) {
1950 820ef2f0 Kostas Papadimitriou
                    if (index.disk.indexOf(flv_size) == -1) {
1951 820ef2f0 Kostas Papadimitriou
                        index.disk.push(flv_size);
1952 820ef2f0 Kostas Papadimitriou
                    }
1953 820ef2f0 Kostas Papadimitriou
                };
1954 820ef2f0 Kostas Papadimitriou
            });
1955 820ef2f0 Kostas Papadimitriou
            
1956 820ef2f0 Kostas Papadimitriou
            return index;
1957 8d08f18a Kostas Papadimitriou
        },
1958 820ef2f0 Kostas Papadimitriou
1959 d965e6dc Kostas Papadimitriou
        get_flavor: function(cpu, mem, disk, disk_template, filter_list) {
1960 8d08f18a Kostas Papadimitriou
            if (!filter_list) { filter_list = this.models };
1961 d965e6dc Kostas Papadimitriou
            
1962 8d08f18a Kostas Papadimitriou
            return this.select(function(flv){
1963 8d08f18a Kostas Papadimitriou
                if (flv.get("cpu") == cpu + "" &&
1964 8d08f18a Kostas Papadimitriou
                   flv.get("ram") == mem + "" &&
1965 8d08f18a Kostas Papadimitriou
                   flv.get("disk") == disk + "" &&
1966 d965e6dc Kostas Papadimitriou
                   flv.get("disk_template") == disk_template &&
1967 820ef2f0 Kostas Papadimitriou
                   filter_list.indexOf(flv) > -1) { return true; }
1968 9ce969a7 Kostas Papadimitriou
            })[0];
1969 8d08f18a Kostas Papadimitriou
        },
1970 820ef2f0 Kostas Papadimitriou
        
1971 8d08f18a Kostas Papadimitriou
        get_data: function(lst) {
1972 ab3df8df Kostas Papadimitriou
            var data = {'cpu': [], 'mem':[], 'disk':[], 'disk_template':[]};
1973 820ef2f0 Kostas Papadimitriou
1974 8d08f18a Kostas Papadimitriou
            _.each(lst, function(flv) {
1975 820ef2f0 Kostas Papadimitriou
                if (data.cpu.indexOf(flv.get("cpu")) == -1) {
1976 820ef2f0 Kostas Papadimitriou
                    data.cpu.push(flv.get("cpu"));
1977 8d08f18a Kostas Papadimitriou
                }
1978 820ef2f0 Kostas Papadimitriou
                if (data.mem.indexOf(flv.get("ram")) == -1) {
1979 820ef2f0 Kostas Papadimitriou
                    data.mem.push(flv.get("ram"));
1980 8d08f18a Kostas Papadimitriou
                }
1981 820ef2f0 Kostas Papadimitriou
                if (data.disk.indexOf(flv.get("disk")) == -1) {
1982 820ef2f0 Kostas Papadimitriou
                    data.disk.push(flv.get("disk"));
1983 8d08f18a Kostas Papadimitriou
                }
1984 ab3df8df Kostas Papadimitriou
                if (data.disk_template.indexOf(flv.get("disk_template")) == -1) {
1985 ab3df8df Kostas Papadimitriou
                    data.disk_template.push(flv.get("disk_template"));
1986 ab3df8df Kostas Papadimitriou
                }
1987 8d08f18a Kostas Papadimitriou
            })
1988 820ef2f0 Kostas Papadimitriou
            
1989 8d08f18a Kostas Papadimitriou
            return data;
1990 bedfe884 Kostas Papadimitriou
        },
1991 bedfe884 Kostas Papadimitriou
1992 bedfe884 Kostas Papadimitriou
        active: function() {
1993 bedfe884 Kostas Papadimitriou
            return this.filter(function(flv){return flv.get('status') != "DELETED"});
1994 8d08f18a Kostas Papadimitriou
        }
1995 8d08f18a Kostas Papadimitriou
            
1996 8d08f18a Kostas Papadimitriou
    })
1997 8d08f18a Kostas Papadimitriou
1998 8d08f18a Kostas Papadimitriou
    models.VMS = models.Collection.extend({
1999 8d08f18a Kostas Papadimitriou
        model: models.VM,
2000 8d08f18a Kostas Papadimitriou
        path: 'servers',
2001 8d08f18a Kostas Papadimitriou
        details: true,
2002 8d08f18a Kostas Papadimitriou
        copy_image_meta: true,
2003 126a01f2 Kostas Papadimitriou
2004 8d08f18a Kostas Papadimitriou
        parse: function (resp, xhr) {
2005 8d08f18a Kostas Papadimitriou
            var data = resp;
2006 8d08f18a Kostas Papadimitriou
            if (!resp) { return [] };
2007 45b964d3 Kostas Papadimitriou
            data = _.filter(_.map(resp.servers, 
2008 45b964d3 Kostas Papadimitriou
                                  _.bind(this.parse_vm_api_data, this)), 
2009 45b964d3 Kostas Papadimitriou
                                  function(v){return v});
2010 8d08f18a Kostas Papadimitriou
            return data;
2011 8d08f18a Kostas Papadimitriou
        },
2012 126a01f2 Kostas Papadimitriou
2013 1e882dd7 Kostas Papadimitriou
        parse_vm_api_data: function(data) {
2014 1e882dd7 Kostas Papadimitriou
            // do not add non existing DELETED entries
2015 1e882dd7 Kostas Papadimitriou
            if (data.status && data.status == "DELETED") {
2016 1e882dd7 Kostas Papadimitriou
                if (!this.get(data.id)) {
2017 1e882dd7 Kostas Papadimitriou
                    return false;
2018 1e882dd7 Kostas Papadimitriou
                }
2019 1e882dd7 Kostas Papadimitriou
            }
2020 a3ac649e Kostas Papadimitriou
            
2021 a3ac649e Kostas Papadimitriou
            if ('SNF:task_state' in data) { 
2022 a3ac649e Kostas Papadimitriou
                data['task_state'] = data['SNF:task_state'];
2023 a3ac649e Kostas Papadimitriou
                if (data['task_state']) {
2024 a3ac649e Kostas Papadimitriou
                    var status = models.VM.TASK_STATE_STATUS_MAP[data['task_state']];
2025 a3ac649e Kostas Papadimitriou
                    if (status) { data['status'] = status }
2026 a3ac649e Kostas Papadimitriou
                }
2027 a3ac649e Kostas Papadimitriou
            }
2028 1e882dd7 Kostas Papadimitriou
2029 1e882dd7 Kostas Papadimitriou
            // OS attribute
2030 1e882dd7 Kostas Papadimitriou
            if (this.has_meta(data)) {
2031 0dee4086 Kostas Papadimitriou
                data['OS'] = data.metadata.OS || snf.config.unknown_os;
2032 1e882dd7 Kostas Papadimitriou
            }
2033 1e882dd7 Kostas Papadimitriou
            
2034 1e882dd7 Kostas Papadimitriou
            if (!data.diagnostics) {
2035 1e882dd7 Kostas Papadimitriou
                data.diagnostics = [];
2036 1e882dd7 Kostas Papadimitriou
            }
2037 1e882dd7 Kostas Papadimitriou
2038 1e882dd7 Kostas Papadimitriou
            // network metadata
2039 1e882dd7 Kostas Papadimitriou
            data['firewalls'] = {};
2040 3e323ae8 Kostas Papadimitriou
            
2041 3e323ae8 Kostas Papadimitriou
            data['fqdn'] = data['SNF:fqdn'] || synnefo.config.vm_hostname_format.format(data['id']);
2042 d7d154c9 Kostas Papadimitriou
2043 1e882dd7 Kostas Papadimitriou
            // if vm has no metadata, no metadata object
2044 1e882dd7 Kostas Papadimitriou
            // is in json response, reset it to force
2045 1e882dd7 Kostas Papadimitriou
            // value update
2046 1e882dd7 Kostas Papadimitriou
            if (!data['metadata']) {
2047 0dee4086 Kostas Papadimitriou
                data['metadata'] = {};
2048 1e882dd7 Kostas Papadimitriou
            }
2049 60ba7fc6 Kostas Papadimitriou
            
2050 60ba7fc6 Kostas Papadimitriou
            // v2.0 API returns objects
2051 60ba7fc6 Kostas Papadimitriou
            data.image_obj = data.image;
2052 60ba7fc6 Kostas Papadimitriou
            data.image = data.image_obj.id;
2053 60ba7fc6 Kostas Papadimitriou
            data.flavor_obj = data.flavor;
2054 60ba7fc6 Kostas Papadimitriou
            data.flavor = data.flavor_obj.id;
2055 1e882dd7 Kostas Papadimitriou
2056 1e882dd7 Kostas Papadimitriou
            return data;
2057 1e882dd7 Kostas Papadimitriou
        },
2058 1e882dd7 Kostas Papadimitriou
2059 122850c5 Kostas Papadimitriou
        get_reboot_required: function() {
2060 122850c5 Kostas Papadimitriou
            return this.filter(function(vm){return vm.get("reboot_required") == true})
2061 122850c5 Kostas Papadimitriou
        },
2062 122850c5 Kostas Papadimitriou
2063 122850c5 Kostas Papadimitriou
        has_pending_actions: function() {
2064 122850c5 Kostas Papadimitriou
            return this.filter(function(vm){return vm.pending_action}).length > 0;
2065 122850c5 Kostas Papadimitriou
        },
2066 8d08f18a Kostas Papadimitriou
2067 8d08f18a Kostas Papadimitriou
        reset_pending_actions: function() {
2068 8d08f18a Kostas Papadimitriou
            this.each(function(vm) {
2069 8d08f18a Kostas Papadimitriou
                vm.clear_pending_action();
2070 8d08f18a Kostas Papadimitriou
            })
2071 8d08f18a Kostas Papadimitriou
        },
2072 101e6604 Kostas Papadimitriou
2073 101e6604 Kostas Papadimitriou
        do_all_pending_actions: function(success, error) {
2074 101e6604 Kostas Papadimitriou
            this.each(function(vm) {
2075 101e6604 Kostas Papadimitriou
                if (vm.has_pending_action()) {
2076 101e6604 Kostas Papadimitriou
                    vm.call(vm.pending_action, success, error);
2077 101e6604 Kostas Papadimitriou
                    vm.clear_pending_action();
2078 101e6604 Kostas Papadimitriou
                }
2079 101e6604 Kostas Papadimitriou
            })
2080 101e6604 Kostas Papadimitriou
        },
2081 101e6604 Kostas Papadimitriou
        
2082 101e6604 Kostas Papadimitriou
        do_all_reboots: function(success, error) {
2083 101e6604 Kostas Papadimitriou
            this.each(function(vm) {
2084 101e6604 Kostas Papadimitriou
                if (vm.get("reboot_required")) {
2085 101e6604 Kostas Papadimitriou
                    vm.call("reboot", success, error);
2086 101e6604 Kostas Papadimitriou
                }
2087 101e6604 Kostas Papadimitriou
            });
2088 101e6604 Kostas Papadimitriou
        },
2089 101e6604 Kostas Papadimitriou
2090 101e6604 Kostas Papadimitriou
        reset_reboot_required: function() {
2091 101e6604 Kostas Papadimitriou
            this.each(function(vm) {
2092 101e6604 Kostas Papadimitriou
                vm.set({'reboot_required': undefined});
2093 101e6604 Kostas Papadimitriou
            })
2094 101e6604 Kostas Papadimitriou
        },
2095 2c9bfad1 Kostas Papadimitriou
        
2096 2c9bfad1 Kostas Papadimitriou
        stop_stats_update: function(exclude) {
2097 2c9bfad1 Kostas Papadimitriou
            var exclude = exclude || [];
2098 96d725ac Kostas Papadimitriou
            this.each(function(vm) {
2099 2c9bfad1 Kostas Papadimitriou
                if (exclude.indexOf(vm) > -1) {
2100 2c9bfad1 Kostas Papadimitriou
                    return;
2101 2c9bfad1 Kostas Papadimitriou
                }
2102 2c9bfad1 Kostas Papadimitriou
                vm.stop_stats_update();
2103 96d725ac Kostas Papadimitriou
            })
2104 96d725ac Kostas Papadimitriou
        },
2105 8d08f18a Kostas Papadimitriou
        
2106 8d08f18a Kostas Papadimitriou
        has_meta: function(vm_data) {
2107 0dee4086 Kostas Papadimitriou
            return vm_data.metadata && vm_data.metadata
2108 8d08f18a Kostas Papadimitriou
        },
2109 8d08f18a Kostas Papadimitriou
2110 8d08f18a Kostas Papadimitriou
        has_addresses: function(vm_data) {
2111 0dee4086 Kostas Papadimitriou
            return vm_data.metadata && vm_data.metadata
2112 8d08f18a Kostas Papadimitriou
        },
2113 8d08f18a Kostas Papadimitriou
2114 8d08f18a Kostas Papadimitriou
        create: function (name, image, flavor, meta, extra, callback) {
2115 88d6d677 Kostas Papadimitriou
2116 8d08f18a Kostas Papadimitriou
            if (this.copy_image_meta) {
2117 88d6d677 Kostas Papadimitriou
                if (synnefo.config.vm_image_common_metadata) {
2118 88d6d677 Kostas Papadimitriou
                    _.each(synnefo.config.vm_image_common_metadata, 
2119 88d6d677 Kostas Papadimitriou
                        function(key){
2120 88d6d677 Kostas Papadimitriou
                            if (image.get_meta(key)) {
2121 88d6d677 Kostas Papadimitriou
                                meta[key] = image.get_meta(key);
2122 88d6d677 Kostas Papadimitriou
                            }
2123 88d6d677 Kostas Papadimitriou
                    });
2124 88d6d677 Kostas Papadimitriou
                }
2125 88d6d677 Kostas Papadimitriou
2126 d5ba5588 Kostas Papadimitriou
                if (image.get("OS")) {
2127 d5ba5588 Kostas Papadimitriou
                    meta['OS'] = image.get("OS");
2128 d5ba5588 Kostas Papadimitriou
                }
2129 88d6d677 Kostas Papadimitriou
            }
2130 8d08f18a Kostas Papadimitriou
            
2131 1489e9b1 Kostas Papadimitriou
            opts = {name: name, imageRef: image.id, flavorRef: flavor.id, 
2132 426e1fb9 Kostas Papadimitriou
                    metadata:meta}
2133 8d08f18a Kostas Papadimitriou
            opts = _.extend(opts, extra);
2134 b14e3b9e Kostas Papadimitriou
            
2135 ee5d26fc Kostas Papadimitriou
            var cb = function(data) {
2136 426e1fb9 Kostas Papadimitriou
              synnefo.storage.quotas.get('cyclades.vm').increase();
2137 ee5d26fc Kostas Papadimitriou
              callback(data);
2138 b14e3b9e Kostas Papadimitriou
            }
2139 8d08f18a Kostas Papadimitriou
2140 426e1fb9 Kostas Papadimitriou
            this.api_call(this.path, "create", {'server': opts}, undefined, 
2141 426e1fb9 Kostas Papadimitriou
                          undefined, cb, {critical: true});
2142 336ddd59 Kostas Papadimitriou
        },
2143 8d08f18a Kostas Papadimitriou
2144 336ddd59 Kostas Papadimitriou
        load_missing_images: function(callback) {
2145 336ddd59 Kostas Papadimitriou
          var missing_ids = [];
2146 614fb66b Kostas Papadimitriou
          var resolved = 0;
2147 614fb66b Kostas Papadimitriou
2148 614fb66b Kostas Papadimitriou
          // fill missing_ids
2149 336ddd59 Kostas Papadimitriou
          this.each(function(el) {
2150 0dee4086 Kostas Papadimitriou
            var imgid = el.get("image");
2151 336ddd59 Kostas Papadimitriou
            var existing = synnefo.storage.images.get(imgid);
2152 336ddd59 Kostas Papadimitriou
            if (!existing && missing_ids.indexOf(imgid) == -1) {
2153 614fb66b Kostas Papadimitriou
              missing_ids.push(imgid);
2154 336ddd59 Kostas Papadimitriou
            }
2155 336ddd59 Kostas Papadimitriou
          });
2156 614fb66b Kostas Papadimitriou
          var check = function() {
2157 614fb66b Kostas Papadimitriou
            // once all missing ids where resolved continue calling the 
2158 614fb66b Kostas Papadimitriou
            // callback
2159 614fb66b Kostas Papadimitriou
            resolved++;
2160 614fb66b Kostas Papadimitriou
            if (resolved == missing_ids.length) {
2161 614fb66b Kostas Papadimitriou
              callback(missing_ids)
2162 614fb66b Kostas Papadimitriou
            }
2163 614fb66b Kostas Papadimitriou
          }
2164 73f9a3d5 Kostas Papadimitriou
          if (missing_ids.length == 0) {
2165 73f9a3d5 Kostas Papadimitriou
            callback(missing_ids);
2166 73f9a3d5 Kostas Papadimitriou
            return;
2167 73f9a3d5 Kostas Papadimitriou
          }
2168 614fb66b Kostas Papadimitriou
          // start resolving missing image ids
2169 614fb66b Kostas Papadimitriou
          _(missing_ids).each(function(imgid){
2170 614fb66b Kostas Papadimitriou
            synnefo.storage.images.update_unknown_id(imgid, check);
2171 614fb66b Kostas Papadimitriou
          });
2172 1fc7640d Kostas Papadimitriou
        },
2173 1fc7640d Kostas Papadimitriou
2174 1fc7640d Kostas Papadimitriou
        get_connectable: function() {
2175 1fc7640d Kostas Papadimitriou
            return storage.vms.filter(function(vm){
2176 1fc7640d Kostas Papadimitriou
                return !vm.in_error_state() && !vm.is_building();
2177 1fc7640d Kostas Papadimitriou
            });
2178 8d08f18a Kostas Papadimitriou
        }
2179 8d08f18a Kostas Papadimitriou
    })
2180 126a01f2 Kostas Papadimitriou
    
2181 c4fff449 Kostas Papadimitriou
    models.PublicKey = models.Model.extend({
2182 859a4609 Kostas Papadimitriou
        path: 'keys',
2183 7f16b9b1 Kostas Papadimitriou
        api_type: 'userdata',
2184 45b964d3 Kostas Papadimitriou
        detail: false,
2185 45b964d3 Kostas Papadimitriou
        model_actions: {
2186 45b964d3 Kostas Papadimitriou
          'remove': [['name'], function() {
2187 45b964d3 Kostas Papadimitriou
            return true;
2188 45b964d3 Kostas Papadimitriou
          }]
2189 45b964d3 Kostas Papadimitriou
        },
2190 859a4609 Kostas Papadimitriou
2191 859a4609 Kostas Papadimitriou
        get_public_key: function() {
2192 859a4609 Kostas Papadimitriou
            return cryptico.publicKeyFromString(this.get("content"));
2193 859a4609 Kostas Papadimitriou
        },
2194 859a4609 Kostas Papadimitriou
2195 859a4609 Kostas Papadimitriou
        get_filename: function() {
2196 859a4609 Kostas Papadimitriou
            return "{0}.pub".format(this.get("name"));
2197 859a4609 Kostas Papadimitriou
        },
2198 859a4609 Kostas Papadimitriou
2199 859a4609 Kostas Papadimitriou
        identify_type: function() {
2200 859a4609 Kostas Papadimitriou
            try {
2201 859a4609 Kostas Papadimitriou
                var cont = snf.util.validatePublicKey(this.get("content"));
2202 859a4609 Kostas Papadimitriou
                var type = cont.split(" ")[0];
2203 859a4609 Kostas Papadimitriou
                return synnefo.util.publicKeyTypesMap[type];
2204 859a4609 Kostas Papadimitriou
            } catch (err) { return false };
2205 45b964d3 Kostas Papadimitriou
        },
2206 859a4609 Kostas Papadimitriou
2207 45b964d3 Kostas Papadimitriou
        rename: function(new_name) {
2208 45b964d3 Kostas Papadimitriou
          //this.set({'name': new_name});
2209 45b964d3 Kostas Papadimitriou
          this.sync("update", this, {
2210 45b964d3 Kostas Papadimitriou
            critical: true,
2211 45b964d3 Kostas Papadimitriou
            data: {'name': new_name}, 
2212 45b964d3 Kostas Papadimitriou
            success: _.bind(function(){
2213 45b964d3 Kostas Papadimitriou
              snf.api.trigger("call");
2214 45b964d3 Kostas Papadimitriou
            }, this)
2215 45b964d3 Kostas Papadimitriou
          });
2216 45b964d3 Kostas Papadimitriou
        }
2217 c4fff449 Kostas Papadimitriou
    })
2218 c4fff449 Kostas Papadimitriou
    
2219 95ff92b4 Kostas Papadimitriou
    models._ActionsModel = models.Model.extend({
2220 95ff92b4 Kostas Papadimitriou
      defaults: { pending: null },
2221 95ff92b4 Kostas Papadimitriou
      actions: [],
2222 95ff92b4 Kostas Papadimitriou
      status: {
2223 95ff92b4 Kostas Papadimitriou
        INACTIVE: 0,
2224 95ff92b4 Kostas Papadimitriou
        PENDING: 1,
2225 95ff92b4 Kostas Papadimitriou
        CALLED: 2
2226 95ff92b4 Kostas Papadimitriou
      },
2227 95ff92b4 Kostas Papadimitriou
2228 95ff92b4 Kostas Papadimitriou
      initialize: function(attrs, opts) {
2229 95ff92b4 Kostas Papadimitriou
        models._ActionsModel.__super__.initialize.call(this, attrs);
2230 95ff92b4 Kostas Papadimitriou
        this.actions = opts.actions;
2231 95ff92b4 Kostas Papadimitriou
        this.model = opts.model;
2232 95ff92b4 Kostas Papadimitriou
        this.bind("change", function() {
2233 95ff92b4 Kostas Papadimitriou
          this.set({'pending': this.get_pending()});
2234 95ff92b4 Kostas Papadimitriou
        }, this);
2235 95ff92b4 Kostas Papadimitriou
        this.clear();
2236 95ff92b4 Kostas Papadimitriou
      },
2237 95ff92b4 Kostas Papadimitriou
      
2238 95ff92b4 Kostas Papadimitriou
      _in_status: function(st) {
2239 95ff92b4 Kostas Papadimitriou
        var actions = null;
2240 95ff92b4 Kostas Papadimitriou
        _.each(this.attributes, function(status, action){
2241 95ff92b4 Kostas Papadimitriou
          if (status == st) {
2242 95ff92b4 Kostas Papadimitriou
            if (!actions) {
2243 95ff92b4 Kostas Papadimitriou
              actions = []
2244 95ff92b4 Kostas Papadimitriou
            }
2245 95ff92b4 Kostas Papadimitriou
            actions.push(action);
2246 95ff92b4 Kostas Papadimitriou
          }
2247 95ff92b4 Kostas Papadimitriou
        });
2248 95ff92b4 Kostas Papadimitriou
        return actions;
2249 95ff92b4 Kostas Papadimitriou
      },
2250 95ff92b4 Kostas Papadimitriou
2251 95ff92b4 Kostas Papadimitriou
      get_pending: function() {
2252 95ff92b4 Kostas Papadimitriou
        return this._in_status(this.status.PENDING);
2253 95ff92b4 Kostas Papadimitriou
      },
2254 95ff92b4 Kostas Papadimitriou
2255 95ff92b4 Kostas Papadimitriou
      unset_pending_action: function(action) {
2256 95ff92b4 Kostas Papadimitriou
        var data = {};
2257 95ff92b4 Kostas Papadimitriou
        data[action] = this.status.INACTIVE;
2258 95ff92b4 Kostas Papadimitriou
        this.set(data);
2259 95ff92b4 Kostas Papadimitriou
      },
2260 95ff92b4 Kostas Papadimitriou
2261 95ff92b4 Kostas Papadimitriou
      set_pending_action: function(action, reset_pending) {
2262 95ff92b4 Kostas Papadimitriou
        reset_pending = reset_pending === undefined ? true : reset_pending;
2263 95ff92b4 Kostas Papadimitriou
        var data = {};
2264 95ff92b4 Kostas Papadimitriou
        data[action] = this.status.PENDING;
2265 95ff92b4 Kostas Papadimitriou
        if (reset_pending) {
2266 95ff92b4 Kostas Papadimitriou
          this.reset_pending();
2267 95ff92b4 Kostas Papadimitriou
        }
2268 95ff92b4 Kostas Papadimitriou
        this.set(data);
2269 bfb11987 Kostas Papadimitriou
        this.trigger("set-pending", action);
2270 95ff92b4 Kostas Papadimitriou
      },
2271 95ff92b4 Kostas Papadimitriou
      
2272 95ff92b4 Kostas Papadimitriou
      reset_pending: function() {
2273 95ff92b4 Kostas Papadimitriou
        var data = {};
2274 95ff92b4 Kostas Papadimitriou
        _.each(this.actions, function(action) {
2275 95ff92b4 Kostas Papadimitriou
          data[action] = this.status.INACTIVE;
2276 95ff92b4 Kostas Papadimitriou
        }, this);
2277 95ff92b4 Kostas Papadimitriou
        this.set(data);
2278 bfb11987 Kostas Papadimitriou
        this.trigger("reset-pending");
2279 95ff92b4 Kostas Papadimitriou
      }
2280 95ff92b4 Kostas Papadimitriou
    });
2281 95ff92b4 Kostas Papadimitriou
2282 eb17e27a Kostas Papadimitriou
    models.PublicPool = models.Model.extend({});
2283 eb17e27a Kostas Papadimitriou
    models.PublicPools = models.Collection.extend({
2284 eb17e27a Kostas Papadimitriou
      model: models.PublicPool,
2285 eb17e27a Kostas Papadimitriou
      path: 'os-floating-ip-pools',
2286 eb17e27a Kostas Papadimitriou
      api_type: 'compute',
2287 eb17e27a Kostas Papadimitriou
      noUpdate: true,
2288 eb17e27a Kostas Papadimitriou
2289 eb17e27a Kostas Papadimitriou
      parse: function(data) {
2290 eb17e27a Kostas Papadimitriou
        return _.map(data.floating_ip_pools, function(pool) {
2291 eb17e27a Kostas Papadimitriou
          pool.id = pool.name;
2292 eb17e27a Kostas Papadimitriou
          return pool;
2293 eb17e27a Kostas Papadimitriou
        });
2294 eb17e27a Kostas Papadimitriou
      }
2295 eb17e27a Kostas Papadimitriou
    });
2296 eb17e27a Kostas Papadimitriou
2297 c4fff449 Kostas Papadimitriou
    models.PublicKeys = models.Collection.extend({
2298 859a4609 Kostas Papadimitriou
        model: models.PublicKey,
2299 859a4609 Kostas Papadimitriou
        details: false,
2300 859a4609 Kostas Papadimitriou
        path: 'keys',
2301 7f16b9b1 Kostas Papadimitriou
        api_type: 'userdata',
2302 859a4609 Kostas Papadimitriou
        noUpdate: true,
2303 45b964d3 Kostas Papadimitriou
        updateEntries: true,
2304 859a4609 Kostas Papadimitriou
2305 556dcd88 Kostas Papadimitriou
        generate_new: function(success, error) {
2306 386481eb Kostas Papadimitriou
            snf.api.sync('create', undefined, {
2307 556dcd88 Kostas Papadimitriou
                url: getUrl.call(this, this.base_url) + "/generate", 
2308 556dcd88 Kostas Papadimitriou
                success: success, 
2309 556dcd88 Kostas Papadimitriou
                error: error,
2310 556dcd88 Kostas Papadimitriou
                skip_api_error: true
2311 556dcd88 Kostas Papadimitriou
            });
2312 859a4609 Kostas Papadimitriou
        },
2313 d7d154c9 Kostas Papadimitriou
        
2314 859a4609 Kostas Papadimitriou
        add_crypto_key: function(key, success, error, options) {
2315 859a4609 Kostas Papadimitriou
            var options = options || {};
2316 859a4609 Kostas Papadimitriou
            var m = new models.PublicKey();
2317 556dcd88 Kostas Papadimitriou
2318 556dcd88 Kostas Papadimitriou
            // guess a name
2319 1efe6159 Kostas Papadimitriou
            var name_tpl = "my generated public key";
2320 859a4609 Kostas Papadimitriou
            var name = name_tpl;
2321 859a4609 Kostas Papadimitriou
            var name_count = 1;
2322 859a4609 Kostas Papadimitriou
            
2323 859a4609 Kostas Papadimitriou
            while(this.filter(function(m){ return m.get("name") == name }).length > 0) {
2324 859a4609 Kostas Papadimitriou
                name = name_tpl + " " + name_count;
2325 859a4609 Kostas Papadimitriou
                name_count++;
2326 859a4609 Kostas Papadimitriou
            }
2327 556dcd88 Kostas Papadimitriou
            
2328 859a4609 Kostas Papadimitriou
            m.set({name: name});
2329 556dcd88 Kostas Papadimitriou
            m.set({content: key});
2330 859a4609 Kostas Papadimitriou
            
2331 859a4609 Kostas Papadimitriou
            options.success = function () { return success(m) };
2332 859a4609 Kostas Papadimitriou
            options.errror = error;
2333 c72a830d Kostas Papadimitriou
            options.skip_api_error = true;
2334 859a4609 Kostas Papadimitriou
            
2335 859a4609 Kostas Papadimitriou
            this.create(m.attributes, options);
2336 859a4609 Kostas Papadimitriou
        }
2337 426e1fb9 Kostas Papadimitriou
    });
2338 426e1fb9 Kostas Papadimitriou
2339 426e1fb9 Kostas Papadimitriou
  
2340 426e1fb9 Kostas Papadimitriou
    models.Quota = models.Model.extend({
2341 426e1fb9 Kostas Papadimitriou
2342 426e1fb9 Kostas Papadimitriou
        initialize: function() {
2343 426e1fb9 Kostas Papadimitriou
            models.Quota.__super__.initialize.apply(this, arguments);
2344 426e1fb9 Kostas Papadimitriou
            this.bind("change", this.check, this);
2345 426e1fb9 Kostas Papadimitriou
            this.check();
2346 426e1fb9 Kostas Papadimitriou
        },
2347 426e1fb9 Kostas Papadimitriou
        
2348 426e1fb9 Kostas Papadimitriou
        check: function() {
2349 426e1fb9 Kostas Papadimitriou
            var usage, limit;
2350 426e1fb9 Kostas Papadimitriou
            usage = this.get('usage');
2351 426e1fb9 Kostas Papadimitriou
            limit = this.get('limit');
2352 426e1fb9 Kostas Papadimitriou
            if (usage >= limit) {
2353 426e1fb9 Kostas Papadimitriou
                this.trigger("available");
2354 426e1fb9 Kostas Papadimitriou
            } else {
2355 426e1fb9 Kostas Papadimitriou
                this.trigger("unavailable");
2356 426e1fb9 Kostas Papadimitriou
            }
2357 426e1fb9 Kostas Papadimitriou
        },
2358 426e1fb9 Kostas Papadimitriou
2359 426e1fb9 Kostas Papadimitriou
        increase: function(val) {
2360 426e1fb9 Kostas Papadimitriou
            if (val === undefined) { val = 1};
2361 426e1fb9 Kostas Papadimitriou
            this.set({'usage': this.get('usage') + val})
2362 426e1fb9 Kostas Papadimitriou
        },
2363 426e1fb9 Kostas Papadimitriou
2364 426e1fb9 Kostas Papadimitriou
        decrease: function(val) {
2365 426e1fb9 Kostas Papadimitriou
            if (val === undefined) { val = 1};
2366 426e1fb9 Kostas Papadimitriou
            this.set({'usage': this.get('usage') - val})
2367 426e1fb9 Kostas Papadimitriou
        },
2368 426e1fb9 Kostas Papadimitriou
2369 426e1fb9 Kostas Papadimitriou
        can_consume: function() {
2370 426e1fb9 Kostas Papadimitriou
            var usage, limit;
2371 426e1fb9 Kostas Papadimitriou
            usage = this.get('usage');
2372 426e1fb9 Kostas Papadimitriou
            limit = this.get('limit');
2373 426e1fb9 Kostas Papadimitriou
            if (usage >= limit) {
2374 426e1fb9 Kostas Papadimitriou
                return false
2375 426e1fb9 Kostas Papadimitriou
            } else {
2376 426e1fb9 Kostas Papadimitriou
                return true
2377 426e1fb9 Kostas Papadimitriou
            }
2378 426e1fb9 Kostas Papadimitriou
        },
2379 426e1fb9 Kostas Papadimitriou
        
2380 426e1fb9 Kostas Papadimitriou
        is_bytes: function() {
2381 426e1fb9 Kostas Papadimitriou
            return this.get('resource').get('unit') == 'bytes';
2382 426e1fb9 Kostas Papadimitriou
        },
2383 426e1fb9 Kostas Papadimitriou
        
2384 ab3df8df Kostas Papadimitriou
        get_available: function(active) {
2385 ab3df8df Kostas Papadimitriou
            suffix = '';
2386 ab3df8df Kostas Papadimitriou
            if (active) { suffix = '_active'}
2387 ab3df8df Kostas Papadimitriou
            var value = this.get('limit'+suffix) - this.get('usage'+suffix);
2388 b76769ef Kostas Papadimitriou
            if (active) {
2389 b76769ef Kostas Papadimitriou
              if (this.get('available') <= value) {
2390 b76769ef Kostas Papadimitriou
                value = this.get('available');
2391 b76769ef Kostas Papadimitriou
              }
2392 b76769ef Kostas Papadimitriou
            }
2393 426e1fb9 Kostas Papadimitriou
            if (value < 0) { return value }
2394 426e1fb9 Kostas Papadimitriou
            return value
2395 426e1fb9 Kostas Papadimitriou
        },
2396 426e1fb9 Kostas Papadimitriou
2397 ab3df8df Kostas Papadimitriou
        get_readable: function(key, active) {
2398 426e1fb9 Kostas Papadimitriou
            var value;
2399 426e1fb9 Kostas Papadimitriou
            if (key == 'available') {
2400 ab3df8df Kostas Papadimitriou
                value = this.get_available(active);
2401 426e1fb9 Kostas Papadimitriou
            } else {
2402 426e1fb9 Kostas Papadimitriou
                value = this.get(key)
2403 426e1fb9 Kostas Papadimitriou
            }
2404 b76769ef Kostas Papadimitriou
            if (value <= 0) { value = 0 }
2405 426e1fb9 Kostas Papadimitriou
            if (!this.is_bytes()) {
2406 426e1fb9 Kostas Papadimitriou
              return value + "";
2407 426e1fb9 Kostas Papadimitriou
            }
2408 426e1fb9 Kostas Papadimitriou
            return snf.util.readablizeBytes(value);
2409 426e1fb9 Kostas Papadimitriou
        }
2410 426e1fb9 Kostas Papadimitriou
    });
2411 426e1fb9 Kostas Papadimitriou
2412 426e1fb9 Kostas Papadimitriou
    models.Quotas = models.Collection.extend({
2413 426e1fb9 Kostas Papadimitriou
        model: models.Quota,
2414 426e1fb9 Kostas Papadimitriou
        api_type: 'accounts',
2415 426e1fb9 Kostas Papadimitriou
        path: 'quotas',
2416 426e1fb9 Kostas Papadimitriou
        parse: function(resp) {
2417 ab3df8df Kostas Papadimitriou
            filtered = _.map(resp.system, function(value, key) {
2418 426e1fb9 Kostas Papadimitriou
                var available = (value.limit - value.usage) || 0;
2419 ab3df8df Kostas Papadimitriou
                var available_active = available;
2420 ab3df8df Kostas Papadimitriou
                var keysplit = key.split(".");
2421 ab3df8df Kostas Papadimitriou
                var limit_active = value.limit;
2422 ab3df8df Kostas Papadimitriou
                var usage_active = value.usage;
2423 8e13afa9 Kostas Papadimitriou
                keysplit[keysplit.length-1] = "total_" + keysplit[keysplit.length-1];
2424 ab3df8df Kostas Papadimitriou
                var activekey = keysplit.join(".");
2425 ab3df8df Kostas Papadimitriou
                var exists = resp.system[activekey];
2426 ab3df8df Kostas Papadimitriou
                if (exists) {
2427 ab3df8df Kostas Papadimitriou
                    available_active = exists.limit - exists.usage;
2428 ab3df8df Kostas Papadimitriou
                    limit_active = exists.limit;
2429 ab3df8df Kostas Papadimitriou
                    usage_active = exists.usage;
2430 ab3df8df Kostas Papadimitriou
                }
2431 426e1fb9 Kostas Papadimitriou
                return _.extend(value, {'name': key, 'id': key, 
2432 426e1fb9 Kostas Papadimitriou
                          'available': available,
2433 ab3df8df Kostas Papadimitriou
                          'available_active': available_active,
2434 ab3df8df Kostas Papadimitriou
                          'limit_active': limit_active,
2435 ab3df8df Kostas Papadimitriou
                          'usage_active': usage_active,
2436 426e1fb9 Kostas Papadimitriou
                          'resource': snf.storage.resources.get(key)});
2437 ab3df8df Kostas Papadimitriou
            });
2438 ab3df8df Kostas Papadimitriou
            return filtered;
2439 ab3df8df Kostas Papadimitriou
        },
2440 ab3df8df Kostas Papadimitriou
        
2441 ab3df8df Kostas Papadimitriou
        get_by_id: function(k) {
2442 ab3df8df Kostas Papadimitriou
          return this.filter(function(q) { return q.get('name') == k})[0]
2443 ab3df8df Kostas Papadimitriou
        },
2444 ab3df8df Kostas Papadimitriou
2445 b76769ef Kostas Papadimitriou
        get_available_for_vm: function(options) {
2446 ab3df8df Kostas Papadimitriou
          var quotas = synnefo.storage.quotas;
2447 ab3df8df Kostas Papadimitriou
          var key = 'available';
2448 b76769ef Kostas Papadimitriou
          var available_quota = {};
2449 b76769ef Kostas Papadimitriou
          _.each(['cyclades.ram', 'cyclades.cpu', 'cyclades.disk'], 
2450 b76769ef Kostas Papadimitriou
            function (key) {
2451 b76769ef Kostas Papadimitriou
              var value = quotas.get(key).get_available(true);
2452 b76769ef Kostas Papadimitriou
              available_quota[key.replace('cyclades.', '')] = value;
2453 b76769ef Kostas Papadimitriou
          });
2454 b76769ef Kostas Papadimitriou
          return available_quota;
2455 426e1fb9 Kostas Papadimitriou
        }
2456 c4fff449 Kostas Papadimitriou
    })
2457 426e1fb9 Kostas Papadimitriou
2458 426e1fb9 Kostas Papadimitriou
    models.Resource = models.Model.extend({
2459 426e1fb9 Kostas Papadimitriou
        api_type: 'accounts',
2460 426e1fb9 Kostas Papadimitriou
        path: 'resources'
2461 426e1fb9 Kostas Papadimitriou
    });
2462 426e1fb9 Kostas Papadimitriou
2463 426e1fb9 Kostas Papadimitriou
    models.Resources = models.Collection.extend({
2464 426e1fb9 Kostas Papadimitriou
        api_type: 'accounts',
2465 426e1fb9 Kostas Papadimitriou
        path: 'resources',
2466 426e1fb9 Kostas Papadimitriou
        model: models.Network,
2467 426e1fb9 Kostas Papadimitriou
2468 426e1fb9 Kostas Papadimitriou
        parse: function(resp) {
2469 426e1fb9 Kostas Papadimitriou
            return _.map(resp, function(value, key) {
2470 426e1fb9 Kostas Papadimitriou
                return _.extend(value, {'name': key, 'id': key});
2471 426e1fb9 Kostas Papadimitriou
            })
2472 426e1fb9 Kostas Papadimitriou
        }
2473 426e1fb9 Kostas Papadimitriou
    });
2474 8d08f18a Kostas Papadimitriou
    
2475 8d08f18a Kostas Papadimitriou
    // storage initialization
2476 8d08f18a Kostas Papadimitriou
    snf.storage.images = new models.Images();
2477 8d08f18a Kostas Papadimitriou
    snf.storage.flavors = new models.Flavors();
2478 8d08f18a Kostas Papadimitriou
    snf.storage.vms = new models.VMS();
2479 c4fff449 Kostas Papadimitriou
    snf.storage.keys = new models.PublicKeys();
2480 426e1fb9 Kostas Papadimitriou
    snf.storage.resources = new models.Resources();
2481 426e1fb9 Kostas Papadimitriou
    snf.storage.quotas = new models.Quotas();
2482 eb17e27a Kostas Papadimitriou
    snf.storage.public_pools = new models.PublicPools();
2483 8d08f18a Kostas Papadimitriou
2484 8d08f18a Kostas Papadimitriou
})(this);