]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/ceph/ServiceList.js
ui: ceph/ServiceList: stop leaky versionsstores
[pve-manager.git] / www / manager6 / ceph / ServiceList.js
CommitLineData
a6c60aed
DC
1Ext.define('PVE.CephCreateService', {
2 extend: 'Proxmox.window.Edit',
3 xtype: 'pveCephCreateService',
4
5 showProgress: true,
6
7 setNode: function(nodename) {
8 var me = this;
9
10 me.nodename = nodename;
7ce1e64c 11 me.url = "/nodes/" + nodename + "/ceph/" + me.type + "/" + nodename;
a6c60aed
DC
12 },
13
14 method: 'POST',
15 isCreate: true,
16
17 items: [
18 {
19 xtype: 'pveNodeSelector',
20 submitValue: false,
21 fieldLabel: gettext('Host'),
22 selectCurNode: true,
23 allowBlank: false,
24 listeners: {
25 change: function(f, value) {
26 var me = this.up('pveCephCreateService');
27 me.setNode(value);
28 }
29 }
30 }
31 ],
32
33 initComponent : function() {
34 var me = this;
35
36 if (!me.nodename) {
37 throw "no node name specified";
38 }
39
40 if (!me.type) {
41 throw "no type specified";
42 }
43
44 me.setNode(me.nodename);
45
46 me.callParent();
47 }
48});
49
50Ext.define('PVE.node.CephServiceList', {
51 extend: 'Ext.grid.GridPanel',
52 xtype: 'pveNodeCephServiceList',
53
54 onlineHelp: 'chapter_pveceph',
e148c752 55 emptyText: gettext('No such service configured.'),
a6c60aed
DC
56
57 stateful: true,
58
59 // will be called when the store loads
60 storeLoadCallback: Ext.emptyFn,
61
62 // if set to true, does shows the ceph install mask if needed
63 showCephInstallMask: false,
64
65 controller: {
66 xclass: 'Ext.app.ViewController',
67
277d6d15
DC
68 render_version: function(value, metadata, rec) {
69 let me = this.getView();
70 let host = rec.data.host;
71 let icon = "";
72 let v = value;
73 let nodev = [0];
74 if (me.nodeversions[host] !== undefined) {
75 nodev = me.nodeversions[host].version.parts;
76 }
77 let maxv = me.maxversion;
78
79 if (PVE.Utils.compare_ceph_versions(maxv, nodev) > 0) {
80 icon = PVE.Utils.get_ceph_icon_html('HEALTH_UPGRADE');
81 } else if (PVE.Utils.compare_ceph_versions(nodev, v) > 0) {
82 icon = PVE.Utils.get_ceph_icon_html('HEALTH_OLD');
83 } else if (me.mixedversions) {
84 icon = PVE.Utils.get_ceph_icon_html('HEALTH_OK');
85 }
86
87 return icon + v;
88 },
89
90 getMaxVersions: function(store, records, success) {
91 if (!success || records.length < 1) {
92 return;
93 }
94 let me = this;
95 let view = me.getView();
96
97 view.nodeversions = records[0].data.node;
98 view.maxversion = [];
99 view.mixedversions = false;
100 for (const [nodename, data] of Object.entries(view.nodeversions)) {
732c147c
DC
101 let res = PVE.Utils.compare_ceph_versions(data.version.parts, view.maxversion);
102 if (res !== 0 && view.maxversion.length > 0) {
103 view.mixedversions = true;
104 }
105 if (res > 0) {
277d6d15
DC
106 view.maxversion = data.version.parts;
107 }
108 }
109 },
110
a6c60aed
DC
111 init: function(view) {
112 if (view.pveSelNode) {
113 view.nodename = view.pveSelNode.data.node;
114 }
115 if (!view.nodename) {
116 throw "no node name specified";
117 }
118
119 if (!view.type) {
120 throw "no type specified";
121 }
122
277d6d15
DC
123 view.versionsstore = Ext.create('Proxmox.data.UpdateStore', {
124 autoLoad: true,
125 autoStart: true,
126 interval: 10000,
127 storeid: 'ceph-versions-' + view.type + '-list' + view.nodename,
128 proxy: {
129 type: 'proxmox',
130 url: "/api2/json/cluster/ceph/metadata?scope=versions"
131 }
132 });
133
134 view.versionsstore.on('load', this.getMaxVersions, this);
facf9404 135 view.on('destroy', view.versionsstore.stopUpdate);
277d6d15 136
a6c60aed
DC
137 view.rstore = Ext.create('Proxmox.data.UpdateStore', {
138 autoLoad: true,
139 autoStart: true,
140 interval: 3000,
141 storeid: 'ceph-' + view.type + '-list' + view.nodename,
142 model: 'ceph-service-list',
143 proxy: {
144 type: 'proxmox',
145 url: "/api2/json/nodes/" + view.nodename + "/ceph/" + view.type
146 }
147 });
148
149 view.setStore(Ext.create('Proxmox.data.DiffStore', {
150 rstore: view.rstore,
151 sorters: [{ property: 'name' }]
152 }));
153
154 if (view.storeLoadCallback) {
155 view.rstore.on('load', view.storeLoadCallback, this);
156 }
157 view.on('destroy', view.rstore.stopUpdate);
158
159 if (view.showCephInstallMask) {
160 var regex = new RegExp("not (installed|initialized)", "i");
161 PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error) {
162 view.rstore.stopUpdate();
163 PVE.Utils.showCephInstallOrMask(view.ownerCt, error.statusText, view.nodename,
164 function(win){
165 me.mon(win, 'cephInstallWindowClosed', function(){
166 view.rstore.startUpdate();
167 });
168 }
169 );
170 });
171 }
172 },
173
174 service_cmd: function(rec, cmd) {
175 var view = this.getView();
176 if (!rec.data.host) {
177 Ext.Msg.alert(gettext('Error'), "entry has no host");
178 return;
179 }
180 Proxmox.Utils.API2Request({
181 url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
182 method: 'POST',
183 params: { service: view.type + '.' + rec.data.name },
184 success: function(response, options) {
185 var upid = response.result.data;
186 var win = Ext.create('Proxmox.window.TaskProgress', {
187 upid: upid,
188 taskDone: function() {
189 view.rstore.load();
190 }
191 });
192 win.show();
193 },
194 failure: function(response, opts) {
195 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
196 }
197 });
198 },
199 onChangeService: function(btn) {
200 var me = this;
201 var view = this.getView();
202 var cmd = btn.action;
203 var rec = view.getSelection()[0];
204 me.service_cmd(rec, cmd);
205 },
206
207 showSyslog: function() {
208 var view = this.getView();
209 var rec = view.getSelection()[0];
210 var servicename = 'ceph-' + view.type + '@' + rec.data.name;
211 var url = "/api2/extjs/nodes/" + rec.data.host + "/syslog?service=" + encodeURIComponent(servicename);
212 var win = Ext.create('Ext.window.Window', {
213 title: gettext('Syslog') + ': ' + servicename,
214 modal: true,
94b79c8e
DC
215 width: 800,
216 height: 400,
217 layout: 'fit',
a6c60aed
DC
218 items: [{
219 xtype: 'proxmoxLogView',
a6c60aed
DC
220 url: url,
221 log_select_timespan: 1
222 }]
223 });
224 win.show();
225 },
226
227 onCreate: function() {
228 var view = this.getView();
229 var win = Ext.create('PVE.CephCreateService', {
230 autoShow: true,
231 nodename: view.nodename,
232 subject: view.getTitle(),
233 type: view.type,
234 taskDone: function() {
235 view.rstore.load();
236 }
237 });
238 }
239 },
240
241 tbar: [
242 {
243 xtype: 'proxmoxButton',
244 text: gettext('Start'),
245 iconCls: 'fa fa-play',
246 action: 'start',
247 disabled: true,
248 enableFn: function(rec) {
249 return rec.data.state === 'stopped' ||
250 rec.data.state === 'unknown';
251 },
252 handler: 'onChangeService'
253 },
254 {
255 xtype: 'proxmoxButton',
256 text: gettext('Stop'),
257 iconCls: 'fa fa-stop',
258 action: 'stop',
259 enableFn: function(rec) {
260 return rec.data.state !== 'stopped';
261 },
262 disabled: true,
263 handler: 'onChangeService'
264 },
265 {
266 xtype: 'proxmoxButton',
267 text: gettext('Restart'),
268 iconCls: 'fa fa-refresh',
269 action: 'restart',
270 disabled: true,
271 enableFn: function(rec) {
272 return rec.data.state !== 'stopped';
273 },
274 handler: 'onChangeService'
275 },
276 '-',
277 {
278 text: gettext('Create'),
279 reference: 'createButton',
280 handler: 'onCreate'
281 },
282 {
283 text: gettext('Destroy'),
284 xtype: 'proxmoxStdRemoveButton',
285 getUrl: function(rec) {
286 var view = this.up('grid');
287 if (!rec.data.host) {
288 Ext.Msg.alert(gettext('Error'), "entry has no host");
289 return;
290 }
291 return "/nodes/" + rec.data.host + "/ceph/" + view.type + "/" + rec.data.name;
292 },
293 callback: function(options, success, response) {
294 var view = this.up('grid');
295 if (!success) {
296 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
297 return;
298 }
299 var upid = response.result.data;
300 var win = Ext.create('Proxmox.window.TaskProgress', {
301 upid: upid,
302 taskDone: function() {
303 view.rstore.load();
304 }
305 });
306 win.show();
307 }
308 },
309 '-',
310 {
311 xtype: 'proxmoxButton',
312 text: gettext('Syslog'),
313 disabled: true,
314 handler: 'showSyslog'
315 }
316 ],
317
318 columns: [
319 {
320 header: gettext('Name'),
ee099a5f 321 flex: 1,
a6c60aed
DC
322 sortable: true,
323 renderer: function(v) {
324 return this.type + '.' + v;
325 },
326 dataIndex: 'name'
327 },
328 {
329 header: gettext('Host'),
ee099a5f 330 flex: 1,
a6c60aed
DC
331 sortable: true,
332 renderer: function(v) {
333 return v || Proxmox.Utils.unknownText;
334 },
335 dataIndex: 'host'
336 },
337 {
338 header: gettext('Status'),
ee099a5f 339 flex: 1,
a6c60aed
DC
340 sortable: false,
341 dataIndex: 'state'
342 },
343 {
344 header: gettext('Address'),
ee099a5f 345 flex: 3,
a6c60aed
DC
346 sortable: true,
347 renderer: function(v) {
348 return v || Proxmox.Utils.unknownText;
349 },
350 dataIndex: 'addr'
351 },
352 {
353 header: gettext('Version'),
ee099a5f 354 flex: 3,
a6c60aed 355 sortable: true,
277d6d15
DC
356 dataIndex: 'version',
357 renderer: 'render_version',
a6c60aed
DC
358 }
359 ],
360
361 initComponent: function() {
362 var me = this;
363
364 if (me.additionalColumns) {
365 me.columns = me.columns.concat(me.additionalColumns);
366 }
367
368 me.callParent();
369 }
370
371}, function() {
372
373 Ext.define('ceph-service-list', {
374 extend: 'Ext.data.Model',
375 fields: [ 'addr', 'name', 'rank', 'host', 'quorum', 'state',
376 'ceph_version', 'ceph_version_short',
377 { type: 'string', name: 'version', calculate: function(data) {
378 return PVE.Utils.parse_ceph_version(data);
379 } }
380 ],
381 idProperty: 'name'
382 });
383});