~ubuntu-branches/ubuntu/utopic/maas/utopic-security

« back to all changes in this revision

Viewing changes to src/maasserver/static/js/image_views.js

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez, Jeroen Vermeulen, Andres Rodriguez, Jason Hobbs, Raphaël Badin, Louis Bouchard, Gavin Panella
  • Date: 2014-08-21 19:36:30 UTC
  • mfrom: (1.3.1)
  • Revision ID: package-import@ubuntu.com-20140821193630-kertpu5hd8yyss8h
Tags: 1.7.0~beta7+bzr3266-0ubuntu1
* New Upstream Snapshot, Beta 7 bzr3266

[ Jeroen Vermeulen ]
* debian/extras/99-maas-sudoers
  debian/maas-dhcp.postinst
  debian/rules
  - Add second DHCP server instance for IPv6.
* debian/maas-region-controller-min.install
  debian/maas-region-controller-min.lintian-overrides
  - Install deployment user-data: maas_configure_interfaces.py script.
* debian/maas-cluster-controller.links
  debian/maas-cluster-controller.install
  debian/maas-cluster-controller.postinst
  - Reflect Celery removal changes made in trunk r3067.
  - Don't install celeryconfig_cluster.py any longer. 
  - Don't install maas_local_celeryconfig_cluster.py any longer.
  - Don't symlink maas_local_celeryconfig_cluster.py from /etc to /usr.
  - Don't insert UUID into maas_local_celeryconfig_cluster.py.

[ Andres Rodriguez ]
* debian/maas-region-controller-min.postrm: Cleanup lefover files.
* debian/maas-dhcp.postrm: Clean leftover configs.
* Provide new maas-proxy package that replaces the usage of
  squid-deb-proxy:
  - debian/control: New maas-proxy package that replaces the usage
    of squid-deb-proxy; Drop depends on squid-deb-proxy.
  - Add upstrart job.
  - Ensure squid3 is stopped as maas-proxy uses a caching proxy.
* Remove Celery references to cluster controller:
  - Rename upstart job from maas-pserv to maas-cluster; rename
    maas-cluster-celery to maas-cluster-register. Ensure services
    are stopped on upgrade.
  - debian/maintscript: Cleanup config files.
  - Remove all references to the MAAS celery daemon and config
    files as we don't use it like that anymore
* Move some entries in debian/maintscript to
  debian/maas-cluster-controller.maintscript
* Remove usage of txlongpoll and rabbitmq-server. Handle upgrades
  to ensure these are removed correctly.

[ Jason Hobbs ]
* debian/maas-region-controller-min.install: Install
  maas-generate-winrm-cert script.

