Statistics
| Branch: | Tag: | Revision:

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

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