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