]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/node/ZFS.js
ui: cert upload: fix private key field sending empty string
[pve-manager.git] / www / manager6 / node / ZFS.js
CommitLineData
fee716d3
DC
1Ext.define('PVE.node.CreateZFS', {
2 extend: 'Proxmox.window.Edit',
3 xtype: 'pveCreateZFS',
4
dc90ab40 5 onlineHelp: 'chapter_zfs',
fee716d3
DC
6 subject: 'ZFS',
7
8 showProgress: true,
dc90ab40 9 isCreate: true,
7d2e6f5b
SI
10 width: 800,
11
84cf9e4f
SH
12 viewModel: {
13 data: {
14 raidLevel: 'single',
15 },
16 formulas: {
049b7836 17 isDraid: get => get('raidLevel')?.startsWith("draid"),
84cf9e4f
SH
18 },
19 },
20
8058410f 21 initComponent: function() {
dc90ab40 22 let me = this;
fee716d3
DC
23
24 if (!me.nodename) {
25 throw "no node name specified";
26 }
27
fee716d3 28 Ext.apply(me, {
dc90ab40 29 url: `/nodes/${me.nodename}/disks/zfs`,
fee716d3
DC
30 method: 'POST',
31 items: [
32 {
33 xtype: 'inputpanel',
049b7836
TL
34 onGetValues: function(values) {
35 if (values.draidData || values.draidSpares) {
36 let opt = { data: values.draidData, spares: values.draidSpares };
37 values['draid-config'] = PVE.Parser.printPropertyString(opt);
38 }
39 delete values.draidData;
40 delete values.draidSpares;
41 return values;
42 },
fee716d3 43 column1: [
fee716d3
DC
44 {
45 xtype: 'proxmoxtextfield',
46 name: 'name',
47 fieldLabel: gettext('Name'),
f6710aac 48 allowBlank: false,
87f43acb
TL
49 maxLength: 128, // ZFS_MAX_DATASET_NAME_LEN is (256 - some edge case)
50 validator: v => {
51 // see zpool_name_valid function in libzfs_zpool.c
52 if (v.match(/^(mirror|raidz|draid|spare)/) || v === 'log') {
53 return gettext('Cannot use reserved pool name');
54 } else if (!v.match(/^[a-zA-Z][a-zA-Z0-9\-_.]*$/)) {
55 // note: zfs would support also : and whitespace, but we don't
56 return gettext("Invalid characters in pool name");
57 }
58 return true;
59 },
fee716d3
DC
60 },
61 {
62 xtype: 'proxmoxcheckbox',
63 name: 'add_storage',
64 fieldLabel: gettext('Add Storage'),
f6710aac
TL
65 value: '1',
66 },
fee716d3
DC
67 ],
68 column2: [
69 {
70 xtype: 'proxmoxKVComboBox',
71 fieldLabel: gettext('RAID Level'),
72 name: 'raidlevel',
f04e415b 73 value: 'single',
fee716d3 74 comboItems: [
f04e415b 75 ['single', gettext('Single Disk')],
fee716d3
DC
76 ['mirror', 'Mirror'],
77 ['raid10', 'RAID10'],
78 ['raidz', 'RAIDZ'],
79 ['raidz2', 'RAIDZ2'],
f6710aac 80 ['raidz3', 'RAIDZ3'],
84cf9e4f
SH
81 ['draid', 'dRAID'],
82 ['draid2', 'dRAID2'],
83 ['draid3', 'dRAID3'],
f6710aac 84 ],
84cf9e4f
SH
85 bind: {
86 value: '{raidLevel}',
87 },
88 },
fee716d3
DC
89 {
90 xtype: 'proxmoxKVComboBox',
91 fieldLabel: gettext('Compression'),
92 name: 'compression',
93 value: 'on',
94 comboItems: [
95 ['on', 'on'],
96 ['off', 'off'],
97 ['gzip', 'gzip'],
98 ['lz4', 'lz4'],
99 ['lzjb', 'lzjb'],
f6710aac 100 ['zle', 'zle'],
fc2ff3e8 101 ['zstd', 'zstd'],
f6710aac 102 ],
fee716d3
DC
103 },
104 {
105 xtype: 'proxmoxintegerfield',
106 fieldLabel: gettext('ashift'),
107 minValue: 9,
108 maxValue: 16,
109 value: '12',
f6710aac
TL
110 name: 'ashift',
111 },
fee716d3
DC
112 ],
113 columnB: [
2db62238
TL
114 {
115 xtype: 'fieldset',
116 title: gettext('dRAID Config'),
117 collapsible: false,
118 bind: {
119 hidden: '{!isDraid}',
120 },
121 layout: 'hbox',
122 padding: '5px 10px',
123 defaults: {
124 flex: 1,
125 layout: 'anchor',
126 },
127 items: [{
128 xtype: 'proxmoxintegerfield',
129 name: 'draidData',
130 fieldLabel: gettext('Data Devs'),
131 minValue: 1,
132 allowBlank: false,
133 disabled: true,
134 hidden: true,
135 bind: {
136 disabled: '{!isDraid}',
137 hidden: '{!isDraid}',
138 },
139 padding: '0 10 0 0',
140 },
141 {
142 xtype: 'proxmoxintegerfield',
143 name: 'draidSpares',
144 fieldLabel: gettext('Spares'),
145 minValue: 0,
146 allowBlank: false,
147 disabled: true,
148 hidden: true,
149 bind: {
150 disabled: '{!isDraid}',
151 hidden: '{!isDraid}',
152 },
153 padding: '0 0 0 10',
154 }],
155 },
fee716d3 156 {
87f16008
FE
157 xtype: 'pmxMultiDiskSelector',
158 name: 'devices',
159 nodename: me.nodename,
160 diskType: 'unused',
6c356c92 161 includePartitions: true,
fee716d3
DC
162 height: 200,
163 emptyText: gettext('No Disks unused'),
164 itemId: 'disklist',
f6710aac
TL
165 },
166 ],
deca45c1
TL
167 },
168 {
169 xtype: 'displayfield',
170 padding: '5 0 0 0',
f71b7c28 171 userCls: 'pmx-hint',
deca45c1 172 value: 'Note: ZFS is not compatible with disks backed by a hardware ' +
dc90ab40
TL
173 'RAID controller. For details see <a target="_blank" href="' +
174 Proxmox.Utils.get_help_link('chapter_zfs') + '">the reference documentation</a>.',
f6710aac
TL
175 },
176 ],
fee716d3
DC
177 });
178
179 me.callParent();
f6710aac 180 },
84cf9e4f 181
fee716d3
DC
182});
183
fee716d3
DC
184Ext.define('PVE.node.ZFSList', {
185 extend: 'Ext.grid.Panel',
186 xtype: 'pveZFSList',
187
14066c09
FE
188 viewModel: {
189 data: {
190 pool: '',
191 },
192 },
193
194 controller: {
195 xclass: 'Ext.app.ViewController',
196
197 destroyPool: function() {
198 let me = this;
199 let vm = me.getViewModel();
200 let view = me.getView();
201
202 const pool = vm.get('pool');
203
204 if (!view.nodename) {
205 throw "no node name specified";
206 }
207
208 if (!pool) {
209 throw "no pool specified";
210 }
211
bccfb43f 212 Ext.create('PVE.window.SafeDestroyStorage', {
14066c09
FE
213 url: `/nodes/${view.nodename}/disks/zfs/${pool}`,
214 item: { id: pool },
14066c09
FE
215 taskName: 'zfsremove',
216 taskDone: () => { view.reload(); },
217 }).show();
218 },
219 },
220
fee716d3
DC
221 stateful: true,
222 stateId: 'grid-node-zfs',
223 columns: [
224 {
225 text: gettext('Name'),
226 dataIndex: 'name',
f6710aac 227 flex: 1,
fee716d3
DC
228 },
229 {
230 header: gettext('Size'),
231 renderer: Proxmox.Utils.format_size,
f6710aac 232 dataIndex: 'size',
fee716d3
DC
233 },
234 {
235 header: gettext('Free'),
236 renderer: Proxmox.Utils.format_size,
f6710aac 237 dataIndex: 'free',
fee716d3
DC
238 },
239 {
240 header: gettext('Allocated'),
241 renderer: Proxmox.Utils.format_size,
f6710aac 242 dataIndex: 'alloc',
fee716d3
DC
243 },
244 {
245 header: gettext('Fragmentation'),
246 renderer: function(value) {
247 return value.toString() + '%';
248 },
f6710aac 249 dataIndex: 'frag',
fee716d3
DC
250 },
251 {
252 header: gettext('Health'),
253 renderer: PVE.Utils.render_zfs_health,
f6710aac 254 dataIndex: 'health',
fee716d3
DC
255 },
256 {
257 header: gettext('Deduplication'),
258 hidden: true,
259 renderer: function(value) {
260 return value.toFixed(2).toString() + 'x';
261 },
f6710aac
TL
262 dataIndex: 'dedup',
263 },
fee716d3
DC
264 ],
265
266 rootVisible: false,
267 useArrows: true,
268
269 tbar: [
270 {
271 text: gettext('Reload'),
272 iconCls: 'fa fa-refresh',
273 handler: function() {
dc90ab40 274 this.up('panel').reload();
f6710aac 275 },
fee716d3
DC
276 },
277 {
278 text: gettext('Create') + ': ZFS',
279 handler: function() {
dc90ab40
TL
280 let view = this.up('panel');
281 Ext.create('PVE.node.CreateZFS', {
282 nodename: view.nodename,
283 listeners: {
284 destroy: () => view.reload(),
285 },
286 autoShow: true,
287 });
f6710aac 288 },
fee716d3
DC
289 },
290 {
291 text: gettext('Detail'),
292 itemId: 'detailbtn',
293 disabled: true,
294 handler: function() {
dc90ab40
TL
295 let view = this.up('panel');
296 let selection = view.getSelection();
297 if (selection.length) {
298 view.show_detail(selection[0].get('name'));
fee716d3 299 }
f6710aac
TL
300 },
301 },
14066c09
FE
302 '->',
303 {
304 xtype: 'tbtext',
305 data: {
306 pool: undefined,
307 },
308 bind: {
309 data: {
310 pool: "{pool}",
311 },
312 },
313 tpl: [
314 '<tpl if="pool">',
315 'Pool {pool}:',
316 '<tpl else>',
317 Ext.String.format(gettext('No {0} selected'), 'pool'),
318 '</tpl>',
319 ],
320 },
321 {
322 text: gettext('More'),
323 iconCls: 'fa fa-bars',
324 disabled: true,
325 bind: {
326 disabled: '{!pool}',
327 },
328 menu: [
329 {
330 text: gettext('Destroy'),
331 itemId: 'remove',
332 iconCls: 'fa fa-fw fa-trash-o',
333 handler: 'destroyPool',
334 disabled: true,
335 bind: {
336 disabled: '{!pool}',
337 },
338 },
339 ],
340 },
fee716d3
DC
341 ],
342
343 show_detail: function(zpool) {
dc90ab40 344 let me = this;
8cfe2088 345
545f94e7
FE
346 Ext.create('Proxmox.window.ZFSDetail', {
347 zpool,
8cfe2088 348 nodename: me.nodename,
545f94e7 349 }).show();
fee716d3
DC
350 },
351
352 set_button_status: function() {
353 var me = this;
fee716d3
DC
354 },
355
356 reload: function() {
357 var me = this;
358 me.store.load();
359 me.store.sort();
360 },
361
362 listeners: {
363 activate: function() {
dc90ab40 364 this.reload();
fee716d3 365 },
14066c09
FE
366 selectionchange: function(model, selected) {
367 let me = this;
368 let vm = me.getViewModel();
369
370 me.down('#detailbtn').setDisabled(selected.length === 0);
371 vm.set('pool', selected[0]?.data.name || '');
fee716d3
DC
372 },
373 itemdblclick: function(grid, record) {
dc90ab40 374 this.show_detail(record.get('name'));
f6710aac 375 },
fee716d3
DC
376 },
377
378 initComponent: function() {
dc90ab40 379 let me = this;
fee716d3
DC
380
381 me.nodename = me.pveSelNode.data.node;
382 if (!me.nodename) {
383 throw "no node name specified";
384 }
385
386 Ext.apply(me, {
387 store: {
388 fields: ['name', 'size', 'free', 'alloc', 'dedup', 'frag', 'health'],
389 proxy: {
390 type: 'proxmox',
dc90ab40 391 url: `/api2/json/nodes/${me.nodename}/disks/zfs`,
fee716d3 392 },
f6710aac
TL
393 sorters: 'name',
394 },
fee716d3
DC
395 });
396
397 me.callParent();
398
399 Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
400 me.reload();
f6710aac 401 },
fee716d3
DC
402});
403