[ Raphaël Badin ]
* debian/extras/maas-region-admin: Bypass django-admin as it prints
  spurious messages to stdout (LP: #1365130).

[Louis Bouchard]
* debian/maas-cluster-controller.postinst:
  - Exclude /var/log/maas/rsyslog when changing ownership
    (LP: #1346703)

[Gavin Panella]
* debian/maas-cluster-controller.maas-clusterd.upstart:
  - Don't start-up the cluster controller unless a shared-secret has
    been installed.
* debian/maas-cluster-controller.maas-cluster-register.upstart: Drop.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2014 Canonical Ltd.  This software is licensed under the
 
2
 * GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 *
 
4
 * Image views.
 
5
 *
 
6
 * @module Y.maas.image_views
 
7
 */
 
8
 
 
9
YUI.add('maas.image_views', function(Y) {
 
10
 
 
11
Y.log('loading maas.image_views');
 
12
var module = Y.namespace('maas.image_views');
 
13
 
 
14
var BOOT_RESOURCE_TYPE = Y.maas.enums.BOOT_RESOURCE_TYPE;
 
15
 
 
16
 
 
17
/**
 
18
 * A base view class to display a set of Images (Y.maas.image.Image).
 
19
 *
 
20
 * It will load the list of images (in this.modelList) when rendered
 
21
 * for the first time and changes to this.modelList will trigger
 
22
 * re-rendering.
 
23
 *
 
24
 * You can provide your custom rendering method by defining a 'render'
 
25
 * method (also, you can provide methods named 'loadImagesStarted' and
 
26
 * 'loadImagesEnded' to customize the display during the initial loading of the
 
27
 * visible images and a method named 'displayGlobalError' to display a message
 
28
 * when errors occur during loading).
 
29
 *
 
30
 */
 
31
module.ImageListLoader = Y.Base.create('imageListLoader', Y.View, [], {
 
32
 
 
33
    initializer: function(config) {
 
34
        this.modelList = new Y.maas.image.ImageList();
 
35
        this.loaded = false;
 
36
    },
 
37
 
 
38
    render: function () {
 
39
    },
 
40
 
 
41
    /**
 
42
     * Add a loader, a Y.IO object. Events fired by this IO object will
 
43
     * be followed, and will drive updates to this object's model.
 
44
     *
 
45
     * It may be wiser to remodel this to consume a YUI DataSource. That
 
46
     * would make testing easier, for one, but it would also mean we can
 
47
     * eliminate our polling code: DataSource has support for polling
 
48
     * via the datasource-polling module.
 
49
     *
 
50
     * @method addLoader
 
51
     */
 
52
    addLoader: function(loader) {
 
53
        loader.on("io:start", this.loadImagesStarted, this);
 
54
        loader.on("io:end", this.loadImagesEnded, this);
 
55
        loader.on("io:failure", this.loadImagesFailed, this);
 
56
        loader.on("io:success", function(id, request) {
 
57
            this.loadImages(request.responseText);
 
58
        }, this);
 
59
    },
 
60
 
 
61
    /**
 
62
     * Load the images from the given data.
 
63
     *
 
64
     * @method loadImages
 
65
     */
 
66
    loadImages: function(data) {
 
67
        try {
 
68
            var parsed = JSON.parse(data);
 
69
            this.regionImportRunning = parsed.region_import_running;
 
70
            this.clusterImportRunning = parsed.cluster_import_running;
 
71
            this.mergeImages(parsed.resources);
 
72
        }
 
73
        catch(e) {
 
74
            this.loadImagesFailed();
 
75
        }
 
76
        this.loaded = true;
 
77
        this.render();
 
78
    },
 
79
 
 
80
    /**
 
81
     * Process an array of images, merging them into modelList with the
 
82
     * fewest modifications possible.
 
83
     *
 
84
     * @method mergeImages
 
85
     */
 
86
    mergeImages: function(images) {
 
87
        var self = this;
 
88
        var imagesByID = {};
 
89
        Y.Array.each(images, function(image) {
 
90
            imagesByID[image.id] = image;
 
91
        });
 
92
        var modelsByID = {};
 
93
        this.modelList.each(function(model) {
 
94
            modelsByID[model.get("id")] = model;
 
95
        });
 
96
 
 
97
        Y.each(imagesByID, function(image, id) {
 
98
            var model = modelsByID[id];
 
99
            if (Y.Lang.isValue(model)) {
 
100
                // Compare the image and the model.
 
101
                var modelAttrs = model.getAttrs();
 
102
                var modelChanges = {};
 
103
                Y.each(modelAttrs, function(value, key) {
 
104
                    if (image[key] !== value) {
 
105
                        modelChanges[key] = image[key];
 
106
                    }
 
107
                });
 
108
                // Update the image.
 
109
                model.setAttrs(modelChanges);
 
110
            }
 
111
            else {
 
112
                // Add the image.
 
113
                self.modelList.add(image);
 
114
            }
 
115
        });
 
116
 
 
117
        Y.each(modelsByID, function(model, id) {
 
118
            // Remove models that don't correspond to a image.
 
119
            if (!Y.Object.owns(imagesByID, id)) {
 
120
                self.modelList.remove(model);
 
121
            }
 
122
        });
 
123
    },
 
124
 
 
125
   /**
 
126
    * Function called if an error occurs during the initial loading.
 
127
    *
 
128
    * @method displayGlobalError
 
129
    */
 
130
    displayGlobalError: function (error_message) {
 
131
    },
 
132
 
 
133
   /**
 
134
    * Function called when the Image list starts loading.
 
135
    *
 
136
    * @method loadImagesStarted
 
137
    */
 
138
    loadImagesStarted: function() {
 
139
    },
 
140
 
 
141
   /**
 
142
    * Function called when the Image list has loaded.
 
143
    *
 
144
    * @method loadImagesEnded
 
145
    */
 
146
    loadImagesEnded: function() {
 
147
    },
 
148
 
 
149
    /**
 
150
     * Function called when the Image list failed to load.
 
151
     *
 
152
     * @method loadImagesFailed
 
153
     */
 
154
    loadImagesFailed: function() {
 
155
        this.displayGlobalError('Unable to load boot images.');
 
156
    }
 
157
 
 
158
});
 
159
 
 
160
/**
 
161
 * A customized view based on ImageListLoader that will display the
 
162
 * images view.
 
163
 */
 
164
module.ImagesView = Y.Base.create(
 
165
    'imagesView', module.ImageListLoader, [], {
 
166
 
 
167
    regionImportingText: 'Step 1/2: Region importing',
 
168
    clusterImportingText: 'Step 2/2: Clusters importing',
 
169
 
 
170
 
 
171
    initializer: function(config) {
 
172
        this.srcNode = Y.one(config.srcNode);
 
173
        this.loader = this.srcNode.one(config.loader);
 
174
        this.content = this.srcNode.one(config.content);
 
175
        this.importer = this.srcNode.one(config.importer);
 
176
        this.ubuntuOptions = this.srcNode.one(config.ubuntuOptions);
 
177
        this.ubuntuSpinner = this.srcNode.one(config.ubuntuSpinner);
 
178
        this.ubuntuTable = this.srcNode.one(config.ubuntuTable);
 
179
        this.ubuntuMissingImages = this.srcNode.one(config.ubuntuMissingImages);
 
180
        this.ubuntuButton = this.srcNode.one(config.ubuntuButton);
 
181
    },
 
182
 
 
183
   /**
 
184
    * Return all Ubuntu images.
 
185
    *
 
186
    * @ method getUbuntuImages
 
187
    */
 
188
    getUbuntuImages: function() {
 
189
        images = this.modelList.filter(function(model) {
 
190
            return model.get('rtype') === BOOT_RESOURCE_TYPE.SYNCED &&
 
191
                model.get('name').indexOf('ubuntu/') === 0;
 
192
        });
 
193
        // Sort the images decending, so newest Ubuntu version is on top.
 
194
        images.sort(function(a, b) {
 
195
            return -(a.get('title').localeCompare(b.get('title')));
 
196
        });
 
197
        return images;
 
198
    },
 
199
 
 
200
   /**
 
201
    * Display images page.
 
202
    *
 
203
    * @method render
 
204
    */
 
205
    render: function () {
 
206
        if(!this.loaded) {
 
207
            this.loader.removeClass('hidden');
 
208
            this.content.addClass('hidden');
 
209
        } else {
 
210
            this.loader.addClass('hidden');
 
211
            this.content.removeClass('hidden');
 
212
        }
 
213
        this.renderImporting();
 
214
        this.renderUbuntuView();
 
215
    },
 
216
 
 
217
   /**
 
218
    * Render the importing header.
 
219
    *
 
220
    * @method renderUbuntuView
 
221
    */
 
222
    renderImporting: function() {
 
223
        var importingText = this.importer.one('.importing-text');
 
224
        if(!this.regionImportRunning && !this.clusterImportRunning) {
 
225
            this.importer.addClass('hidden');
 
226
            importingText.setContent('');
 
227
        } else if (this.regionImportRunning) {
 
228
            this.importer.removeClass('hidden');
 
229
            importingText.setContent(this.regionImportingText);
 
230
        } else if (this.clusterImportRunning) {
 
231
            this.importer.removeClass('hidden');
 
232
            importingText.setContent(this.clusterImportingText);
 
233
        }
 
234
    },
 
235
 
 
236
   /**
 
237
    * Render the Ubuntu section of the view.
 
238
    *
 
239
    * @method renderUbuntuView
 
240
    */
 
241
    renderUbuntuView: function() {
 
242
        if(this.regionImportRunning) {
 
243
            if(Y.Lang.isValue(this.ubuntuOptions)) {
 
244
                this.ubuntuOptions.addClass('hidden');
 
245
            }
 
246
            if(Y.Lang.isValue(this.ubuntuButton)) {
 
247
                this.ubuntuButton.addClass('hidden');
 
248
            }
 
249
        } else {
 
250
            if(Y.Lang.isValue(this.ubuntuOptions)) {
 
251
                this.ubuntuOptions.removeClass('hidden');
 
252
            }
 
253
            if(Y.Lang.isValue(this.ubuntuButton)) {
 
254
                this.ubuntuButton.removeClass('hidden');
 
255
            }
 
256
        }
 
257
        var ubuntuImages = this.getUbuntuImages();
 
258
        if(ubuntuImages.length === 0) {
 
259
            this.ubuntuMissingImages.removeClass('hidden');
 
260
            this.ubuntuTable.addClass('hidden');
 
261
            this.updateUbuntuButton(false);
 
262
        } else {
 
263
            this.ubuntuMissingImages.addClass('hidden');
 
264
            this.ubuntuTable.removeClass('hidden');
 
265
            this.updateUbuntuButton(true);
 
266
        }
 
267
        var self = this;
 
268
        var innerTable = "";
 
269
        Y.each(ubuntuImages, function(model) {
 
270
            innerTable += "<tr><td>" + self.getSpinner(model) + "</td>";
 
271
            innerTable += "<td>" + model.get('title') + "</td>";
 
272
            innerTable += "<td>" + model.get('arch') + "</td>";
 
273
            innerTable += "<td>" + model.get('size') + "</td>";
 
274
            innerTable += "<td>" + model.get('numberOfNodes') + "</td>";
 
275
            innerTable += "<td>" + model.get('lastUpdate') + "</td>";
 
276
            innerTable += "</tr>";
 
277
        });
 
278
        this.ubuntuTable.one('tbody').setHTML(innerTable);
 
279
    },
 
280
 
 
281
   /**
 
282
    * Update the value of the ubuntuButton.
 
283
    *
 
284
    * The value of the button can be locked meaning it should not change, this
 
285
    * is done using the data attribute lock-value. data-lock-value="true"
 
286
    *
 
287
    * @method updateUbuntuButton
 
288
    */
 
289
    updateUbuntuButton: function(showApply) {
 
290
        if(!Y.Lang.isValue(this.ubuntuButton)) {
 
291
            return;
 
292
        }
 
293
        if(this.ubuntuButton.getData('lock-value') === "true") {
 
294
            return;
 
295
        }
 
296
        if(showApply) {
 
297
            this.ubuntuButton.set('value', 'Apply changes');
 
298
        }
 
299
        else {
 
300
            this.ubuntuButton.set('value', 'Import images');
 
301
        }
 
302
    },
 
303
 
 
304
   /**
 
305
    * Return the HTML for the downloading spinner for the given model.
 
306
    *
 
307
    * @method getSpinner
 
308
    */
 
309
    getSpinner: function(model) {
 
310
        // Spinner is not rendered when the model is complete.
 
311
        if(model.get('complete')) {
 
312
            return '';
 
313
        }
 
314
        html = '<div title="' + model.get('status') + '" class="spinner';
 
315
        if(model.get('downloading')) {
 
316
            html += ' spin';
 
317
        }
 
318
        html += '"></div>';
 
319
        return html;
 
320
    }
 
321
});
 
322
 
 
323
}, '0.1', {'requires': [
 
324
    'view', 'io', 'maas.enums', 'maas.image']}
 
325
);