]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/dc/Cluster.js
ui: ceph/status: cleanup legacy version handling
[pve-manager.git] / www / manager6 / dc / Cluster.js
1 /*jslint confusion: true*/
2 Ext.define('pve-cluster-nodes', {
3 extend: 'Ext.data.Model',
4 fields: [
5 'node', { type: 'integer', name: 'nodeid' }, 'ring0_addr', 'ring1_addr',
6 { type: 'integer', name: 'quorum_votes' }
7 ],
8 proxy: {
9 type: 'proxmox',
10 url: "/api2/json/cluster/config/nodes"
11 },
12 idProperty: 'nodeid'
13 });
14
15 Ext.define('pve-cluster-info', {
16 extend: 'Ext.data.Model',
17 proxy: {
18 type: 'proxmox',
19 url: "/api2/json/cluster/config/join"
20 }
21 });
22
23 Ext.define('PVE.ClusterAdministration', {
24 extend: 'Ext.panel.Panel',
25 xtype: 'pveClusterAdministration',
26
27 title: gettext('Cluster Administration'),
28 onlineHelp: 'chapter_pvecm',
29
30 border: false,
31 defaults: { border: false },
32
33 viewModel: {
34 parent: null,
35 data: {
36 totem: {},
37 nodelist: [],
38 preferred_node: {
39 name: '',
40 fp: '',
41 addr: ''
42 },
43 isInCluster: false,
44 nodecount: 0
45 }
46 },
47
48 items: [
49 {
50 xtype: 'panel',
51 title: gettext('Cluster Information'),
52 controller: {
53 xclass: 'Ext.app.ViewController',
54
55 init: function(view) {
56 view.store = Ext.create('Proxmox.data.UpdateStore', {
57 autoStart: true,
58 interval: 15 * 1000,
59 storeid: 'pve-cluster-info',
60 model: 'pve-cluster-info'
61 });
62 view.store.on('load', this.onLoad, this);
63 view.on('destroy', view.store.stopUpdate);
64 },
65
66 onLoad: function(store, records, success) {
67 var vm = this.getViewModel();
68 if (!success || !records || !records[0].data) {
69 vm.set('totem', {});
70 vm.set('isInCluster', false);
71 vm.set('nodelist', []);
72 vm.set('preferred_node', {
73 name: '',
74 addr: '',
75 fp: ''
76 });
77 return;
78 }
79 var data = records[0].data;
80 vm.set('totem', data.totem);
81 vm.set('isInCluster', !!data.totem.cluster_name);
82 vm.set('nodelist', data.nodelist);
83
84 var nodeinfo = Ext.Array.findBy(data.nodelist, function (el) {
85 return el.name === data.preferred_node;
86 });
87
88 let links = {};
89 let ring_addr = [];
90 PVE.Utils.forEachCorosyncLink(nodeinfo, (num, link) => {
91 links[num] = link;
92 ring_addr.push(link);
93 });
94
95 vm.set('preferred_node', {
96 name: data.preferred_node,
97 addr: nodeinfo.pve_addr,
98 peerLinks: links,
99 ring_addr: ring_addr,
100 fp: nodeinfo.pve_fp
101 });
102 },
103
104 onCreate: function() {
105 var view = this.getView();
106 view.store.stopUpdate();
107 var win = Ext.create('PVE.ClusterCreateWindow', {
108 autoShow: true,
109 listeners: {
110 destroy: function() {
111 view.store.startUpdate();
112 }
113 }
114 });
115 },
116
117 onClusterInfo: function() {
118 var vm = this.getViewModel();
119 var win = Ext.create('PVE.ClusterInfoWindow', {
120 joinInfo: {
121 ipAddress: vm.get('preferred_node.addr'),
122 fingerprint: vm.get('preferred_node.fp'),
123 peerLinks: vm.get('preferred_node.peerLinks'),
124 ring_addr: vm.get('preferred_node.ring_addr'),
125 totem: vm.get('totem')
126 }
127 });
128 win.show();
129 },
130
131 onJoin: function() {
132 var view = this.getView();
133 view.store.stopUpdate();
134 var win = Ext.create('PVE.ClusterJoinNodeWindow', {
135 autoShow: true,
136 listeners: {
137 destroy: function() {
138 view.store.startUpdate();
139 }
140 }
141 });
142 }
143 },
144 tbar: [
145 {
146 text: gettext('Create Cluster'),
147 reference: 'createButton',
148 handler: 'onCreate',
149 bind: {
150 disabled: '{isInCluster}'
151 }
152 },
153 {
154 text: gettext('Join Information'),
155 reference: 'addButton',
156 handler: 'onClusterInfo',
157 bind: {
158 disabled: '{!isInCluster}'
159 }
160 },
161 {
162 text: gettext('Join Cluster'),
163 reference: 'joinButton',
164 handler: 'onJoin',
165 bind: {
166 disabled: '{isInCluster}'
167 }
168 }
169 ],
170 layout: 'hbox',
171 bodyPadding: 5,
172 items: [
173 {
174 xtype: 'displayfield',
175 fieldLabel: gettext('Cluster Name'),
176 bind: {
177 value: '{totem.cluster_name}',
178 hidden: '{!isInCluster}'
179 },
180 flex: 1
181 },
182 {
183 xtype: 'displayfield',
184 fieldLabel: gettext('Config Version'),
185 bind: {
186 value: '{totem.config_version}',
187 hidden: '{!isInCluster}'
188 },
189 flex: 1
190 },
191 {
192 xtype: 'displayfield',
193 fieldLabel: gettext('Number of Nodes'),
194 labelWidth: 120,
195 bind: {
196 value: '{nodecount}',
197 hidden: '{!isInCluster}'
198 },
199 flex: 1
200 },
201 {
202 xtype: 'displayfield',
203 value: gettext('Standalone node - no cluster defined'),
204 bind: {
205 hidden: '{isInCluster}'
206 },
207 flex: 1
208 }
209 ]
210 },
211 {
212 xtype: 'grid',
213 title: gettext('Cluster Nodes'),
214 autoScroll: true,
215 enableColumnHide: false,
216 controller: {
217 xclass: 'Ext.app.ViewController',
218
219 init: function(view) {
220 view.rstore = Ext.create('Proxmox.data.UpdateStore', {
221 autoLoad: true,
222 xtype: 'update',
223 interval: 5 * 1000,
224 autoStart: true,
225 storeid: 'pve-cluster-nodes',
226 model: 'pve-cluster-nodes'
227 });
228 view.setStore(Ext.create('Proxmox.data.DiffStore', {
229 rstore: view.rstore,
230 sorters: {
231 property: 'nodeid',
232 order: 'DESC'
233 }
234 }));
235 Proxmox.Utils.monStoreErrors(view, view.rstore);
236 view.rstore.on('load', this.onLoad, this);
237 view.on('destroy', view.rstore.stopUpdate);
238 },
239
240 onLoad: function(store, records, success) {
241 var view = this.getView();
242 var vm = this.getViewModel();
243
244 if (!success || !records || !records.length) {
245 vm.set('nodecount', 0);
246 return;
247 }
248 vm.set('nodecount', records.length);
249
250 // show/hide columns according to used links
251 var linkIndex = view.columns.length;
252 var columns = Ext.each(view.columns, (col, i) => {
253 if (col.linkNumber !== undefined) {
254 col.setHidden(true);
255
256 // save offset at which link columns start, so we
257 // can address them directly below
258 if (i < linkIndex) {
259 linkIndex = i;
260 }
261 }
262 });
263
264 PVE.Utils.forEachCorosyncLink(records[0].data,
265 (linknum, val) => {
266 if (linknum > 7) {
267 return;
268 }
269 view.columns[linkIndex+linknum].setHidden(false);
270 }
271 );
272 }
273 },
274 columns: {
275 items: [
276 {
277 header: gettext('Nodename'),
278 hidden: false,
279 dataIndex: 'name'
280 },
281 {
282 header: gettext('ID'),
283 minWidth: 100,
284 width: 100,
285 flex: 0,
286 hidden: false,
287 dataIndex: 'nodeid'
288 },
289 {
290 header: gettext('Votes'),
291 minWidth: 100,
292 width: 100,
293 flex: 0,
294 hidden: false,
295 dataIndex: 'quorum_votes'
296 },
297 {
298 header: Ext.String.format(gettext('Link {0}'), 0),
299 dataIndex: 'ring0_addr',
300 linkNumber: 0
301 },
302 {
303 header: Ext.String.format(gettext('Link {0}'), 1),
304 dataIndex: 'ring1_addr',
305 linkNumber: 1
306 },
307 {
308 header: Ext.String.format(gettext('Link {0}'), 2),
309 dataIndex: 'ring2_addr',
310 linkNumber: 2
311 },
312 {
313 header: Ext.String.format(gettext('Link {0}'), 3),
314 dataIndex: 'ring3_addr',
315 linkNumber: 3
316 },
317 {
318 header: Ext.String.format(gettext('Link {0}'), 4),
319 dataIndex: 'ring4_addr',
320 linkNumber: 4
321 },
322 {
323 header: Ext.String.format(gettext('Link {0}'), 5),
324 dataIndex: 'ring5_addr',
325 linkNumber: 5
326 },
327 {
328 header: Ext.String.format(gettext('Link {0}'), 6),
329 dataIndex: 'ring6_addr',
330 linkNumber: 6
331 },
332 {
333 header: Ext.String.format(gettext('Link {0}'), 7),
334 dataIndex: 'ring7_addr',
335 linkNumber: 7
336 }
337 ],
338 defaults: {
339 flex: 1,
340 hidden: true,
341 minWidth: 150
342 }
343 }
344 }
345 ]
346 });