Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / models.js @ 820ef2f0

History | View | Annotate | Download (44.9 kB)

1 8d08f18a Kostas Papadimitriou
;(function(root){
2 8d08f18a Kostas Papadimitriou
    
3 8d08f18a Kostas Papadimitriou
    // root
4 8d08f18a Kostas Papadimitriou
    var root = root;
5 8d08f18a Kostas Papadimitriou
    
6 8d08f18a Kostas Papadimitriou
    // setup namepsaces
7 8d08f18a Kostas Papadimitriou
    var snf = root.synnefo = root.synnefo || {};
8 8d08f18a Kostas Papadimitriou
    var models = snf.models = snf.models || {}
9 8d08f18a Kostas Papadimitriou
    var storage = snf.storage = snf.storage || {};
10 8d08f18a Kostas Papadimitriou
    var util = snf.util = snf.util || {};
11 8d08f18a Kostas Papadimitriou
12 8d08f18a Kostas Papadimitriou
    // shortcuts
13 8d08f18a Kostas Papadimitriou
    var bb = root.Backbone;
14 8d08f18a Kostas Papadimitriou
    var slice = Array.prototype.slice
15 8d08f18a Kostas Papadimitriou
16 8d08f18a Kostas Papadimitriou
    // logging
17 8d08f18a Kostas Papadimitriou
    var logger = new snf.logging.logger("SNF-MODELS");
18 8d08f18a Kostas Papadimitriou
    var debug = _.bind(logger.debug, logger);
19 8d08f18a Kostas Papadimitriou
    
20 8d08f18a Kostas Papadimitriou
    // get url helper
21 8d08f18a Kostas Papadimitriou
    var getUrl = function() {
22 8d08f18a Kostas Papadimitriou
        return snf.config.api_url + "/" + this.path;
23 8d08f18a Kostas Papadimitriou
    }
24 8d08f18a Kostas Papadimitriou
    
25 8d08f18a Kostas Papadimitriou
    // i18n
26 8d08f18a Kostas Papadimitriou
    BUILDING_MESSAGES = window.BUILDING_MESSAGES || {'INIT': 'init', 'COPY': '{0}, {1}, {2}', 'FINAL': 'final'};
27 8d08f18a Kostas Papadimitriou
28 8d08f18a Kostas Papadimitriou
    // Base object for all our models
29 8d08f18a Kostas Papadimitriou
    models.Model = bb.Model.extend({
30 8d08f18a Kostas Papadimitriou
        sync: snf.api.sync,
31 8d08f18a Kostas Papadimitriou
        api: snf.api,
32 8d08f18a Kostas Papadimitriou
        has_status: false,
33 8d08f18a Kostas Papadimitriou
34 8d08f18a Kostas Papadimitriou
        initialize: function() {
35 8d08f18a Kostas Papadimitriou
            if (this.has_status) {
36 8d08f18a Kostas Papadimitriou
                this.bind("change:status", this.handle_remove);
37 8d08f18a Kostas Papadimitriou
                this.handle_remove();
38 8d08f18a Kostas Papadimitriou
            }
39 8d08f18a Kostas Papadimitriou
            models.Model.__super__.initialize.apply(this, arguments)
40 8d08f18a Kostas Papadimitriou
        },
41 8d08f18a Kostas Papadimitriou
42 8d08f18a Kostas Papadimitriou
        handle_remove: function() {
43 8d08f18a Kostas Papadimitriou
            if (this.get("status") == "DELETED") {
44 8d08f18a Kostas Papadimitriou
                if (this.collection) {
45 8d08f18a Kostas Papadimitriou
                    this.collection.remove(this.id);
46 8d08f18a Kostas Papadimitriou
                }
47 8d08f18a Kostas Papadimitriou
            }
48 8d08f18a Kostas Papadimitriou
        },
49 8d08f18a Kostas Papadimitriou
        
50 8d08f18a Kostas Papadimitriou
        // custom set method to allow submodels to use
51 8d08f18a Kostas Papadimitriou
        // set_<attr> methods for handling the value of each
52 8d08f18a Kostas Papadimitriou
        // attribute and overriding the default set method
53 8d08f18a Kostas Papadimitriou
        // for specific parameters
54 8d08f18a Kostas Papadimitriou
        set: function(params, options) {
55 8d08f18a Kostas Papadimitriou
            _.each(params, _.bind(function(value, key){
56 8d08f18a Kostas Papadimitriou
                if (this["set_" + key]) {
57 8d08f18a Kostas Papadimitriou
                    params[key] = this["set_" + key](value);
58 8d08f18a Kostas Papadimitriou
                }
59 8d08f18a Kostas Papadimitriou
            }, this))
60 8d08f18a Kostas Papadimitriou
            var ret = bb.Model.prototype.set.call(this, params, options);
61 8d08f18a Kostas Papadimitriou
            return ret;
62 8d08f18a Kostas Papadimitriou
        },
63 8d08f18a Kostas Papadimitriou
64 8d08f18a Kostas Papadimitriou
        url: function(options) {
65 8d08f18a Kostas Papadimitriou
            return getUrl.call(this) + "/" + this.id;
66 8d08f18a Kostas Papadimitriou
        },
67 8d08f18a Kostas Papadimitriou
68 8d08f18a Kostas Papadimitriou
        api_path: function(options) {
69 8d08f18a Kostas Papadimitriou
            return this.path + "/" + this.id;
70 8d08f18a Kostas Papadimitriou
        },
71 8d08f18a Kostas Papadimitriou
72 8d08f18a Kostas Papadimitriou
        parse: function(resp, xhr) {
73 8d08f18a Kostas Papadimitriou
            return resp.server;
74 8d08f18a Kostas Papadimitriou
        },
75 8d08f18a Kostas Papadimitriou
76 8d08f18a Kostas Papadimitriou
        remove: function() {
77 8d08f18a Kostas Papadimitriou
            this.api.call(this.api_path(), "delete");
78 8d08f18a Kostas Papadimitriou
        }
79 8d08f18a Kostas Papadimitriou
80 8d08f18a Kostas Papadimitriou
    })
81 8d08f18a Kostas Papadimitriou
    
82 8d08f18a Kostas Papadimitriou
    // Base object for all our model collections
83 8d08f18a Kostas Papadimitriou
    models.Collection = bb.Collection.extend({
84 8d08f18a Kostas Papadimitriou
        sync: snf.api.sync,
85 8d08f18a Kostas Papadimitriou
        api: snf.api,
86 8d08f18a Kostas Papadimitriou
87 8d08f18a Kostas Papadimitriou
        url: function(options) {
88 8d08f18a Kostas Papadimitriou
            return getUrl.call(this) + (options.details || this.details ? '/detail' : '');
89 8d08f18a Kostas Papadimitriou
        },
90 8d08f18a Kostas Papadimitriou
91 8d08f18a Kostas Papadimitriou
        fetch: function(options) {
92 8d08f18a Kostas Papadimitriou
            // default to update
93 8d08f18a Kostas Papadimitriou
            if (!this.noUpdate) {
94 8d08f18a Kostas Papadimitriou
                if (!options) { options = {} };
95 8d08f18a Kostas Papadimitriou
                if (options.update === undefined) { options.update = true };
96 8d08f18a Kostas Papadimitriou
                if (!options.removeMissing && options.refresh) { options.removeMissing = true };
97 8d08f18a Kostas Papadimitriou
            }
98 8d08f18a Kostas Papadimitriou
            // custom event foreach fetch
99 8d08f18a Kostas Papadimitriou
            return bb.Collection.prototype.fetch.call(this, options)
100 8d08f18a Kostas Papadimitriou
        },
101 8d08f18a Kostas Papadimitriou
102 8d08f18a Kostas Papadimitriou
        get_fetcher: function(timeout, fast, limit, initial, params) {
103 8d08f18a Kostas Papadimitriou
            var fetch_params = params;
104 8d08f18a Kostas Papadimitriou
            var timeout = parseInt(timeout);
105 8d08f18a Kostas Papadimitriou
            var fast = fast || 1000;
106 8d08f18a Kostas Papadimitriou
            var limit = limit;
107 8d08f18a Kostas Papadimitriou
            var initial_call = initial || true;
108 8d08f18a Kostas Papadimitriou
            
109 8d08f18a Kostas Papadimitriou
            var last_ajax = undefined;
110 8d08f18a Kostas Papadimitriou
            var cb = _.bind(function(){
111 8d08f18a Kostas Papadimitriou
                updater._ajax = last_ajax;
112 8d08f18a Kostas Papadimitriou
                if (last_ajax) {
113 8d08f18a Kostas Papadimitriou
                    last_ajax.abort();
114 8d08f18a Kostas Papadimitriou
                }
115 8d08f18a Kostas Papadimitriou
                last_ajax = this.fetch(fetch_params);
116 8d08f18a Kostas Papadimitriou
            }, this);
117 8d08f18a Kostas Papadimitriou
            var updater = new snf.api.updateHandler({'callback': cb, timeout:timeout, 
118 8d08f18a Kostas Papadimitriou
                                                    fast:fast, limit:limit, 
119 8d08f18a Kostas Papadimitriou
                                                    call_on_start:initial_call});
120 8d08f18a Kostas Papadimitriou
121 8d08f18a Kostas Papadimitriou
            snf.api.bind("call", _.bind(function(){ updater.faster()}, this));
122 8d08f18a Kostas Papadimitriou
            return updater;
123 8d08f18a Kostas Papadimitriou
        }
124 8d08f18a Kostas Papadimitriou
    });
125 8d08f18a Kostas Papadimitriou
    
126 8d08f18a Kostas Papadimitriou
    // Image model
127 8d08f18a Kostas Papadimitriou
    models.Image = models.Model.extend({
128 8d08f18a Kostas Papadimitriou
        path: 'images',
129 8d08f18a Kostas Papadimitriou
130 8d08f18a Kostas Papadimitriou
        get_size: function() {
131 820ef2f0 Kostas Papadimitriou
            return parseInt(this.get('metadata') ? this.get('metadata').values.size : -1)
132 820ef2f0 Kostas Papadimitriou
        },
133 820ef2f0 Kostas Papadimitriou
134 820ef2f0 Kostas Papadimitriou
        get_os: function() {
135 820ef2f0 Kostas Papadimitriou
            return this.get("OS");
136 8d08f18a Kostas Papadimitriou
        }
137 8d08f18a Kostas Papadimitriou
    });
138 8d08f18a Kostas Papadimitriou
139 8d08f18a Kostas Papadimitriou
    // Flavor model
140 8d08f18a Kostas Papadimitriou
    models.Flavor = models.Model.extend({
141 8d08f18a Kostas Papadimitriou
        path: 'flavors',
142 8d08f18a Kostas Papadimitriou
143 8d08f18a Kostas Papadimitriou
        details_string: function() {
144 8d08f18a Kostas Papadimitriou
            return "{0} CPU, {1}MB, {2}GB".format(this.get('cpu'), this.get('ram'), this.get('disk'));
145 820ef2f0 Kostas Papadimitriou
        },
146 820ef2f0 Kostas Papadimitriou
147 820ef2f0 Kostas Papadimitriou
        get_disk_size: function() {
148 820ef2f0 Kostas Papadimitriou
            return parseInt(this.get("disk") * 1000)
149 820ef2f0 Kostas Papadimitriou
        },
150 820ef2f0 Kostas Papadimitriou
151 8d08f18a Kostas Papadimitriou
    });
152 8d08f18a Kostas Papadimitriou
    
153 8d08f18a Kostas Papadimitriou
    //network vms list helper
154 8d08f18a Kostas Papadimitriou
    var NetworkVMSList = function() {
155 8d08f18a Kostas Papadimitriou
        this.initialize = function() {
156 8d08f18a Kostas Papadimitriou
            this.vms = [];
157 8d08f18a Kostas Papadimitriou
            this.pending = [];
158 8d08f18a Kostas Papadimitriou
            this.pending_for_removal = [];
159 8d08f18a Kostas Papadimitriou
        }
160 8d08f18a Kostas Papadimitriou
        
161 8d08f18a Kostas Papadimitriou
        this.add_pending_for_remove = function(vm_id) {
162 8d08f18a Kostas Papadimitriou
            if (this.pending_for_removal.indexOf(vm_id) == -1) {
163 8d08f18a Kostas Papadimitriou
                this.pending_for_removal.push(vm_id);
164 8d08f18a Kostas Papadimitriou
            }
165 8d08f18a Kostas Papadimitriou
166 8d08f18a Kostas Papadimitriou
            if (this.pending_for_removal.length) {
167 8d08f18a Kostas Papadimitriou
                this.trigger("pending:remove:add");
168 8d08f18a Kostas Papadimitriou
            }
169 8d08f18a Kostas Papadimitriou
        },
170 8d08f18a Kostas Papadimitriou
171 8d08f18a Kostas Papadimitriou
        this.add_pending = function(vm_id) {
172 8d08f18a Kostas Papadimitriou
            if (this.pending.indexOf(vm_id) == -1) {
173 8d08f18a Kostas Papadimitriou
                this.pending[this.pending.length] = vm_id;
174 8d08f18a Kostas Papadimitriou
            }
175 8d08f18a Kostas Papadimitriou
176 8d08f18a Kostas Papadimitriou
            if (this.pending.length) {
177 8d08f18a Kostas Papadimitriou
                this.trigger("pending:add");
178 8d08f18a Kostas Papadimitriou
            }
179 8d08f18a Kostas Papadimitriou
        }
180 8d08f18a Kostas Papadimitriou
181 8d08f18a Kostas Papadimitriou
        this.check_pending = function() {
182 8d08f18a Kostas Papadimitriou
            var len = this.pending.length;
183 8d08f18a Kostas Papadimitriou
            var args = [this.pending];
184 8d08f18a Kostas Papadimitriou
            this.pending = _.difference(this.pending, this.vms);
185 8d08f18a Kostas Papadimitriou
            if (len != this.pending.length) {
186 8d08f18a Kostas Papadimitriou
                if (this.pending.length == 0) {
187 8d08f18a Kostas Papadimitriou
                    this.trigger("pending:clear");
188 8d08f18a Kostas Papadimitriou
                }
189 8d08f18a Kostas Papadimitriou
            }
190 8d08f18a Kostas Papadimitriou
191 8d08f18a Kostas Papadimitriou
            var len = this.pending_for_removal.length;
192 8d08f18a Kostas Papadimitriou
            this.pending_for_removal = _.intersection(this.pending_for_removal, this.vms);
193 8d08f18a Kostas Papadimitriou
            if (this.pending_for_removal.length == 0) {
194 8d08f18a Kostas Papadimitriou
                this.trigger("pending:remove:clear");
195 8d08f18a Kostas Papadimitriou
            }
196 8d08f18a Kostas Papadimitriou
197 8d08f18a Kostas Papadimitriou
        }
198 8d08f18a Kostas Papadimitriou
199 8d08f18a Kostas Papadimitriou
200 8d08f18a Kostas Papadimitriou
        this.add = function(vm_id) {
201 8d08f18a Kostas Papadimitriou
            if (this.vms.indexOf(vm_id) == -1) {
202 8d08f18a Kostas Papadimitriou
                this.vms[this.vms.length] = vm_id;
203 8d08f18a Kostas Papadimitriou
                this.trigger("network:connect", vm_id);
204 8d08f18a Kostas Papadimitriou
                this.check_pending();
205 8d08f18a Kostas Papadimitriou
                return true;
206 8d08f18a Kostas Papadimitriou
            }
207 8d08f18a Kostas Papadimitriou
        }
208 8d08f18a Kostas Papadimitriou
209 8d08f18a Kostas Papadimitriou
        this.remove = function(vm_id) {
210 8d08f18a Kostas Papadimitriou
            if (this.vms.indexOf(vm_id) > -1) {
211 8d08f18a Kostas Papadimitriou
                this.vms = _.without(this.vms, vm_id);
212 8d08f18a Kostas Papadimitriou
                this.trigger("network:disconnect", vm_id);
213 8d08f18a Kostas Papadimitriou
                this.check_pending();
214 8d08f18a Kostas Papadimitriou
                return true;
215 8d08f18a Kostas Papadimitriou
            }
216 8d08f18a Kostas Papadimitriou
        }
217 8d08f18a Kostas Papadimitriou
218 8d08f18a Kostas Papadimitriou
        this.get = function() {
219 8d08f18a Kostas Papadimitriou
            return this.vms;
220 8d08f18a Kostas Papadimitriou
        }
221 8d08f18a Kostas Papadimitriou
222 8d08f18a Kostas Papadimitriou
        this.list = function() {
223 8d08f18a Kostas Papadimitriou
            return storage.vms.filter(_.bind(function(vm){
224 8d08f18a Kostas Papadimitriou
                return this.vms.indexOf(vm.id) > -1;
225 8d08f18a Kostas Papadimitriou
            }, this))
226 8d08f18a Kostas Papadimitriou
        }
227 8d08f18a Kostas Papadimitriou
228 8d08f18a Kostas Papadimitriou
        this.initialize();
229 8d08f18a Kostas Papadimitriou
    };
230 8d08f18a Kostas Papadimitriou
    _.extend(NetworkVMSList.prototype, bb.Events);
231 8d08f18a Kostas Papadimitriou
    
232 8d08f18a Kostas Papadimitriou
    // vm networks list helper
233 8d08f18a Kostas Papadimitriou
    var VMNetworksList = function() {
234 8d08f18a Kostas Papadimitriou
        this.initialize = function() {
235 8d08f18a Kostas Papadimitriou
            this.networks = {};
236 8d08f18a Kostas Papadimitriou
            this.network_ids = [];
237 8d08f18a Kostas Papadimitriou
        }
238 8d08f18a Kostas Papadimitriou
239 8d08f18a Kostas Papadimitriou
        this.add = function(net_id, data) {
240 8d08f18a Kostas Papadimitriou
            if (!this.networks[net_id]) {
241 8d08f18a Kostas Papadimitriou
                this.networks[net_id] = data || {};
242 8d08f18a Kostas Papadimitriou
                this.network_ids[this.network_ids.length] = net_id;
243 8d08f18a Kostas Papadimitriou
                this.trigger("network:connect", net_id);
244 8d08f18a Kostas Papadimitriou
                return true;
245 8d08f18a Kostas Papadimitriou
            }
246 8d08f18a Kostas Papadimitriou
        }
247 8d08f18a Kostas Papadimitriou
248 8d08f18a Kostas Papadimitriou
        this.remove = function(net_id) {
249 8d08f18a Kostas Papadimitriou
            if (this.networks[net_id]) {
250 8d08f18a Kostas Papadimitriou
                delete this.networks[net_id];
251 8d08f18a Kostas Papadimitriou
                this.network_ids = _.without(this.network_ids, net_id);
252 8d08f18a Kostas Papadimitriou
                this.trigger("network:disconnect", net_id);
253 8d08f18a Kostas Papadimitriou
                return true;
254 8d08f18a Kostas Papadimitriou
            }
255 8d08f18a Kostas Papadimitriou
            return false;
256 8d08f18a Kostas Papadimitriou
        }
257 8d08f18a Kostas Papadimitriou
258 8d08f18a Kostas Papadimitriou
        this.get = function() {
259 8d08f18a Kostas Papadimitriou
            return this.networks;
260 8d08f18a Kostas Papadimitriou
        }
261 8d08f18a Kostas Papadimitriou
262 8d08f18a Kostas Papadimitriou
        this.list = function() {
263 8d08f18a Kostas Papadimitriou
            return storage.networks.filter(_.bind(function(net){
264 8d08f18a Kostas Papadimitriou
                return this.network_ids.indexOf(net.id) > -1;
265 8d08f18a Kostas Papadimitriou
            }, this))
266 8d08f18a Kostas Papadimitriou
        }
267 8d08f18a Kostas Papadimitriou
268 8d08f18a Kostas Papadimitriou
        this.initialize();
269 8d08f18a Kostas Papadimitriou
    };
270 8d08f18a Kostas Papadimitriou
    _.extend(VMNetworksList.prototype, bb.Events);
271 8d08f18a Kostas Papadimitriou
272 8d08f18a Kostas Papadimitriou
    // Image model
273 8d08f18a Kostas Papadimitriou
    models.Network = models.Model.extend({
274 8d08f18a Kostas Papadimitriou
        path: 'networks',
275 8d08f18a Kostas Papadimitriou
        has_status: true,
276 8d08f18a Kostas Papadimitriou
        
277 8d08f18a Kostas Papadimitriou
        initialize: function() {
278 8d08f18a Kostas Papadimitriou
            this.vms = new NetworkVMSList();
279 8d08f18a Kostas Papadimitriou
            this.vms.bind("pending:add", _.bind(this.handle_pending_connections, this, "add"));
280 8d08f18a Kostas Papadimitriou
            this.vms.bind("pending:clear", _.bind(this.handle_pending_connections, this, "clear"));
281 8d08f18a Kostas Papadimitriou
            this.vms.bind("pending:remove:add", _.bind(this.handle_pending_connections, this, "add"));
282 8d08f18a Kostas Papadimitriou
            this.vms.bind("pending:remove:clear", _.bind(this.handle_pending_connections, this, "clear"));
283 8d08f18a Kostas Papadimitriou
284 8d08f18a Kostas Papadimitriou
            ret = models.Network.__super__.initialize.apply(this, arguments);
285 8d08f18a Kostas Papadimitriou
286 8d08f18a Kostas Papadimitriou
            storage.vms.bind("change:linked_to_nets", _.bind(this.update_connections, this, "vm:change"));
287 8d08f18a Kostas Papadimitriou
            storage.vms.bind("add", _.bind(this.update_connections, this, "add"));
288 8d08f18a Kostas Papadimitriou
            storage.vms.bind("remove", _.bind(this.update_connections, this, "remove"));
289 8d08f18a Kostas Papadimitriou
            storage.vms.bind("reset", _.bind(this.update_connections, this, "reset"));
290 8d08f18a Kostas Papadimitriou
            this.bind("change:linked_to", _.bind(this.update_connections, this, "net:change"));
291 8d08f18a Kostas Papadimitriou
            this.update_connections();
292 8d08f18a Kostas Papadimitriou
            this.update_state();
293 8d08f18a Kostas Papadimitriou
            return ret;
294 8d08f18a Kostas Papadimitriou
        },
295 8d08f18a Kostas Papadimitriou
296 8d08f18a Kostas Papadimitriou
        update_state: function() {
297 8d08f18a Kostas Papadimitriou
            if (this.vms.pending.length) {
298 8d08f18a Kostas Papadimitriou
                this.set({state: "CONNECTING"});
299 8d08f18a Kostas Papadimitriou
                return
300 8d08f18a Kostas Papadimitriou
            }
301 8d08f18a Kostas Papadimitriou
            if (this.vms.pending_for_removal.length) {
302 8d08f18a Kostas Papadimitriou
                this.set({state: "DISCONNECTING"});
303 8d08f18a Kostas Papadimitriou
                return
304 8d08f18a Kostas Papadimitriou
            }   
305 8d08f18a Kostas Papadimitriou
            
306 8d08f18a Kostas Papadimitriou
            var firewalling = false;
307 8d08f18a Kostas Papadimitriou
            _.each(this.vms.get(), _.bind(function(vm_id){
308 8d08f18a Kostas Papadimitriou
                var vm = storage.vms.get(vm_id);
309 8d08f18a Kostas Papadimitriou
                if (!vm) { return };
310 8d08f18a Kostas Papadimitriou
                if (!_.isEmpty(vm.pending_firewalls)) {
311 8d08f18a Kostas Papadimitriou
                    this.set({state:"FIREWALLING"});
312 8d08f18a Kostas Papadimitriou
                    firewalling = true;
313 8d08f18a Kostas Papadimitriou
                    return false;
314 8d08f18a Kostas Papadimitriou
                }
315 8d08f18a Kostas Papadimitriou
            },this));
316 8d08f18a Kostas Papadimitriou
            if (firewalling) { return };
317 8d08f18a Kostas Papadimitriou
318 8d08f18a Kostas Papadimitriou
            this.set({state:"NORMAL"});
319 8d08f18a Kostas Papadimitriou
        },
320 8d08f18a Kostas Papadimitriou
321 8d08f18a Kostas Papadimitriou
        handle_pending_connections: function(action) {
322 8d08f18a Kostas Papadimitriou
            this.update_state();
323 8d08f18a Kostas Papadimitriou
        },
324 8d08f18a Kostas Papadimitriou
325 8d08f18a Kostas Papadimitriou
        // handle vm/network connections
326 8d08f18a Kostas Papadimitriou
        update_connections: function(action, model) {
327 8d08f18a Kostas Papadimitriou
            
328 8d08f18a Kostas Papadimitriou
            // vm removed disconnect vm from network
329 8d08f18a Kostas Papadimitriou
            if (action == "remove") {
330 8d08f18a Kostas Papadimitriou
                var removed_from_net = this.vms.remove(model.id);
331 8d08f18a Kostas Papadimitriou
                var removed_from_vm = model.networks.remove(this.id);
332 8d08f18a Kostas Papadimitriou
                if (removed_from_net) {this.trigger("vm:disconnect", model, this); this.change()};
333 8d08f18a Kostas Papadimitriou
                if (removed_from_vm) {vm.trigger("network:disconnect", this, model); this.change()};
334 8d08f18a Kostas Papadimitriou
                return;
335 8d08f18a Kostas Papadimitriou
            }
336 8d08f18a Kostas Papadimitriou
            
337 8d08f18a Kostas Papadimitriou
            // update links for all vms
338 8d08f18a Kostas Papadimitriou
            var links = this.get("linked_to");
339 8d08f18a Kostas Papadimitriou
            storage.vms.each(_.bind(function(vm) {
340 8d08f18a Kostas Papadimitriou
                var vm_links = vm.get("linked_to") || [];
341 8d08f18a Kostas Papadimitriou
                if (vm_links.indexOf(this.id) > -1) {
342 8d08f18a Kostas Papadimitriou
                    // vm has connection to current network
343 8d08f18a Kostas Papadimitriou
                    if (links.indexOf(vm.id) > -1) {
344 8d08f18a Kostas Papadimitriou
                        // and network has connection to vm, so try
345 8d08f18a Kostas Papadimitriou
                        // to append it
346 8d08f18a Kostas Papadimitriou
                        var add_to_net = this.vms.add(vm.id);
347 8d08f18a Kostas Papadimitriou
                        var index = _.indexOf(vm_links, this.id);
348 8d08f18a Kostas Papadimitriou
                        var add_to_vm = vm.networks.add(this.id, vm.get("linked_to_nets")[index]);
349 8d08f18a Kostas Papadimitriou
                        
350 8d08f18a Kostas Papadimitriou
                        // call only if connection did not existed
351 8d08f18a Kostas Papadimitriou
                        if (add_to_net) {this.trigger("vm:connect", vm, this); this.change()};
352 8d08f18a Kostas Papadimitriou
                        if (add_to_vm) {vm.trigger("network:connect", this, vm); vm.change()};
353 8d08f18a Kostas Papadimitriou
                    } else {
354 8d08f18a Kostas Papadimitriou
                        // no connection, try to remove it
355 8d08f18a Kostas Papadimitriou
                        var removed_from_net = this.vms.remove(vm.id);
356 8d08f18a Kostas Papadimitriou
                        var removed_from_vm = vm.networks.remove(this.id);
357 8d08f18a Kostas Papadimitriou
                        if (removed_from_net) {this.trigger("vm:disconnect", vm, this); this.change()};
358 8d08f18a Kostas Papadimitriou
                        if (removed_from_vm) {vm.trigger("network:disconnect", this, vm); vm.change()};
359 8d08f18a Kostas Papadimitriou
                    }
360 8d08f18a Kostas Papadimitriou
                } else {
361 8d08f18a Kostas Papadimitriou
                    // vm has no connection to current network, try to remove it
362 8d08f18a Kostas Papadimitriou
                    var removed_from_net = this.vms.remove(vm.id);
363 8d08f18a Kostas Papadimitriou
                    var removed_from_vm = vm.networks.remove(this.id);
364 8d08f18a Kostas Papadimitriou
                    if (removed_from_net) {this.trigger("vm:disconnect", vm, this); this.change()};
365 8d08f18a Kostas Papadimitriou
                    if (removed_from_vm) {vm.trigger("network:disconnect", this, vm); vm.change()};
366 8d08f18a Kostas Papadimitriou
                }
367 8d08f18a Kostas Papadimitriou
            },this));
368 8d08f18a Kostas Papadimitriou
        },
369 8d08f18a Kostas Papadimitriou
370 8d08f18a Kostas Papadimitriou
        is_public: function() {
371 8d08f18a Kostas Papadimitriou
            return this.id == "public";
372 8d08f18a Kostas Papadimitriou
        },
373 8d08f18a Kostas Papadimitriou
374 8d08f18a Kostas Papadimitriou
        contains_vm: function(vm) {
375 8d08f18a Kostas Papadimitriou
            var net_vm_exists = this.vms.get().indexOf(vm.id) > -1;
376 8d08f18a Kostas Papadimitriou
            var vm_net_exists = vm.is_connected_to(this);
377 8d08f18a Kostas Papadimitriou
            return net_vm_exists && vm_net_exists;
378 8d08f18a Kostas Papadimitriou
        },
379 8d08f18a Kostas Papadimitriou
380 8d08f18a Kostas Papadimitriou
        add_vm: function (vm, callback) {
381 8d08f18a Kostas Papadimitriou
            return this.api.call(this.api_path() + "/action", "create", 
382 8d08f18a Kostas Papadimitriou
                                 {add:{serverRef:"" + vm.id}},
383 8d08f18a Kostas Papadimitriou
                                 _.bind(function(){
384 8d08f18a Kostas Papadimitriou
                                     this.vms.add_pending(vm.id);
385 8d08f18a Kostas Papadimitriou
                                     if (callback) {callback()}
386 8d08f18a Kostas Papadimitriou
                                 },this));
387 8d08f18a Kostas Papadimitriou
        },
388 8d08f18a Kostas Papadimitriou
389 8d08f18a Kostas Papadimitriou
        remove_vm: function (vm, callback) {
390 8d08f18a Kostas Papadimitriou
            return this.api.call(this.api_path() + "/action", "create", 
391 8d08f18a Kostas Papadimitriou
                                 {remove:{serverRef:"" + vm.id}},
392 8d08f18a Kostas Papadimitriou
                                 _.bind(function(){
393 8d08f18a Kostas Papadimitriou
                                     this.vms.add_pending_for_remove(vm.id);
394 8d08f18a Kostas Papadimitriou
                                     if (callback) {callback()}
395 8d08f18a Kostas Papadimitriou
                                 },this));
396 8d08f18a Kostas Papadimitriou
        },
397 8d08f18a Kostas Papadimitriou
398 8d08f18a Kostas Papadimitriou
        rename: function(name, callback) {
399 8d08f18a Kostas Papadimitriou
            return this.api.call(this.api_path(), "update", {network:{name:name}}, callback);
400 8d08f18a Kostas Papadimitriou
        },
401 8d08f18a Kostas Papadimitriou
402 8d08f18a Kostas Papadimitriou
        get_connectable_vms: function() {
403 8d08f18a Kostas Papadimitriou
            var servers = this.vms.list();
404 8d08f18a Kostas Papadimitriou
            return storage.vms.filter(function(vm){return servers.indexOf(vm.id) == -1})
405 8d08f18a Kostas Papadimitriou
        },
406 8d08f18a Kostas Papadimitriou
407 8d08f18a Kostas Papadimitriou
        state_message: function() {
408 8d08f18a Kostas Papadimitriou
            if (this.get("state") == "NORMAL" && this.is_public()) {
409 8d08f18a Kostas Papadimitriou
                return "Public network";
410 8d08f18a Kostas Papadimitriou
            }
411 8d08f18a Kostas Papadimitriou
412 8d08f18a Kostas Papadimitriou
            return models.Network.STATES[this.get("state")];
413 8d08f18a Kostas Papadimitriou
        },
414 8d08f18a Kostas Papadimitriou
415 8d08f18a Kostas Papadimitriou
        in_progress: function() {
416 8d08f18a Kostas Papadimitriou
            return models.Network.STATES_TRANSITIONS[this.get("state")] != undefined;
417 8d08f18a Kostas Papadimitriou
        }
418 8d08f18a Kostas Papadimitriou
    });
419 8d08f18a Kostas Papadimitriou
    
420 8d08f18a Kostas Papadimitriou
    models.Network.STATES = {
421 8d08f18a Kostas Papadimitriou
        'NORMAL': 'Private network',
422 8d08f18a Kostas Papadimitriou
        'CONNECTING': 'Connecting...',
423 8d08f18a Kostas Papadimitriou
        'DISCONNECTING': 'Disconnecting...',
424 8d08f18a Kostas Papadimitriou
        'FIREWALLING': 'Firewall update...'
425 8d08f18a Kostas Papadimitriou
    }
426 8d08f18a Kostas Papadimitriou
427 8d08f18a Kostas Papadimitriou
    models.Network.STATES_TRANSITIONS = {
428 8d08f18a Kostas Papadimitriou
        'CONNECTING': ['NORMAL'],
429 8d08f18a Kostas Papadimitriou
        'DISCONNECTING': ['NORMAL'],
430 8d08f18a Kostas Papadimitriou
        'FIREWALLING': ['NORMAL']
431 8d08f18a Kostas Papadimitriou
    }
432 8d08f18a Kostas Papadimitriou
433 8d08f18a Kostas Papadimitriou
    // Virtualmachine model
434 8d08f18a Kostas Papadimitriou
    models.VM = models.Model.extend({
435 8d08f18a Kostas Papadimitriou
436 8d08f18a Kostas Papadimitriou
        path: 'servers',
437 8d08f18a Kostas Papadimitriou
        has_status: true,
438 8d08f18a Kostas Papadimitriou
        initialize: function(params) {
439 8d08f18a Kostas Papadimitriou
            this.networks = new VMNetworksList();
440 8d08f18a Kostas Papadimitriou
            
441 8d08f18a Kostas Papadimitriou
            this.pending_firewalls = {};
442 8d08f18a Kostas Papadimitriou
            
443 8d08f18a Kostas Papadimitriou
            models.VM.__super__.initialize.apply(this, arguments);
444 8d08f18a Kostas Papadimitriou
445 8d08f18a Kostas Papadimitriou
            this.set({state: params.status || "ERROR"});
446 8d08f18a Kostas Papadimitriou
            this.log = new snf.logging.logger("VM " + this.id);
447 8d08f18a Kostas Papadimitriou
            this.pending_action = undefined;
448 8d08f18a Kostas Papadimitriou
            
449 8d08f18a Kostas Papadimitriou
            // init stats parameter
450 8d08f18a Kostas Papadimitriou
            this.set({'stats': undefined}, {silent: true});
451 8d08f18a Kostas Papadimitriou
            // defaults to not update the stats
452 8d08f18a Kostas Papadimitriou
            // each view should handle this vm attribute 
453 8d08f18a Kostas Papadimitriou
            // depending on if it displays stat images or not
454 8d08f18a Kostas Papadimitriou
            this.do_update_stats = false;
455 8d08f18a Kostas Papadimitriou
            
456 8d08f18a Kostas Papadimitriou
            // interval time
457 8d08f18a Kostas Papadimitriou
            // this will dynamicaly change if the server responds that
458 8d08f18a Kostas Papadimitriou
            // images get refreshed on different intervals
459 8d08f18a Kostas Papadimitriou
            this.stats_update_interval = synnefo.config.STATS_INTERVAL || 5000;
460 8d08f18a Kostas Papadimitriou
461 8d08f18a Kostas Papadimitriou
            // initialize interval
462 8d08f18a Kostas Papadimitriou
            this.init_stats_intervals(this.stats_update_interval);
463 8d08f18a Kostas Papadimitriou
            
464 8d08f18a Kostas Papadimitriou
            // clear stats intervals on update
465 8d08f18a Kostas Papadimitriou
            this.bind("remove", _.bind(function(){
466 8d08f18a Kostas Papadimitriou
                try {
467 8d08f18a Kostas Papadimitriou
                    window.clearInterval(this.stats_interval);
468 8d08f18a Kostas Papadimitriou
                } catch (err) {};
469 8d08f18a Kostas Papadimitriou
            }, this));
470 8d08f18a Kostas Papadimitriou
            
471 8d08f18a Kostas Papadimitriou
            this.bind("change:progress", _.bind(this.update_building_progress, this));
472 8d08f18a Kostas Papadimitriou
            this.update_building_progress();
473 8d08f18a Kostas Papadimitriou
474 8d08f18a Kostas Papadimitriou
            this.bind("change:firewalls", _.bind(this.handle_firewall_change, this));
475 8d08f18a Kostas Papadimitriou
            
476 8d08f18a Kostas Papadimitriou
            // default values
477 8d08f18a Kostas Papadimitriou
            this.set({linked_to_nets:this.get("linked_to_nets") || []});
478 8d08f18a Kostas Papadimitriou
            this.set({firewalls:this.get("firewalls") || []});
479 8d08f18a Kostas Papadimitriou
        },
480 8d08f18a Kostas Papadimitriou
481 8d08f18a Kostas Papadimitriou
        handle_firewall_change: function() {
482 8d08f18a Kostas Papadimitriou
483 8d08f18a Kostas Papadimitriou
        },
484 8d08f18a Kostas Papadimitriou
        
485 8d08f18a Kostas Papadimitriou
        set_linked_to_nets: function(data) {
486 8d08f18a Kostas Papadimitriou
            this.set({"linked_to":_.map(data, function(n){ return n.id})});
487 8d08f18a Kostas Papadimitriou
            return data;
488 8d08f18a Kostas Papadimitriou
        },
489 8d08f18a Kostas Papadimitriou
490 8d08f18a Kostas Papadimitriou
        is_connected_to: function(net) {
491 8d08f18a Kostas Papadimitriou
            return _.filter(this.networks.list(), function(n){return n.id == net.id}).length > 0;
492 8d08f18a Kostas Papadimitriou
        },
493 8d08f18a Kostas Papadimitriou
        
494 8d08f18a Kostas Papadimitriou
        status: function(st) {
495 8d08f18a Kostas Papadimitriou
            if (!st) { return this.get("status")}
496 8d08f18a Kostas Papadimitriou
            return this.set({status:st});
497 8d08f18a Kostas Papadimitriou
        },
498 8d08f18a Kostas Papadimitriou
499 8d08f18a Kostas Papadimitriou
        set_status: function(st) {
500 8d08f18a Kostas Papadimitriou
            var new_state = this.state_for_api_status(st);
501 8d08f18a Kostas Papadimitriou
            var transition = false;
502 8d08f18a Kostas Papadimitriou
503 8d08f18a Kostas Papadimitriou
            if (this.state() != new_state) {
504 8d08f18a Kostas Papadimitriou
                if (models.VM.STATES_TRANSITIONS[this.state()]) {
505 8d08f18a Kostas Papadimitriou
                    transition = this.state();
506 8d08f18a Kostas Papadimitriou
                }
507 8d08f18a Kostas Papadimitriou
            }
508 8d08f18a Kostas Papadimitriou
            
509 8d08f18a Kostas Papadimitriou
            // call it silently to avoid double change trigger
510 8d08f18a Kostas Papadimitriou
            this.set({'state': this.state_for_api_status(st)}, {silent: true});
511 8d08f18a Kostas Papadimitriou
            
512 8d08f18a Kostas Papadimitriou
            // trigger transition
513 8d08f18a Kostas Papadimitriou
            if (transition) { this.trigger("transition", {from:transition, to:new_state}) };
514 8d08f18a Kostas Papadimitriou
            return st;
515 8d08f18a Kostas Papadimitriou
        },
516 8d08f18a Kostas Papadimitriou
517 8d08f18a Kostas Papadimitriou
        update_building_progress: function() {
518 8d08f18a Kostas Papadimitriou
            if (this.is_building()) {
519 8d08f18a Kostas Papadimitriou
                var progress = this.get("progress");
520 8d08f18a Kostas Papadimitriou
                if (progress == 0) {
521 8d08f18a Kostas Papadimitriou
                    this.state("BUILD_INIT");
522 8d08f18a Kostas Papadimitriou
                    this.set({progress_message: BUILDING_MESSAGES['INIT']});
523 8d08f18a Kostas Papadimitriou
                }
524 8d08f18a Kostas Papadimitriou
                if (progress > 0 && progress < 99) {
525 8d08f18a Kostas Papadimitriou
                    this.state("BUILD_COPY");
526 8d08f18a Kostas Papadimitriou
                    var params = this.get_copy_details(true);
527 8d08f18a Kostas Papadimitriou
                    this.set({progress_message: BUILDING_MESSAGES['COPY'].format(params.copy, 
528 8d08f18a Kostas Papadimitriou
                                                                                 params.size, 
529 8d08f18a Kostas Papadimitriou
                                                                                 params.progress)});
530 8d08f18a Kostas Papadimitriou
                }
531 8d08f18a Kostas Papadimitriou
                if (progress == 100) {
532 8d08f18a Kostas Papadimitriou
                    this.state("BUILD_FINAL");
533 8d08f18a Kostas Papadimitriou
                    this.set({progress_message: BUILDING_MESSAGES['FINAL']});
534 8d08f18a Kostas Papadimitriou
                }
535 8d08f18a Kostas Papadimitriou
            } else {
536 8d08f18a Kostas Papadimitriou
            }
537 8d08f18a Kostas Papadimitriou
        },
538 8d08f18a Kostas Papadimitriou
539 8d08f18a Kostas Papadimitriou
        get_copy_details: function(human, image) {
540 8d08f18a Kostas Papadimitriou
            var human = human || false;
541 8d08f18a Kostas Papadimitriou
            var image = image || this.get_image();
542 8d08f18a Kostas Papadimitriou
543 8d08f18a Kostas Papadimitriou
            var progress = this.get('progress');
544 8d08f18a Kostas Papadimitriou
            var size = image.get_size();
545 8d08f18a Kostas Papadimitriou
            var size_copied = (size * progress / 100).toFixed(2);
546 8d08f18a Kostas Papadimitriou
            
547 8d08f18a Kostas Papadimitriou
            if (human) {
548 8d08f18a Kostas Papadimitriou
                size = util.readablizeBytes(size*1024*1024);
549 8d08f18a Kostas Papadimitriou
                size_copied = util.readablizeBytes(size_copied*1024*1024);
550 8d08f18a Kostas Papadimitriou
            }
551 8d08f18a Kostas Papadimitriou
            return {'progress': progress, 'size': size, 'copy': size_copied};
552 8d08f18a Kostas Papadimitriou
        },
553 8d08f18a Kostas Papadimitriou
554 8d08f18a Kostas Papadimitriou
        // clear and reinitialize update interval
555 8d08f18a Kostas Papadimitriou
        init_stats_intervals: function (interval) {
556 8d08f18a Kostas Papadimitriou
            try {
557 8d08f18a Kostas Papadimitriou
                window.clearInterval(this.stats_interval);
558 8d08f18a Kostas Papadimitriou
            } catch (err){}
559 8d08f18a Kostas Papadimitriou
            //this.stats_interval = window.setInterval(_.bind(this.update_stats, this), interval);
560 8d08f18a Kostas Papadimitriou
            //this.update_stats(true);
561 8d08f18a Kostas Papadimitriou
        },
562 8d08f18a Kostas Papadimitriou
        
563 8d08f18a Kostas Papadimitriou
        // do the api call
564 8d08f18a Kostas Papadimitriou
        update_stats: function(force) {
565 8d08f18a Kostas Papadimitriou
            // do not update stats if flag not set
566 8d08f18a Kostas Papadimitriou
            if (!this.do_update_stats && !force) {
567 8d08f18a Kostas Papadimitriou
                return;
568 8d08f18a Kostas Papadimitriou
            }
569 8d08f18a Kostas Papadimitriou
            
570 8d08f18a Kostas Papadimitriou
            // make the api call, execute handle_stats_update on sucess
571 8d08f18a Kostas Papadimitriou
            // TODO: onError handler ???
572 8d08f18a Kostas Papadimitriou
            stats_url = this.url() + "/stats";
573 8d08f18a Kostas Papadimitriou
            this.sync("GET", this, {url: stats_url, refresh:true, success: _.bind(this.handle_stats_update, this)});
574 8d08f18a Kostas Papadimitriou
        },
575 8d08f18a Kostas Papadimitriou
        
576 8d08f18a Kostas Papadimitriou
        // this method gets executed after a successful vm stats api call
577 8d08f18a Kostas Papadimitriou
        handle_stats_update: function(data) {
578 8d08f18a Kostas Papadimitriou
            // avoid browser caching
579 8d08f18a Kostas Papadimitriou
            if (data.stats && _.size(data.stats) > 0) {
580 8d08f18a Kostas Papadimitriou
                var ts = $.now();
581 8d08f18a Kostas Papadimitriou
                var stats = data.stats;
582 8d08f18a Kostas Papadimitriou
                _.each(['cpuBar', 'cpuTimeSeries', 'netBar', 'netTimeSeries'], function(k) {
583 8d08f18a Kostas Papadimitriou
                    stats[k] = stats[k] + "?_=" + ts;
584 8d08f18a Kostas Papadimitriou
                })
585 8d08f18a Kostas Papadimitriou
                data.stats = stats;
586 8d08f18a Kostas Papadimitriou
            }
587 8d08f18a Kostas Papadimitriou
            this.set({'stats': data.stats}, {silent:true});
588 8d08f18a Kostas Papadimitriou
            // trigger the event
589 8d08f18a Kostas Papadimitriou
            this.trigger("stats:update");
590 8d08f18a Kostas Papadimitriou
    
591 8d08f18a Kostas Papadimitriou
            // do we need to change the interval ??
592 8d08f18a Kostas Papadimitriou
            if (data.stats.refresh * 1000 != this.stats_update_interval) {
593 8d08f18a Kostas Papadimitriou
                this.stats_update_interval = data.stats.refresh * 1000;
594 8d08f18a Kostas Papadimitriou
                this.init_stats_intervals(this.stats_update_interval);
595 8d08f18a Kostas Papadimitriou
            }
596 8d08f18a Kostas Papadimitriou
        },
597 8d08f18a Kostas Papadimitriou
        
598 8d08f18a Kostas Papadimitriou
        // helper method that sets the do_update_stats
599 8d08f18a Kostas Papadimitriou
        // in the future this method could also make an api call
600 8d08f18a Kostas Papadimitriou
        // immediaetly if needed
601 8d08f18a Kostas Papadimitriou
        enable_stats_update: function() {
602 8d08f18a Kostas Papadimitriou
            this.do_update_stats = true;
603 8d08f18a Kostas Papadimitriou
        },
604 122850c5 Kostas Papadimitriou
605 122850c5 Kostas Papadimitriou
        require_reboot: function() {
606 122850c5 Kostas Papadimitriou
            if (this.is_active()) {
607 122850c5 Kostas Papadimitriou
                this.set({'reboot_required': true});
608 122850c5 Kostas Papadimitriou
            }
609 122850c5 Kostas Papadimitriou
        },
610 8d08f18a Kostas Papadimitriou
        
611 8d08f18a Kostas Papadimitriou
        set_pending_action: function(data) {
612 8d08f18a Kostas Papadimitriou
            this.pending_action = data;
613 8d08f18a Kostas Papadimitriou
            return data;
614 8d08f18a Kostas Papadimitriou
        },
615 8d08f18a Kostas Papadimitriou
616 8d08f18a Kostas Papadimitriou
        // machine has pending action
617 8d08f18a Kostas Papadimitriou
        update_pending_action: function(action, force) {
618 8d08f18a Kostas Papadimitriou
            this.set({pending_action: action});
619 8d08f18a Kostas Papadimitriou
        },
620 8d08f18a Kostas Papadimitriou
621 8d08f18a Kostas Papadimitriou
        clear_pending_action: function() {
622 8d08f18a Kostas Papadimitriou
            this.set({pending_action: undefined});
623 8d08f18a Kostas Papadimitriou
        },
624 8d08f18a Kostas Papadimitriou
625 8d08f18a Kostas Papadimitriou
        has_pending_action: function() {
626 8d08f18a Kostas Papadimitriou
            return this.get("pending_action") ? this.get("pending_action") : false;
627 8d08f18a Kostas Papadimitriou
        },
628 8d08f18a Kostas Papadimitriou
        
629 8d08f18a Kostas Papadimitriou
        // machine is active
630 8d08f18a Kostas Papadimitriou
        is_active: function() {
631 8d08f18a Kostas Papadimitriou
            return models.VM.ACTIVE_STATES.indexOf(this.state()) > -1;
632 8d08f18a Kostas Papadimitriou
        },
633 8d08f18a Kostas Papadimitriou
        
634 122850c5 Kostas Papadimitriou
        // machine is building 
635 8d08f18a Kostas Papadimitriou
        is_building: function() {
636 8d08f18a Kostas Papadimitriou
            return models.VM.BUILDING_STATES.indexOf(this.state()) > -1;
637 8d08f18a Kostas Papadimitriou
        },
638 8d08f18a Kostas Papadimitriou
639 8d08f18a Kostas Papadimitriou
        // user can connect to machine
640 8d08f18a Kostas Papadimitriou
        is_connectable: function() {
641 8d08f18a Kostas Papadimitriou
            // check if ips exist
642 8d08f18a Kostas Papadimitriou
            if (!this.get_addresses().ip4 && !this.get_addresses().ip6) {
643 8d08f18a Kostas Papadimitriou
                return false;
644 8d08f18a Kostas Papadimitriou
            }
645 8d08f18a Kostas Papadimitriou
            return models.VM.CONNECT_STATES.indexOf(this.state()) > -1;
646 8d08f18a Kostas Papadimitriou
        },
647 8d08f18a Kostas Papadimitriou
        
648 8d08f18a Kostas Papadimitriou
        set_firewalls: function(data) {
649 8d08f18a Kostas Papadimitriou
            _.each(data, _.bind(function(val, key){
650 8d08f18a Kostas Papadimitriou
                if (this.pending_firewalls && this.pending_firewalls[key] && this.pending_firewalls[key] == val) {
651 122850c5 Kostas Papadimitriou
                        this.require_reboot();
652 8d08f18a Kostas Papadimitriou
                        this.remove_pending_firewall(key, val);
653 8d08f18a Kostas Papadimitriou
                }
654 8d08f18a Kostas Papadimitriou
            }, this));
655 8d08f18a Kostas Papadimitriou
            return data;
656 8d08f18a Kostas Papadimitriou
        },
657 8d08f18a Kostas Papadimitriou
658 8d08f18a Kostas Papadimitriou
        remove_pending_firewall: function(net_id, value) {
659 8d08f18a Kostas Papadimitriou
            if (this.pending_firewalls[net_id] == value) {
660 8d08f18a Kostas Papadimitriou
                delete this.pending_firewalls[net_id];
661 8d08f18a Kostas Papadimitriou
                storage.networks.get(net_id).update_state();
662 8d08f18a Kostas Papadimitriou
            }
663 8d08f18a Kostas Papadimitriou
        },
664 8d08f18a Kostas Papadimitriou
            
665 8d08f18a Kostas Papadimitriou
        remove_meta: function(key, complete, error) {
666 8d08f18a Kostas Papadimitriou
            var url = this.api_path() + "/meta/" + key;
667 8d08f18a Kostas Papadimitriou
            this.api.call(url, "delete", undefined, complete, error);
668 8d08f18a Kostas Papadimitriou
        },
669 8d08f18a Kostas Papadimitriou
670 8d08f18a Kostas Papadimitriou
        save_meta: function(meta, complete, error) {
671 8d08f18a Kostas Papadimitriou
            var url = this.api_path() + "/meta/" + meta.key;
672 8d08f18a Kostas Papadimitriou
            var payload = {meta:{}};
673 8d08f18a Kostas Papadimitriou
            payload.meta[meta.key] = meta.value;
674 8d08f18a Kostas Papadimitriou
675 8d08f18a Kostas Papadimitriou
            this.api.call(url, "update", payload, complete, error)
676 8d08f18a Kostas Papadimitriou
        },
677 8d08f18a Kostas Papadimitriou
678 8d08f18a Kostas Papadimitriou
        set_firewall: function(net_id, value, callback) {
679 8d08f18a Kostas Papadimitriou
            if (this.get("firewalls") && this.get("firewalls")[net_id] == value) { return }
680 122850c5 Kostas Papadimitriou
681 8d08f18a Kostas Papadimitriou
            this.pending_firewalls[net_id] = value;
682 8d08f18a Kostas Papadimitriou
            this.trigger("change", this, this);
683 8d08f18a Kostas Papadimitriou
            this.api.call(this.api_path() + "/action", "create", {"firewallProfile":{"profile":value}}, callback);
684 8d08f18a Kostas Papadimitriou
            storage.networks.get(net_id).update_state();
685 8d08f18a Kostas Papadimitriou
        },
686 8d08f18a Kostas Papadimitriou
687 8d08f18a Kostas Papadimitriou
        firewall_pending: function(net_id) {
688 8d08f18a Kostas Papadimitriou
            return this.pending_firewalls[net_id] != undefined;
689 8d08f18a Kostas Papadimitriou
        },
690 8d08f18a Kostas Papadimitriou
        
691 8d08f18a Kostas Papadimitriou
        // update/get the state of the machine
692 8d08f18a Kostas Papadimitriou
        state: function() {
693 8d08f18a Kostas Papadimitriou
            var args = slice.call(arguments);
694 8d08f18a Kostas Papadimitriou
                
695 8d08f18a Kostas Papadimitriou
            // TODO: it might not be a good idea to let api set the state
696 8d08f18a Kostas Papadimitriou
            if (args.length > 0 && models.VM.STATES.indexOf(args[0]) > -1) {
697 8d08f18a Kostas Papadimitriou
                this.set({'state': args[0]});
698 8d08f18a Kostas Papadimitriou
            }
699 8d08f18a Kostas Papadimitriou
700 8d08f18a Kostas Papadimitriou
            return this.get('state');
701 8d08f18a Kostas Papadimitriou
        },
702 8d08f18a Kostas Papadimitriou
        
703 8d08f18a Kostas Papadimitriou
        // get the state that the api status corresponds to
704 8d08f18a Kostas Papadimitriou
        state_for_api_status: function(status) {
705 8d08f18a Kostas Papadimitriou
            return this.state_transition(this.state(), status);
706 8d08f18a Kostas Papadimitriou
        },
707 8d08f18a Kostas Papadimitriou
        
708 8d08f18a Kostas Papadimitriou
        // vm state equals vm api status
709 8d08f18a Kostas Papadimitriou
        state_is_status: function(state) {
710 8d08f18a Kostas Papadimitriou
            return models.VM.STATUSES.indexOf(state) != -1;
711 8d08f18a Kostas Papadimitriou
        },
712 8d08f18a Kostas Papadimitriou
        
713 8d08f18a Kostas Papadimitriou
        // get transition state for the corresponging api status
714 8d08f18a Kostas Papadimitriou
        state_transition: function(state, new_status) {
715 8d08f18a Kostas Papadimitriou
            var statuses = models.VM.STATES_TRANSITIONS[state];
716 8d08f18a Kostas Papadimitriou
            if (statuses) {
717 8d08f18a Kostas Papadimitriou
                if (statuses.indexOf(new_status) > -1) {
718 8d08f18a Kostas Papadimitriou
                    return new_status;
719 8d08f18a Kostas Papadimitriou
                } else {
720 8d08f18a Kostas Papadimitriou
                    return state;
721 8d08f18a Kostas Papadimitriou
                }
722 8d08f18a Kostas Papadimitriou
            } else {
723 8d08f18a Kostas Papadimitriou
                return new_status;
724 8d08f18a Kostas Papadimitriou
            }
725 8d08f18a Kostas Papadimitriou
        },
726 8d08f18a Kostas Papadimitriou
        
727 8d08f18a Kostas Papadimitriou
        // the current vm state is a transition state
728 8d08f18a Kostas Papadimitriou
        in_transition: function() {
729 8d08f18a Kostas Papadimitriou
            return models.VM.TRANSITION_STATES.indexOf(this.state()) > -1 || 
730 8d08f18a Kostas Papadimitriou
                models.VM.TRANSITION_STATES.indexOf(this.get('status')) > -1;
731 8d08f18a Kostas Papadimitriou
        },
732 8d08f18a Kostas Papadimitriou
        
733 8d08f18a Kostas Papadimitriou
        // get image object
734 8d08f18a Kostas Papadimitriou
        // TODO: update images synchronously if image not found
735 8d08f18a Kostas Papadimitriou
        get_image: function() {
736 bedfe884 Kostas Papadimitriou
            var image = storage.images.get(this.get('imageRef'));
737 bedfe884 Kostas Papadimitriou
            if (!image) {
738 bedfe884 Kostas Papadimitriou
                storage.images.update_unknown_id(this.get('imageRef'));
739 bedfe884 Kostas Papadimitriou
                image = storage.flavors.get(this.get('imageRef'));
740 bedfe884 Kostas Papadimitriou
            }
741 bedfe884 Kostas Papadimitriou
            return image;
742 8d08f18a Kostas Papadimitriou
        },
743 8d08f18a Kostas Papadimitriou
        
744 8d08f18a Kostas Papadimitriou
        // get flavor object
745 8d08f18a Kostas Papadimitriou
        // TODO: update flavors synchronously if image not found
746 8d08f18a Kostas Papadimitriou
        get_flavor: function() {
747 bedfe884 Kostas Papadimitriou
            var flv = storage.flavors.get(this.get('flavorRef'));
748 bedfe884 Kostas Papadimitriou
            if (!flv) {
749 bedfe884 Kostas Papadimitriou
                storage.flavors.update_unknown_id(this.get('flavorRef'));
750 bedfe884 Kostas Papadimitriou
                flv = storage.flavors.get(this.get('flavorRef'));
751 bedfe884 Kostas Papadimitriou
            }
752 bedfe884 Kostas Papadimitriou
            return flv;
753 8d08f18a Kostas Papadimitriou
        },
754 8d08f18a Kostas Papadimitriou
755 8d08f18a Kostas Papadimitriou
        // retrieve the metadata object
756 8d08f18a Kostas Papadimitriou
        get_meta: function() {
757 8d08f18a Kostas Papadimitriou
            //return {
758 8d08f18a Kostas Papadimitriou
                //'OS': 'debian',
759 8d08f18a Kostas Papadimitriou
                //'username': 'vinilios',
760 8d08f18a Kostas Papadimitriou
                //'group': 'webservers',
761 8d08f18a Kostas Papadimitriou
                //'meta2': 'meta value',
762 8d08f18a Kostas Papadimitriou
                //'looooooooooooooooong meta': 'short value',
763 8d08f18a Kostas Papadimitriou
                //'short meta': 'loooooooooooooooooooooooooooooooooong value',
764 8d08f18a Kostas Papadimitriou
                //'21421': 'fdsfds fds',
765 8d08f18a Kostas Papadimitriou
                //'21421': 'fdsfds fds',
766 8d08f18a Kostas Papadimitriou
                //'1fds 21421': 'fdsfds fds',
767 8d08f18a Kostas Papadimitriou
                //'fds 21421': 'fdsfds fds',
768 8d08f18a Kostas Papadimitriou
                //'fge 21421': 'fdsfds fds',
769 8d08f18a Kostas Papadimitriou
                //'21421 rew rew': 'fdsfds fds'
770 8d08f18a Kostas Papadimitriou
            //}
771 8d08f18a Kostas Papadimitriou
            try {
772 8d08f18a Kostas Papadimitriou
                return this.get('metadata').values
773 8d08f18a Kostas Papadimitriou
            } catch (err) {
774 8d08f18a Kostas Papadimitriou
                return {};
775 8d08f18a Kostas Papadimitriou
            }
776 8d08f18a Kostas Papadimitriou
        },
777 8d08f18a Kostas Papadimitriou
        
778 8d08f18a Kostas Papadimitriou
        // get metadata OS value
779 8d08f18a Kostas Papadimitriou
        get_os: function() {
780 8d08f18a Kostas Papadimitriou
            return this.get_meta().OS;
781 8d08f18a Kostas Papadimitriou
        },
782 8d08f18a Kostas Papadimitriou
        
783 8d08f18a Kostas Papadimitriou
        // get public ip addresses
784 8d08f18a Kostas Papadimitriou
        // TODO: public network is always the 0 index ???
785 8d08f18a Kostas Papadimitriou
        get_addresses: function(net_id) {
786 8d08f18a Kostas Papadimitriou
            var net_id = net_id || "public";
787 8d08f18a Kostas Papadimitriou
            
788 8d08f18a Kostas Papadimitriou
            var info = this.get_network_info(net_id);
789 8d08f18a Kostas Papadimitriou
            if (!info) { return {} };
790 8d08f18a Kostas Papadimitriou
            addrs = {};
791 8d08f18a Kostas Papadimitriou
            _.each(info.values, function(addr) {
792 8d08f18a Kostas Papadimitriou
                addrs["ip" + addr.version] = addr.addr;
793 8d08f18a Kostas Papadimitriou
            });
794 8d08f18a Kostas Papadimitriou
            return addrs
795 8d08f18a Kostas Papadimitriou
        },
796 8d08f18a Kostas Papadimitriou
797 8d08f18a Kostas Papadimitriou
        get_network_info: function(net_id) {
798 8d08f18a Kostas Papadimitriou
            var net_id = net_id || "public";
799 8d08f18a Kostas Papadimitriou
            
800 8d08f18a Kostas Papadimitriou
            if (!this.networks.network_ids.length) { return {} };
801 8d08f18a Kostas Papadimitriou
802 8d08f18a Kostas Papadimitriou
            var addresses = this.networks.get();
803 8d08f18a Kostas Papadimitriou
            try {
804 8d08f18a Kostas Papadimitriou
                return _.select(addresses, function(net, key){return key == net_id })[0];
805 8d08f18a Kostas Papadimitriou
            } catch (err) {
806 8d08f18a Kostas Papadimitriou
                //this.log.debug("Cannot find network {0}".format(net_id))
807 8d08f18a Kostas Papadimitriou
            }
808 8d08f18a Kostas Papadimitriou
        },
809 8d08f18a Kostas Papadimitriou
810 8d08f18a Kostas Papadimitriou
        firewall_profile: function(net_id) {
811 8d08f18a Kostas Papadimitriou
            var net_id = net_id || "public";
812 8d08f18a Kostas Papadimitriou
            var firewalls = this.get("firewalls");
813 8d08f18a Kostas Papadimitriou
            return firewalls[net_id];
814 8d08f18a Kostas Papadimitriou
        },
815 8d08f18a Kostas Papadimitriou
816 8d08f18a Kostas Papadimitriou
        has_firewall: function(net_id) {
817 8d08f18a Kostas Papadimitriou
            var net_id = net_id || "public";
818 8d08f18a Kostas Papadimitriou
            return ["ENABLED","PROTECTED"].indexOf(this.firewall_profile()) > -1;
819 8d08f18a Kostas Papadimitriou
        },
820 8d08f18a Kostas Papadimitriou
    
821 8d08f18a Kostas Papadimitriou
        // get actions that the user can execute
822 8d08f18a Kostas Papadimitriou
        // depending on the vm state/status
823 8d08f18a Kostas Papadimitriou
        get_available_actions: function() {
824 8d08f18a Kostas Papadimitriou
            return models.VM.AVAILABLE_ACTIONS[this.state()];
825 8d08f18a Kostas Papadimitriou
        },
826 8d08f18a Kostas Papadimitriou
827 8d08f18a Kostas Papadimitriou
        set_profile: function(profile, net_id) {
828 8d08f18a Kostas Papadimitriou
        },
829 8d08f18a Kostas Papadimitriou
        
830 8d08f18a Kostas Papadimitriou
        // call rename api
831 8d08f18a Kostas Papadimitriou
        rename: function(new_name) {
832 8d08f18a Kostas Papadimitriou
            //this.set({'name': new_name});
833 8d08f18a Kostas Papadimitriou
            this.sync("update", this, {
834 8d08f18a Kostas Papadimitriou
                data: {
835 8d08f18a Kostas Papadimitriou
                    'server': {
836 8d08f18a Kostas Papadimitriou
                        'name': new_name
837 8d08f18a Kostas Papadimitriou
                    }
838 8d08f18a Kostas Papadimitriou
                }, 
839 8d08f18a Kostas Papadimitriou
                // do the rename after the method succeeds
840 8d08f18a Kostas Papadimitriou
                success: _.bind(function(){
841 8d08f18a Kostas Papadimitriou
                    //this.set({name: new_name});
842 8d08f18a Kostas Papadimitriou
                    snf.api.trigger("call");
843 8d08f18a Kostas Papadimitriou
                }, this)
844 8d08f18a Kostas Papadimitriou
            });
845 8d08f18a Kostas Papadimitriou
        },
846 8d08f18a Kostas Papadimitriou
        
847 8d08f18a Kostas Papadimitriou
        get_console_url: function(data) {
848 8d08f18a Kostas Papadimitriou
            var url_params = {
849 8d08f18a Kostas Papadimitriou
                machine: this.get("name"),
850 8d08f18a Kostas Papadimitriou
                host_ip: this.get_addresses().ip4,
851 8d08f18a Kostas Papadimitriou
                host_ip_v6: this.get_addresses().ip6,
852 8d08f18a Kostas Papadimitriou
                host: data.host,
853 8d08f18a Kostas Papadimitriou
                port: data.port,
854 8d08f18a Kostas Papadimitriou
                password: data.password
855 8d08f18a Kostas Papadimitriou
            }
856 8d08f18a Kostas Papadimitriou
            return '/machines/console?' + $.param(url_params);
857 8d08f18a Kostas Papadimitriou
        },
858 8d08f18a Kostas Papadimitriou
859 8d08f18a Kostas Papadimitriou
        // action helper
860 8d08f18a Kostas Papadimitriou
        call: function(action_name, success, error) {
861 8d08f18a Kostas Papadimitriou
            var id_param = [this.id];
862 8d08f18a Kostas Papadimitriou
863 8d08f18a Kostas Papadimitriou
            success = success || function() {};
864 8d08f18a Kostas Papadimitriou
            error = error || function() {};
865 8d08f18a Kostas Papadimitriou
866 8d08f18a Kostas Papadimitriou
            var self = this;
867 8d08f18a Kostas Papadimitriou
868 8d08f18a Kostas Papadimitriou
            switch(action_name) {
869 8d08f18a Kostas Papadimitriou
                case 'start':
870 8d08f18a Kostas Papadimitriou
                    this.__make_api_call(this.get_action_url(), // vm actions url
871 8d08f18a Kostas Papadimitriou
                                         "create", // create so that sync later uses POST to make the call
872 8d08f18a Kostas Papadimitriou
                                         {start:{}}, // payload
873 8d08f18a Kostas Papadimitriou
                                         function() {
874 8d08f18a Kostas Papadimitriou
                                             // set state after successful call
875 8d08f18a Kostas Papadimitriou
                                             self.state("START"); 
876 8d08f18a Kostas Papadimitriou
                                             success.apply(this, arguments);
877 8d08f18a Kostas Papadimitriou
                                             snf.api.trigger("call");
878 8d08f18a Kostas Papadimitriou
                                         },  
879 8d08f18a Kostas Papadimitriou
                                         error);
880 8d08f18a Kostas Papadimitriou
                    break;
881 8d08f18a Kostas Papadimitriou
                case 'reboot':
882 8d08f18a Kostas Papadimitriou
                    this.__make_api_call(this.get_action_url(), // vm actions url
883 8d08f18a Kostas Papadimitriou
                                         "create", // create so that sync later uses POST to make the call
884 8d08f18a Kostas Papadimitriou
                                         {reboot:{type:"HARD"}}, // payload
885 8d08f18a Kostas Papadimitriou
                                         function() {
886 8d08f18a Kostas Papadimitriou
                                             // set state after successful call
887 8d08f18a Kostas Papadimitriou
                                             self.state("REBOOT"); 
888 8d08f18a Kostas Papadimitriou
                                             success.apply(this, arguments)
889 8d08f18a Kostas Papadimitriou
                                             snf.api.trigger("call");
890 122850c5 Kostas Papadimitriou
                                             self.set({'reboot_required': false});
891 8d08f18a Kostas Papadimitriou
                                         },
892 8d08f18a Kostas Papadimitriou
                                         error);
893 8d08f18a Kostas Papadimitriou
                    break;
894 8d08f18a Kostas Papadimitriou
                case 'shutdown':
895 8d08f18a Kostas Papadimitriou
                    this.__make_api_call(this.get_action_url(), // vm actions url
896 8d08f18a Kostas Papadimitriou
                                         "create", // create so that sync later uses POST to make the call
897 8d08f18a Kostas Papadimitriou
                                         {shutdown:{}}, // payload
898 8d08f18a Kostas Papadimitriou
                                         function() {
899 8d08f18a Kostas Papadimitriou
                                             // set state after successful call
900 8d08f18a Kostas Papadimitriou
                                             self.state("SHUTDOWN"); 
901 8d08f18a Kostas Papadimitriou
                                             success.apply(this, arguments)
902 8d08f18a Kostas Papadimitriou
                                             snf.api.trigger("call");
903 8d08f18a Kostas Papadimitriou
                                         },  
904 8d08f18a Kostas Papadimitriou
                                         error);
905 8d08f18a Kostas Papadimitriou
                    break;
906 8d08f18a Kostas Papadimitriou
                case 'console':
907 8d08f18a Kostas Papadimitriou
                    this.__make_api_call(this.url() + "/action", "create", {'console': {'type':'vnc'}}, function(data) {
908 8d08f18a Kostas Papadimitriou
                        var cons_data = data.console;
909 8d08f18a Kostas Papadimitriou
                        success.apply(this, [cons_data]);
910 8d08f18a Kostas Papadimitriou
                    })
911 8d08f18a Kostas Papadimitriou
                    break;
912 8d08f18a Kostas Papadimitriou
                case 'destroy':
913 8d08f18a Kostas Papadimitriou
                    this.__make_api_call(this.url(), // vm actions url
914 8d08f18a Kostas Papadimitriou
                                         "delete", // create so that sync later uses POST to make the call
915 8d08f18a Kostas Papadimitriou
                                         undefined, // payload
916 8d08f18a Kostas Papadimitriou
                                         function() {
917 8d08f18a Kostas Papadimitriou
                                             // set state after successful call
918 8d08f18a Kostas Papadimitriou
                                             self.state('DESTROY');
919 8d08f18a Kostas Papadimitriou
                                             success.apply(this, arguments)
920 8d08f18a Kostas Papadimitriou
                                         },  
921 8d08f18a Kostas Papadimitriou
                                         error);
922 8d08f18a Kostas Papadimitriou
                    break;
923 8d08f18a Kostas Papadimitriou
                default:
924 8d08f18a Kostas Papadimitriou
                    throw "Invalid VM action ("+action_name+")";
925 8d08f18a Kostas Papadimitriou
            }
926 8d08f18a Kostas Papadimitriou
        },
927 8d08f18a Kostas Papadimitriou
        
928 8d08f18a Kostas Papadimitriou
        __make_api_call: function(url, method, data, success, error) {
929 8d08f18a Kostas Papadimitriou
            var self = this;
930 8d08f18a Kostas Papadimitriou
            error = error || function(){};
931 8d08f18a Kostas Papadimitriou
            success = success || function(){};
932 8d08f18a Kostas Papadimitriou
933 8d08f18a Kostas Papadimitriou
            var params = {
934 8d08f18a Kostas Papadimitriou
                url: url,
935 8d08f18a Kostas Papadimitriou
                data: data,
936 8d08f18a Kostas Papadimitriou
                success: function(){ self.handle_action_succeed.apply(self, arguments); success.apply(this, arguments)},
937 8d08f18a Kostas Papadimitriou
                error: function(){ self.handle_action_fail.apply(self, arguments); error.apply(this, arguments)}
938 8d08f18a Kostas Papadimitriou
            }
939 8d08f18a Kostas Papadimitriou
            this.sync(method, this, params);
940 8d08f18a Kostas Papadimitriou
        },
941 8d08f18a Kostas Papadimitriou
942 8d08f18a Kostas Papadimitriou
        handle_action_succeed: function() {
943 8d08f18a Kostas Papadimitriou
            this.trigger("action:success", arguments);
944 8d08f18a Kostas Papadimitriou
        },
945 8d08f18a Kostas Papadimitriou
946 8d08f18a Kostas Papadimitriou
        handle_action_fail: function() {
947 8d08f18a Kostas Papadimitriou
            this.trigger("action:fail", arguments);
948 8d08f18a Kostas Papadimitriou
        },
949 8d08f18a Kostas Papadimitriou
950 8d08f18a Kostas Papadimitriou
        get_action_url: function(name) {
951 8d08f18a Kostas Papadimitriou
            return this.url() + "/action";
952 8d08f18a Kostas Papadimitriou
        }
953 8d08f18a Kostas Papadimitriou
    })
954 8d08f18a Kostas Papadimitriou
    
955 8d08f18a Kostas Papadimitriou
    models.VM.ACTIONS = [
956 8d08f18a Kostas Papadimitriou
        'start',
957 8d08f18a Kostas Papadimitriou
        'shutdown',
958 8d08f18a Kostas Papadimitriou
        'reboot',
959 8d08f18a Kostas Papadimitriou
        'destroy'
960 8d08f18a Kostas Papadimitriou
    ]
961 8d08f18a Kostas Papadimitriou
962 8d08f18a Kostas Papadimitriou
    models.VM.AVAILABLE_ACTIONS = {
963 8d08f18a Kostas Papadimitriou
        'UNKNWON'       : ['destroy'],
964 8d08f18a Kostas Papadimitriou
        'BUILD'         : ['destroy'],
965 8d08f18a Kostas Papadimitriou
        'REBOOT'        : ['shutdown', 'destroy', 'console'],
966 8d08f18a Kostas Papadimitriou
        'STOPPED'       : ['start', 'destroy'],
967 8d08f18a Kostas Papadimitriou
        'ACTIVE'        : ['shutdown', 'destroy', 'reboot', 'console'],
968 8d08f18a Kostas Papadimitriou
        'ERROR'         : ['destroy'],
969 8d08f18a Kostas Papadimitriou
        'DELETE'        : [],
970 8d08f18a Kostas Papadimitriou
        'DESTROY'       : [],
971 8d08f18a Kostas Papadimitriou
        'BUILD_INIT'    : ['destroy'],
972 8d08f18a Kostas Papadimitriou
        'BUILD_COPY'    : ['destroy'],
973 8d08f18a Kostas Papadimitriou
        'BUILD_FINAL'   : ['destroy'],
974 8d08f18a Kostas Papadimitriou
        'SHUTDOWN'      : ['destroy'],
975 8d08f18a Kostas Papadimitriou
        'START'         : [],
976 8d08f18a Kostas Papadimitriou
        'CONNECT'       : [],
977 8d08f18a Kostas Papadimitriou
        'DISCONNECT'    : []
978 8d08f18a Kostas Papadimitriou
    }
979 8d08f18a Kostas Papadimitriou
980 8d08f18a Kostas Papadimitriou
    // api status values
981 8d08f18a Kostas Papadimitriou
    models.VM.STATUSES = [
982 8d08f18a Kostas Papadimitriou
        'UNKNWON',
983 8d08f18a Kostas Papadimitriou
        'BUILD',
984 8d08f18a Kostas Papadimitriou
        'REBOOT',
985 8d08f18a Kostas Papadimitriou
        'STOPPED',
986 8d08f18a Kostas Papadimitriou
        'ACTIVE',
987 8d08f18a Kostas Papadimitriou
        'ERROR',
988 8d08f18a Kostas Papadimitriou
        'DELETE'
989 8d08f18a Kostas Papadimitriou
    ]
990 8d08f18a Kostas Papadimitriou
991 8d08f18a Kostas Papadimitriou
    // api status values
992 8d08f18a Kostas Papadimitriou
    models.VM.CONNECT_STATES = [
993 8d08f18a Kostas Papadimitriou
        'ACTIVE',
994 8d08f18a Kostas Papadimitriou
        'REBOOT',
995 8d08f18a Kostas Papadimitriou
        'START'
996 8d08f18a Kostas Papadimitriou
    ]
997 8d08f18a Kostas Papadimitriou
998 8d08f18a Kostas Papadimitriou
    // vm states
999 8d08f18a Kostas Papadimitriou
    models.VM.STATES = models.VM.STATUSES.concat([
1000 8d08f18a Kostas Papadimitriou
        'DESTROY',
1001 8d08f18a Kostas Papadimitriou
        'BUILD_INIT',
1002 8d08f18a Kostas Papadimitriou
        'BUILD_COPY',
1003 8d08f18a Kostas Papadimitriou
        'BUILD_FINAL',
1004 8d08f18a Kostas Papadimitriou
        'SHUTDOWN',
1005 8d08f18a Kostas Papadimitriou
        'START',
1006 8d08f18a Kostas Papadimitriou
        'CONNECT',
1007 8d08f18a Kostas Papadimitriou
        'DISCONNECT',
1008 8d08f18a Kostas Papadimitriou
        'FIREWALL'
1009 8d08f18a Kostas Papadimitriou
    ]);
1010 8d08f18a Kostas Papadimitriou
    
1011 8d08f18a Kostas Papadimitriou
    models.VM.STATES_TRANSITIONS = {
1012 8d08f18a Kostas Papadimitriou
        'DESTROY' : ['DELETE'],
1013 8d08f18a Kostas Papadimitriou
        'SHUTDOWN': ['ERROR', 'STOPPED', 'DESTROY'],
1014 8d08f18a Kostas Papadimitriou
        'STOPPED': ['ERROR', 'ACTIVE', 'DESTROY'],
1015 8d08f18a Kostas Papadimitriou
        'ACTIVE': ['ERROR', 'STOPPED', 'REBOOT', 'SHUTDOWN', 'DESTROY'],
1016 8d08f18a Kostas Papadimitriou
        'START': ['ERROR', 'ACTIVE', 'DESTROY'],
1017 8d08f18a Kostas Papadimitriou
        'REBOOT': ['ERROR', 'ACTIVE', 'STOPPED', 'DESTROY'],
1018 8d08f18a Kostas Papadimitriou
        'BUILD': ['ERROR', 'ACTIVE', 'DESTROY'],
1019 8d08f18a Kostas Papadimitriou
        'BUILD_COPY': ['ERROR', 'ACTIVE', 'BUILD_FINAL', 'DESTROY'],
1020 8d08f18a Kostas Papadimitriou
        'BUILD_FINAL': ['ERROR', 'ACTIVE', 'DESTROY'],
1021 8d08f18a Kostas Papadimitriou
        'BUILD_INIT': ['ERROR', 'ACTIVE', 'BUILD_COPY', 'BUILD_FINAL', 'DESTROY']
1022 8d08f18a Kostas Papadimitriou
    }
1023 8d08f18a Kostas Papadimitriou
1024 8d08f18a Kostas Papadimitriou
    models.VM.TRANSITION_STATES = [
1025 8d08f18a Kostas Papadimitriou
        'DESTROY',
1026 8d08f18a Kostas Papadimitriou
        'SHUTDOWN',
1027 8d08f18a Kostas Papadimitriou
        'START',
1028 8d08f18a Kostas Papadimitriou
        'REBOOT',
1029 8d08f18a Kostas Papadimitriou
        'BUILD'
1030 8d08f18a Kostas Papadimitriou
    ]
1031 8d08f18a Kostas Papadimitriou
1032 8d08f18a Kostas Papadimitriou
    models.VM.ACTIVE_STATES = [
1033 8d08f18a Kostas Papadimitriou
        'BUILD', 'REBOOT', 'ACTIVE',
1034 8d08f18a Kostas Papadimitriou
        'BUILD_INIT', 'BUILD_COPY', 'BUILD_FINAL',
1035 8d08f18a Kostas Papadimitriou
        'START', 'CONNECT', 'DISCONNECT'
1036 8d08f18a Kostas Papadimitriou
    ]
1037 8d08f18a Kostas Papadimitriou
1038 8d08f18a Kostas Papadimitriou
    models.VM.BUILDING_STATES = [
1039 8d08f18a Kostas Papadimitriou
        'BUILD', 'BUILD_INIT', 'BUILD_COPY', 'BUILD_FINAL'
1040 8d08f18a Kostas Papadimitriou
    ]
1041 8d08f18a Kostas Papadimitriou
1042 8d08f18a Kostas Papadimitriou
    models.Networks = models.Collection.extend({
1043 8d08f18a Kostas Papadimitriou
        model: models.Network,
1044 8d08f18a Kostas Papadimitriou
        path: 'networks',
1045 8d08f18a Kostas Papadimitriou
        details: true,
1046 8d08f18a Kostas Papadimitriou
        //noUpdate: true,
1047 8d08f18a Kostas Papadimitriou
        defaults: {'linked_to':[]},
1048 8d08f18a Kostas Papadimitriou
1049 8d08f18a Kostas Papadimitriou
        parse: function (resp, xhr) {
1050 8d08f18a Kostas Papadimitriou
            // FIXME: depricated global var
1051 8d08f18a Kostas Papadimitriou
            if (!resp) { return []};
1052 8d08f18a Kostas Papadimitriou
               
1053 8d08f18a Kostas Papadimitriou
            var data = _.map(resp.networks.values, _.bind(this.parse_net_api_data, this));
1054 8d08f18a Kostas Papadimitriou
            return data;
1055 8d08f18a Kostas Papadimitriou
        },
1056 8d08f18a Kostas Papadimitriou
1057 8d08f18a Kostas Papadimitriou
        parse_net_api_data: function(data) {
1058 8d08f18a Kostas Papadimitriou
            if (data.servers && data.servers.values) {
1059 8d08f18a Kostas Papadimitriou
                data['linked_to'] = data.servers.values;
1060 8d08f18a Kostas Papadimitriou
            }
1061 8d08f18a Kostas Papadimitriou
            return data;
1062 8d08f18a Kostas Papadimitriou
        },
1063 8d08f18a Kostas Papadimitriou
1064 8d08f18a Kostas Papadimitriou
        create: function (name, callback) {
1065 8d08f18a Kostas Papadimitriou
            return this.api.call(this.path, "create", {network:{name:name}}, callback);
1066 8d08f18a Kostas Papadimitriou
        }
1067 8d08f18a Kostas Papadimitriou
    })
1068 8d08f18a Kostas Papadimitriou
1069 8d08f18a Kostas Papadimitriou
    models.Images = models.Collection.extend({
1070 8d08f18a Kostas Papadimitriou
        model: models.Image,
1071 8d08f18a Kostas Papadimitriou
        path: 'images',
1072 8d08f18a Kostas Papadimitriou
        details: true,
1073 8d08f18a Kostas Papadimitriou
        noUpdate: true,
1074 8d08f18a Kostas Papadimitriou
        
1075 8d08f18a Kostas Papadimitriou
        meta_keys_as_attrs: ["OS", "description", "kernel", "size", "GUI"],
1076 8d08f18a Kostas Papadimitriou
1077 bedfe884 Kostas Papadimitriou
        // update collection model with id passed
1078 bedfe884 Kostas Papadimitriou
        // making a direct call to the flavor
1079 bedfe884 Kostas Papadimitriou
        // api url
1080 bedfe884 Kostas Papadimitriou
        update_unknown_id: function(id) {
1081 bedfe884 Kostas Papadimitriou
            var url = getUrl.call(this) + "/" + id;
1082 bedfe884 Kostas Papadimitriou
            this.api.call(this.path + "/" + id, "read", {_options:{async:false}}, undefined, 
1083 bedfe884 Kostas Papadimitriou
            _.bind(function() {
1084 bedfe884 Kostas Papadimitriou
                this.add({id:id, name:"Unknown image", size:-1, progress:100, status:"DELETED"})
1085 bedfe884 Kostas Papadimitriou
            }, this), _.bind(function(image) {
1086 bedfe884 Kostas Papadimitriou
                this.add(image.image);
1087 bedfe884 Kostas Papadimitriou
            }, this));
1088 bedfe884 Kostas Papadimitriou
        },
1089 bedfe884 Kostas Papadimitriou
1090 8d08f18a Kostas Papadimitriou
        parse: function (resp, xhr) {
1091 8d08f18a Kostas Papadimitriou
            // FIXME: depricated global var
1092 8d08f18a Kostas Papadimitriou
            var data = _.map(resp.images.values, _.bind(this.parse_meta, this));
1093 8d08f18a Kostas Papadimitriou
            return resp.images.values;
1094 8d08f18a Kostas Papadimitriou
        },
1095 8d08f18a Kostas Papadimitriou
1096 8d08f18a Kostas Papadimitriou
        get_meta_key: function(img, key) {
1097 8d08f18a Kostas Papadimitriou
            if (img.metadata && img.metadata.values && img.metadata.values[key]) {
1098 8d08f18a Kostas Papadimitriou
                return img.metadata.values[key];
1099 8d08f18a Kostas Papadimitriou
            }
1100 8d08f18a Kostas Papadimitriou
            return undefined;
1101 8d08f18a Kostas Papadimitriou
        },
1102 8d08f18a Kostas Papadimitriou
1103 8d08f18a Kostas Papadimitriou
        parse_meta: function(img) {
1104 8d08f18a Kostas Papadimitriou
            _.each(this.meta_keys_as_attrs, _.bind(function(key){
1105 8d08f18a Kostas Papadimitriou
                img[key] = this.get_meta_key(img, key);
1106 8d08f18a Kostas Papadimitriou
            }, this));
1107 8d08f18a Kostas Papadimitriou
            return img;
1108 bedfe884 Kostas Papadimitriou
        },
1109 bedfe884 Kostas Papadimitriou
1110 bedfe884 Kostas Papadimitriou
        active: function() {
1111 bedfe884 Kostas Papadimitriou
            return this.filter(function(img){return img.get('status') != "DELETED"});
1112 8d08f18a Kostas Papadimitriou
        }
1113 8d08f18a Kostas Papadimitriou
    })
1114 8d08f18a Kostas Papadimitriou
1115 8d08f18a Kostas Papadimitriou
    models.Flavors = models.Collection.extend({
1116 8d08f18a Kostas Papadimitriou
        model: models.Flavor,
1117 8d08f18a Kostas Papadimitriou
        path: 'flavors',
1118 8d08f18a Kostas Papadimitriou
        details: true,
1119 8d08f18a Kostas Papadimitriou
        noUpdate: true,
1120 bedfe884 Kostas Papadimitriou
        
1121 bedfe884 Kostas Papadimitriou
        // update collection model with id passed
1122 bedfe884 Kostas Papadimitriou
        // making a direct call to the flavor
1123 bedfe884 Kostas Papadimitriou
        // api url
1124 bedfe884 Kostas Papadimitriou
        update_unknown_id: function(id) {
1125 bedfe884 Kostas Papadimitriou
            var url = getUrl.call(this) + "/" + id;
1126 bedfe884 Kostas Papadimitriou
            this.api.call(this.path + "/" + id, "read", {_options:{async:false}}, undefined, 
1127 bedfe884 Kostas Papadimitriou
            _.bind(function() {
1128 bedfe884 Kostas Papadimitriou
                this.add({id:id, cpu:"", ram:"", disk:"", name: "", status:"DELETED"})
1129 bedfe884 Kostas Papadimitriou
            }, this), _.bind(function(flv) {
1130 bedfe884 Kostas Papadimitriou
                if (!flv.flavor.status) { flv.flavor.status = "DELETED" };
1131 bedfe884 Kostas Papadimitriou
                this.add(flv.flavor);
1132 bedfe884 Kostas Papadimitriou
            }, this));
1133 bedfe884 Kostas Papadimitriou
        },
1134 8d08f18a Kostas Papadimitriou
1135 8d08f18a Kostas Papadimitriou
        parse: function (resp, xhr) {
1136 8d08f18a Kostas Papadimitriou
            // FIXME: depricated global var
1137 8d08f18a Kostas Papadimitriou
            return resp.flavors.values;
1138 8d08f18a Kostas Papadimitriou
        },
1139 8d08f18a Kostas Papadimitriou
1140 820ef2f0 Kostas Papadimitriou
        unavailable_values_for_image: function(img, flavors) {
1141 820ef2f0 Kostas Papadimitriou
            var flavors = flavors || this.active();
1142 820ef2f0 Kostas Papadimitriou
            var size = img.get_size();
1143 820ef2f0 Kostas Papadimitriou
            
1144 820ef2f0 Kostas Papadimitriou
            var index = {cpu:[], disk:[], ram:[]};
1145 820ef2f0 Kostas Papadimitriou
1146 820ef2f0 Kostas Papadimitriou
            _.each(this.active(), function(el) {
1147 820ef2f0 Kostas Papadimitriou
                var img_size = size;
1148 820ef2f0 Kostas Papadimitriou
                var flv_size = el.get_disk_size();
1149 820ef2f0 Kostas Papadimitriou
                if (flv_size < img_size) {
1150 820ef2f0 Kostas Papadimitriou
                    if (index.disk.indexOf(flv_size) == -1) {
1151 820ef2f0 Kostas Papadimitriou
                        index.disk.push(flv_size);
1152 820ef2f0 Kostas Papadimitriou
                    }
1153 820ef2f0 Kostas Papadimitriou
                };
1154 820ef2f0 Kostas Papadimitriou
            });
1155 820ef2f0 Kostas Papadimitriou
            
1156 820ef2f0 Kostas Papadimitriou
            return index;
1157 8d08f18a Kostas Papadimitriou
        },
1158 820ef2f0 Kostas Papadimitriou
1159 8d08f18a Kostas Papadimitriou
        get_flavor: function(cpu, mem, disk, filter_list) {
1160 8d08f18a Kostas Papadimitriou
            if (!filter_list) { filter_list = this.models };
1161 8d08f18a Kostas Papadimitriou
            return this.select(function(flv){
1162 8d08f18a Kostas Papadimitriou
                if (flv.get("cpu") == cpu + "" &&
1163 8d08f18a Kostas Papadimitriou
                   flv.get("ram") == mem + "" &&
1164 8d08f18a Kostas Papadimitriou
                   flv.get("disk") == disk + "" &&
1165 820ef2f0 Kostas Papadimitriou
                   filter_list.indexOf(flv) > -1) { return true; }
1166 8d08f18a Kostas Papadimitriou
            })[0]
1167 8d08f18a Kostas Papadimitriou
        },
1168 820ef2f0 Kostas Papadimitriou
        
1169 8d08f18a Kostas Papadimitriou
        get_data: function(lst) {
1170 8d08f18a Kostas Papadimitriou
            var data = {'cpu': [], 'mem':[], 'disk':[]};
1171 820ef2f0 Kostas Papadimitriou
1172 8d08f18a Kostas Papadimitriou
            _.each(lst, function(flv) {
1173 820ef2f0 Kostas Papadimitriou
                if (data.cpu.indexOf(flv.get("cpu")) == -1) {
1174 820ef2f0 Kostas Papadimitriou
                    data.cpu.push(flv.get("cpu"));
1175 8d08f18a Kostas Papadimitriou
                }
1176 820ef2f0 Kostas Papadimitriou
                if (data.mem.indexOf(flv.get("ram")) == -1) {
1177 820ef2f0 Kostas Papadimitriou
                    data.mem.push(flv.get("ram"));
1178 8d08f18a Kostas Papadimitriou
                }
1179 820ef2f0 Kostas Papadimitriou
                if (data.disk.indexOf(flv.get("disk")) == -1) {
1180 820ef2f0 Kostas Papadimitriou
                    data.disk.push(flv.get("disk"));
1181 8d08f18a Kostas Papadimitriou
                }
1182 8d08f18a Kostas Papadimitriou
            })
1183 820ef2f0 Kostas Papadimitriou
            
1184 8d08f18a Kostas Papadimitriou
            return data;
1185 bedfe884 Kostas Papadimitriou
        },
1186 bedfe884 Kostas Papadimitriou
1187 bedfe884 Kostas Papadimitriou
        active: function() {
1188 bedfe884 Kostas Papadimitriou
            return this.filter(function(flv){return flv.get('status') != "DELETED"});
1189 8d08f18a Kostas Papadimitriou
        }
1190 8d08f18a Kostas Papadimitriou
            
1191 8d08f18a Kostas Papadimitriou
    })
1192 8d08f18a Kostas Papadimitriou
1193 8d08f18a Kostas Papadimitriou
    models.VMS = models.Collection.extend({
1194 8d08f18a Kostas Papadimitriou
        model: models.VM,
1195 8d08f18a Kostas Papadimitriou
        path: 'servers',
1196 8d08f18a Kostas Papadimitriou
        details: true,
1197 8d08f18a Kostas Papadimitriou
        copy_image_meta: true,
1198 8d08f18a Kostas Papadimitriou
        
1199 8d08f18a Kostas Papadimitriou
        parse: function (resp, xhr) {
1200 8d08f18a Kostas Papadimitriou
            // FIXME: depricated after refactoring
1201 8d08f18a Kostas Papadimitriou
            var data = resp;
1202 8d08f18a Kostas Papadimitriou
            if (!resp) { return [] };
1203 820ef2f0 Kostas Papadimitriou
            data = _.filter(_.map(resp.servers.values, _.bind(this.parse_vm_api_data, this)), function(v){return v});
1204 8d08f18a Kostas Papadimitriou
            return data;
1205 8d08f18a Kostas Papadimitriou
        },
1206 122850c5 Kostas Papadimitriou
        
1207 122850c5 Kostas Papadimitriou
        get_reboot_required: function() {
1208 122850c5 Kostas Papadimitriou
            return this.filter(function(vm){return vm.get("reboot_required") == true})
1209 122850c5 Kostas Papadimitriou
        },
1210 122850c5 Kostas Papadimitriou
1211 122850c5 Kostas Papadimitriou
        has_pending_actions: function() {
1212 122850c5 Kostas Papadimitriou
            return this.filter(function(vm){return vm.pending_action}).length > 0;
1213 122850c5 Kostas Papadimitriou
        },
1214 8d08f18a Kostas Papadimitriou
1215 8d08f18a Kostas Papadimitriou
        reset_pending_actions: function() {
1216 8d08f18a Kostas Papadimitriou
            this.each(function(vm) {
1217 8d08f18a Kostas Papadimitriou
                vm.clear_pending_action();
1218 8d08f18a Kostas Papadimitriou
            })
1219 8d08f18a Kostas Papadimitriou
        },
1220 8d08f18a Kostas Papadimitriou
        
1221 8d08f18a Kostas Papadimitriou
        has_meta: function(vm_data) {
1222 8d08f18a Kostas Papadimitriou
            return vm_data.metadata && vm_data.metadata.values
1223 8d08f18a Kostas Papadimitriou
        },
1224 8d08f18a Kostas Papadimitriou
1225 8d08f18a Kostas Papadimitriou
        has_addresses: function(vm_data) {
1226 8d08f18a Kostas Papadimitriou
            return vm_data.metadata && vm_data.metadata.values
1227 8d08f18a Kostas Papadimitriou
        },
1228 8d08f18a Kostas Papadimitriou
1229 8d08f18a Kostas Papadimitriou
        parse_vm_api_data: function(data) {
1230 820ef2f0 Kostas Papadimitriou
1231 820ef2f0 Kostas Papadimitriou
            // do not add non existing DELETED entries
1232 820ef2f0 Kostas Papadimitriou
            if (data.status && data.status == "DELETED") {
1233 820ef2f0 Kostas Papadimitriou
                if (!this.get(data.id)) {
1234 820ef2f0 Kostas Papadimitriou
                    console.error("non exising deleted vm", data)
1235 820ef2f0 Kostas Papadimitriou
                    return false;
1236 820ef2f0 Kostas Papadimitriou
                }
1237 820ef2f0 Kostas Papadimitriou
            }
1238 820ef2f0 Kostas Papadimitriou
1239 8d08f18a Kostas Papadimitriou
            // OS attribute
1240 8d08f18a Kostas Papadimitriou
            if (this.has_meta(data)) {
1241 8d08f18a Kostas Papadimitriou
                data['OS'] = data.metadata.values.OS || "undefined";
1242 8d08f18a Kostas Papadimitriou
            }
1243 8d08f18a Kostas Papadimitriou
            
1244 8d08f18a Kostas Papadimitriou
            data['firewalls'] = {};
1245 8d08f18a Kostas Papadimitriou
            if (data['addresses'] && data['addresses'].values) {
1246 8d08f18a Kostas Papadimitriou
                data['linked_to_nets'] = data['addresses'].values;
1247 8d08f18a Kostas Papadimitriou
                _.each(data['addresses'].values, function(f){
1248 8d08f18a Kostas Papadimitriou
                    if (f['firewallProfile']) {
1249 8d08f18a Kostas Papadimitriou
                        data['firewalls'][f['id']] = f['firewallProfile']
1250 8d08f18a Kostas Papadimitriou
                    }
1251 8d08f18a Kostas Papadimitriou
                });
1252 8d08f18a Kostas Papadimitriou
            }
1253 8d08f18a Kostas Papadimitriou
            
1254 8d08f18a Kostas Papadimitriou
            // if vm has no metadata, no metadata object
1255 8d08f18a Kostas Papadimitriou
            // is in json response, reset it to force
1256 8d08f18a Kostas Papadimitriou
            // value update
1257 8d08f18a Kostas Papadimitriou
            if (!data['metadata']) {
1258 8d08f18a Kostas Papadimitriou
                data['metadata'] = {values:{}};
1259 8d08f18a Kostas Papadimitriou
            }
1260 8d08f18a Kostas Papadimitriou
1261 8d08f18a Kostas Papadimitriou
            return data;
1262 8d08f18a Kostas Papadimitriou
        },
1263 8d08f18a Kostas Papadimitriou
1264 8d08f18a Kostas Papadimitriou
        create: function (name, image, flavor, meta, extra, callback) {
1265 8d08f18a Kostas Papadimitriou
            if (this.copy_image_meta) {
1266 8d08f18a Kostas Papadimitriou
                meta['OS'] = image.get("OS");
1267 8d08f18a Kostas Papadimitriou
           }
1268 8d08f18a Kostas Papadimitriou
            
1269 8d08f18a Kostas Papadimitriou
            opts = {name: name, imageRef: image.id, flavorRef: flavor.id, metadata:meta}
1270 8d08f18a Kostas Papadimitriou
            opts = _.extend(opts, extra);
1271 8d08f18a Kostas Papadimitriou
1272 8d08f18a Kostas Papadimitriou
            this.api.call(this.path, "create", {'server': opts}, undefined, undefined, callback);
1273 8d08f18a Kostas Papadimitriou
        }
1274 8d08f18a Kostas Papadimitriou
1275 8d08f18a Kostas Papadimitriou
    })
1276 8d08f18a Kostas Papadimitriou
    
1277 8d08f18a Kostas Papadimitriou
1278 8d08f18a Kostas Papadimitriou
    // storage initialization
1279 8d08f18a Kostas Papadimitriou
    snf.storage.images = new models.Images();
1280 8d08f18a Kostas Papadimitriou
    snf.storage.flavors = new models.Flavors();
1281 8d08f18a Kostas Papadimitriou
    snf.storage.networks = new models.Networks();
1282 8d08f18a Kostas Papadimitriou
    snf.storage.vms = new models.VMS();
1283 8d08f18a Kostas Papadimitriou
1284 8d08f18a Kostas Papadimitriou
    //snf.storage.vms.fetch({update:true});
1285 8d08f18a Kostas Papadimitriou
    //snf.storage.images.fetch({update:true});
1286 8d08f18a Kostas Papadimitriou
    //snf.storage.flavors.fetch({update:true});
1287 8d08f18a Kostas Papadimitriou
1288 8d08f18a Kostas Papadimitriou
})(this);