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