Statistics
| Branch: | Tag: | Revision:

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

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