foreman_fog_proxmox 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm.js +54 -33
  3. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm_server.js +25 -5
  4. data/app/assets/stylesheets/foreman_fog_proxmox/accordion.css +21 -0
  5. data/app/helpers/proxmox_compute_resources_helper.rb +1 -1
  6. data/app/helpers/proxmox_form_helper.rb +2 -2
  7. data/app/helpers/proxmox_vm_attrs_helper.rb +131 -0
  8. data/app/helpers/proxmox_vm_cloudinit_helper.rb +1 -1
  9. data/app/helpers/proxmox_vm_interfaces_helper.rb +3 -3
  10. data/app/helpers/proxmox_vm_volumes_helper.rb +3 -3
  11. data/app/models/concerns/fog_extensions/proxmox/node.rb +1 -1
  12. data/app/models/foreman_fog_proxmox/proxmox.rb +1 -1
  13. data/app/models/foreman_fog_proxmox/proxmox_compute_attributes.rb +3 -3
  14. data/app/models/foreman_fog_proxmox/proxmox_console.rb +1 -1
  15. data/app/models/foreman_fog_proxmox/proxmox_images.rb +5 -0
  16. data/app/models/foreman_fog_proxmox/proxmox_version.rb +1 -1
  17. data/app/models/foreman_fog_proxmox/proxmox_vm_commands.rb +5 -2
  18. data/app/models/foreman_fog_proxmox/proxmox_vm_new.rb +1 -1
  19. data/app/overrides/compute_resources_vms/form/add_from_profile_to_compute_attributes_form.rb +8 -0
  20. data/app/overrides/compute_resources_vms/form/add_react_component_to_host.rb +25 -0
  21. data/app/overrides/compute_resources_vms/form/update_react_component_to_host_form.rb +25 -0
  22. data/app/views/compute_resources_vms/form/proxmox/_add_react_component_to_host_form.html.erb +5 -0
  23. data/app/views/compute_resources_vms/form/proxmox/_base.html.erb +21 -21
  24. data/app/views/compute_resources_vms/form/proxmox/_update_react_component_to_host_form.html.erb +26 -0
  25. data/app/views/compute_resources_vms/form/proxmox/container/_config.html.erb +17 -13
  26. data/app/views/compute_resources_vms/form/proxmox/server/_config.html.erb +20 -20
  27. data/app/views/compute_resources_vms/form/proxmox/server/_volume_hard_disk.html.erb +4 -1
  28. data/config/routes.rb +3 -3
  29. data/lib/foreman_fog_proxmox/version.rb +1 -1
  30. data/package.json +42 -0
  31. data/test/factories/proxmox_factory.rb +7 -7
  32. data/test/unit/foreman_fog_proxmox/proxmox_compute_attributes_test.rb +1 -1
  33. data/test/unit/foreman_fog_proxmox/proxmox_interfaces_test.rb +6 -6
  34. data/webpack/components/GeneralTabContent.js +107 -0
  35. data/webpack/components/ProxmoxComputeSelectors.js +141 -0
  36. data/webpack/components/ProxmoxContainer/MountPoint.js +91 -0
  37. data/webpack/components/ProxmoxContainer/ProxmoxContainerHardware.js +85 -0
  38. data/webpack/components/ProxmoxContainer/ProxmoxContainerNetwork.js +179 -0
  39. data/webpack/components/ProxmoxContainer/ProxmoxContainerOptions.js +104 -0
  40. data/webpack/components/ProxmoxContainer/ProxmoxContainerStorage.js +194 -0
  41. data/webpack/components/ProxmoxContainer/components/NetworkInterface.js +193 -0
  42. data/webpack/components/ProxmoxServer/ProxmoxServerHardware.js +204 -0
  43. data/webpack/components/ProxmoxServer/ProxmoxServerNetwork.js +161 -0
  44. data/webpack/components/ProxmoxServer/ProxmoxServerOptions.js +105 -0
  45. data/webpack/components/ProxmoxServer/ProxmoxServerStorage.js +272 -0
  46. data/webpack/components/ProxmoxServer/components/CDRom.js +149 -0
  47. data/webpack/components/ProxmoxServer/components/CPUFlagsModal.js +88 -0
  48. data/webpack/components/ProxmoxServer/components/HardDisk.js +143 -0
  49. data/webpack/components/ProxmoxServer/components/NetworkInterface.js +150 -0
  50. data/webpack/components/ProxmoxStoragesUtils.js +50 -0
  51. data/webpack/components/ProxmoxVmType.js +256 -0
  52. data/webpack/components/ProxmoxVmUtils.js +62 -0
  53. data/webpack/components/common/FormInputs.js +143 -0
  54. data/webpack/global_index.js +15 -0
  55. data/webpack/index.js +7 -0
  56. metadata +50 -21
@@ -0,0 +1,193 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Divider } from '@patternfly/react-core';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+ import InputField from '../../common/FormInputs';
6
+
7
+ const NetworkInterface = ({
8
+ id,
9
+ networks,
10
+ bridges,
11
+ data,
12
+ updateNetworkData,
13
+ existingInterfaces,
14
+ }) => {
15
+ const [network, setNetwork] = useState(data);
16
+ const [error, setError] = useState('');
17
+ useEffect(() => {
18
+ const currentNetData = JSON.stringify(network);
19
+ const parentNetData = JSON.stringify(data);
20
+
21
+ if (currentNetData !== parentNetData) {
22
+ updateNetworkData(id, network);
23
+ }
24
+ }, [network, id, data, updateNetworkData]);
25
+ const handleChange = e => {
26
+ const { name, type, checked, value: targetValue } = e.target;
27
+ let value;
28
+ if (type === 'checkbox') {
29
+ value = checked ? '1' : '0';
30
+ } else {
31
+ value = targetValue;
32
+ }
33
+ const updatedKey = Object.keys(network).find(
34
+ key => network[key].name === name
35
+ );
36
+ const updatedData = {
37
+ ...network,
38
+ [updatedKey]: { ...network[updatedKey], value },
39
+ };
40
+ setNetwork(updatedData);
41
+
42
+ if (updatedKey === 'id') {
43
+ const idValue = value;
44
+ if (
45
+ Object.values(existingInterfaces).some(
46
+ net =>
47
+ net.data.id.value === idValue &&
48
+ net.data.id.value !== network.id.value
49
+ )
50
+ ) {
51
+ setError(__('Error: Duplicate ID found.'));
52
+ return;
53
+ }
54
+ setError('');
55
+ }
56
+ if (updatedKey === 'name') {
57
+ const idValue = value;
58
+ if (
59
+ Object.values(existingInterfaces).some(
60
+ net =>
61
+ net.data.id.value === idValue &&
62
+ net.data.id.value !== network.id.value
63
+ )
64
+ ) {
65
+ setError(__('Error: Duplicate Name found.'));
66
+ } else {
67
+ setError('');
68
+ }
69
+ }
70
+ };
71
+ const bridgesMap = bridges.map(bridge => ({
72
+ value: bridge.iface,
73
+ label: bridge.iface,
74
+ }));
75
+
76
+ return (
77
+ <div style={{ position: 'relative' }}>
78
+ <Divider component="li" style={{ marginBottom: '2rem' }} />
79
+ <InputField
80
+ name={network?.id?.name}
81
+ label={__('Identifier')}
82
+ info={__('net[n] with n integer >= 0, e.g. net0')}
83
+ type="text"
84
+ value={network?.id?.value}
85
+ onChange={handleChange}
86
+ error={error}
87
+ />
88
+ <InputField
89
+ name={network?.name?.name}
90
+ label={__('Name')}
91
+ info={__('eth[n] with n integer >= 0, e.g. eth0')}
92
+ type="text"
93
+ value={network?.name?.value}
94
+ onChange={handleChange}
95
+ error={error}
96
+ />
97
+ <InputField
98
+ name={network?.bridge?.name}
99
+ label={__('Bridge')}
100
+ type="select"
101
+ options={bridgesMap}
102
+ value={network?.bridge?.value}
103
+ onChange={handleChange}
104
+ />
105
+ <InputField
106
+ name={network?.dhcp?.name}
107
+ label={__('DHCP IPv4')}
108
+ type="checkbox"
109
+ value={network?.dhcp?.value}
110
+ checked={network?.dhcp?.value === '1'}
111
+ onChange={handleChange}
112
+ />
113
+ <InputField
114
+ name={network?.cidr?.name}
115
+ label={__('CIDR IPv4')}
116
+ info={__('integer within [0..32]')}
117
+ type="text"
118
+ value={network?.cidr?.value}
119
+ onChange={handleChange}
120
+ />
121
+ <InputField
122
+ name={network?.gw?.name}
123
+ label={__('Gateway IPv4')}
124
+ type="text"
125
+ value={network?.gw?.value}
126
+ onChange={handleChange}
127
+ />
128
+ <InputField
129
+ name={network?.dhcp6?.name}
130
+ label={__('DHCP IPv6')}
131
+ type="checkbox"
132
+ value={network?.dhcp6?.value}
133
+ checked={network?.dhcp6?.value === '1'}
134
+ onChange={handleChange}
135
+ />
136
+ <InputField
137
+ name={network?.cidr6?.name}
138
+ label={__('CIDR IPv6')}
139
+ info={__('integer within [0..128]')}
140
+ type="text"
141
+ value={network?.cidr6?.value}
142
+ onChange={handleChange}
143
+ />
144
+ <InputField
145
+ name={network?.gw6?.name}
146
+ label={__('Gateway IPv6')}
147
+ type="text"
148
+ value={network?.gw6?.value}
149
+ onChange={handleChange}
150
+ />
151
+ <InputField
152
+ name={network?.tag?.name}
153
+ label={__('VLAN Tag')}
154
+ type="text"
155
+ value={network?.tag?.value}
156
+ onChange={handleChange}
157
+ />
158
+ <InputField
159
+ name={network?.rate?.name}
160
+ label={__('Rate limit')}
161
+ type="text"
162
+ value={network?.rate?.value}
163
+ onChange={handleChange}
164
+ />
165
+ <InputField
166
+ name={network?.firewall?.name}
167
+ label={__('Firewall')}
168
+ type="checkbox"
169
+ value={network?.firewall?.value}
170
+ checked={network?.firewall?.value === '1'}
171
+ onChange={handleChange}
172
+ />
173
+ </div>
174
+ );
175
+ };
176
+
177
+ NetworkInterface.propTypes = {
178
+ id: PropTypes.number.isRequired,
179
+ networks: PropTypes.array,
180
+ bridges: PropTypes.array,
181
+ data: PropTypes.object,
182
+ updateNetworkData: PropTypes.func,
183
+ existingInterfaces: PropTypes.array,
184
+ };
185
+
186
+ NetworkInterface.defaultProps = {
187
+ networks: [],
188
+ bridges: [],
189
+ data: {},
190
+ updateNetworkData: Function.prototype,
191
+ existingInterfaces: [],
192
+ };
193
+ export default NetworkInterface;
@@ -0,0 +1,204 @@
1
+ import React, { useState } from 'react';
2
+ import { Button, Title, Divider, PageSection } from '@patternfly/react-core';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+ import PropTypes from 'prop-types';
5
+ import InputField from '../common/FormInputs';
6
+ import ProxmoxComputeSelectors from '../ProxmoxComputeSelectors';
7
+ import CPUFlagsModal from './components/CPUFlagsModal';
8
+
9
+ const cpuFlagNames = [
10
+ 'md_clear',
11
+ 'pcid',
12
+ 'spec_ctrl',
13
+ 'ssbd',
14
+ 'ibpb',
15
+ 'virt_ssbd',
16
+ 'amd_ssbd',
17
+ 'amd_no_ssb',
18
+ 'pdpe1gb',
19
+ 'hv_tlbflush',
20
+ 'hv_evmcs',
21
+ 'aes',
22
+ ];
23
+
24
+ const cpuFlagDescriptions = {
25
+ md_clear: __(
26
+ 'Required to let the guest OS know if MDS is mitigated correctly'
27
+ ),
28
+ pcid: __(
29
+ 'Meltdown fix cost reduction on Westmere, Sandy-, and IvyBridge Intel CPUs'
30
+ ),
31
+ spec_ctrl: __('Allows improved Spectre mitigation with Intel CPUs'),
32
+ ssbd: __('Protection for "Speculative Store Bypass" for Intel models'),
33
+ ibpb: __('Allows improved Spectre mitigation with AMD CPUs'),
34
+ virt_ssbd: __(
35
+ 'Basis for "Speculative Store Bypass" protection for AMD models'
36
+ ),
37
+ amd_ssbd: __(
38
+ 'Improves Spectre mitigation performance with AMD CPUs, best used with "virt-ssbd"'
39
+ ),
40
+ amd_no_ssb: __(
41
+ 'Notifies guest OS that host is not vulnerable for Spectre on AMD CPUs'
42
+ ),
43
+ pdpe1gb: __('Allow guest OS to use 1GB size pages, if host HW supports it'),
44
+ hv_tlbflush: __(
45
+ 'Improve performance in overcommitted Windows guests. May lead to guest bluescreens on old CPUs.'
46
+ ),
47
+ hv_evmcs: __(
48
+ 'Improve performance for nested virtualization. Only supported on Intel CPUs.'
49
+ ),
50
+ aes: __('Activate AES instruction set for HW instruction'),
51
+ };
52
+
53
+ const filterAndAddDescriptions = hardware =>
54
+ Object.keys(hardware)
55
+ .filter(key => cpuFlagNames.includes(key))
56
+ .reduce((acc, key) => {
57
+ acc[key] = {
58
+ ...hardware[key],
59
+ description: cpuFlagDescriptions[key] || '',
60
+ label: key,
61
+ };
62
+ return acc;
63
+ }, {});
64
+
65
+ const ProxmoxServerHardware = ({ hardware }) => {
66
+ const [hw, setHw] = useState(hardware);
67
+ const [isModalOpen, setIsModalOpen] = useState(false);
68
+
69
+ const handleChange = e => {
70
+ const { name, type, checked, value: targetValue } = e.target;
71
+ let value;
72
+ if (type === 'checkbox') {
73
+ value = checked ? '1' : '0';
74
+ } else {
75
+ value = targetValue;
76
+ }
77
+ const updatedKey = Object.keys(hw).find(key => hw[key].name === name);
78
+
79
+ setHw(prevHw => ({
80
+ ...prevHw,
81
+ [updatedKey]: { ...prevHw[updatedKey], value },
82
+ }));
83
+ };
84
+
85
+ const handleModalToggle = _event => {
86
+ setIsModalOpen(prevIsModalOpen => !prevIsModalOpen);
87
+ };
88
+
89
+ const cpuFlags = filterAndAddDescriptions(hw);
90
+
91
+ return (
92
+ <div>
93
+ <PageSection padding={{ default: 'noPadding' }}>
94
+ <Title headingLevel="h3">{__('CPU')}</Title>
95
+ <Divider component="li" style={{ marginBottom: '2rem' }} />
96
+ <InputField
97
+ name={hw?.cpuType?.name}
98
+ label={__('Type')}
99
+ type="select"
100
+ value={hw?.cpuType?.value}
101
+ options={ProxmoxComputeSelectors.proxmoxCpusMap}
102
+ onChange={handleChange}
103
+ />
104
+ <InputField
105
+ name={hw?.sockets?.name}
106
+ label={__('Sockets')}
107
+ type="number"
108
+ value={hw?.sockets?.value}
109
+ onChange={handleChange}
110
+ />
111
+ <InputField
112
+ name={hw?.cores?.name}
113
+ label={__('Cores')}
114
+ type="number"
115
+ value={hw?.cores?.value}
116
+ onChange={handleChange}
117
+ />
118
+ <InputField
119
+ name={hw?.vcpus?.name}
120
+ label={__('VCPUs')}
121
+ type="number"
122
+ value={hw?.vcpus?.value}
123
+ onChange={handleChange}
124
+ />
125
+ <InputField
126
+ name={hw?.cpulimit?.name}
127
+ label={__('CPU limit')}
128
+ type="number"
129
+ value={hw?.cpulimit?.value}
130
+ onChange={handleChange}
131
+ />
132
+ <InputField
133
+ name={hw?.cpuunits?.name}
134
+ label={__('CPU units')}
135
+ type="number"
136
+ value={hw?.cpuunits?.value}
137
+ onChange={handleChange}
138
+ />
139
+ <InputField
140
+ name={hw?.numa?.name}
141
+ label={__('Enable NUMA')}
142
+ type="checkbox"
143
+ value={hw?.numa?.value}
144
+ checked={hw?.numa?.value === '1'}
145
+ onChange={handleChange}
146
+ />
147
+ <div style={{ marginLeft: '5%', display: 'inline-block' }}>
148
+ <Button variant="link" onClick={handleModalToggle}>
149
+ {__('Extra CPU Flags')}
150
+ </Button>
151
+ </div>
152
+ <CPUFlagsModal
153
+ isOpen={isModalOpen}
154
+ onClose={handleModalToggle}
155
+ flags={cpuFlags}
156
+ handleChange={handleChange}
157
+ />
158
+ {Object.keys(cpuFlags).map(key => (
159
+ <input
160
+ key={hw[key].name}
161
+ name={hw[key].name}
162
+ type="hidden"
163
+ value={hw[key].value}
164
+ />
165
+ ))}
166
+ </PageSection>
167
+ <PageSection padding={{ default: 'noPadding' }}>
168
+ <Title headingLevel="h3">{__('Memory')}</Title>
169
+ <Divider component="li" style={{ marginBottom: '2rem' }} />
170
+ <InputField
171
+ name={hw?.memory?.name}
172
+ label={__('Memory (MB)')}
173
+ type="text"
174
+ value={hw?.memory?.value}
175
+ onChange={handleChange}
176
+ />
177
+ <InputField
178
+ name={hw?.balloon?.name}
179
+ label={__('Minimum Memory (MB)')}
180
+ type="text"
181
+ value={hw?.balloon?.value}
182
+ onChange={handleChange}
183
+ />
184
+ <InputField
185
+ name={hw?.shares?.name}
186
+ label={__('Shares (MB)')}
187
+ type="text"
188
+ value={hw?.shares?.value}
189
+ onChange={handleChange}
190
+ />
191
+ </PageSection>
192
+ </div>
193
+ );
194
+ };
195
+
196
+ ProxmoxServerHardware.propTypes = {
197
+ hardware: PropTypes.object,
198
+ };
199
+
200
+ ProxmoxServerHardware.defaultProps = {
201
+ hardware: {},
202
+ };
203
+
204
+ export default ProxmoxServerHardware;
@@ -0,0 +1,161 @@
1
+ import React, { useState, useEffect, useCallback } from 'react';
2
+ import { Title, PageSection, Button } from '@patternfly/react-core';
3
+ import { TimesIcon } from '@patternfly/react-icons';
4
+ import { sprintf, translate as __ } from 'foremanReact/common/I18n';
5
+ import PropTypes from 'prop-types';
6
+ import NetworkInterface from './components/NetworkInterface';
7
+
8
+ const ProxmoxServerNetwork = ({ network, bridges, paramScope }) => {
9
+ const [interfaces, setInterfaces] = useState([]);
10
+ const [nextId, setNextId] = useState(0);
11
+ const [availableIds, setAvailableIds] = useState([]);
12
+ const [usedIds, setUsedIds] = useState(new Set());
13
+ useEffect(() => {
14
+ if (network?.length > 0) {
15
+ const existingIds = new Set();
16
+ network.forEach(net => {
17
+ if (!net.value.model.value) return;
18
+ const id = parseInt(net.value.id.value.replace('net', ''), 10);
19
+ existingIds.add(id);
20
+ addInterface(null, net.value);
21
+ });
22
+ setUsedIds(existingIds);
23
+ }
24
+ }, [network]);
25
+
26
+ const getLowestAvailableId = useCallback(() => {
27
+ let id = 0;
28
+ while (usedIds.has(id)) {
29
+ id += 1;
30
+ }
31
+ return id;
32
+ }, [usedIds]);
33
+ const addInterface = useCallback(
34
+ (event, initialData = null) => {
35
+ if (event) event.preventDefault();
36
+ const netId = getLowestAvailableId();
37
+ const initData = initialData || {
38
+ id: {
39
+ name: `${paramScope}[interfaces_attributes][${nextId}][id]`,
40
+ value: `net${netId}`,
41
+ },
42
+ model: {
43
+ name: `${paramScope}[interfaces_attributes][${nextId}][model]`,
44
+ value: 'virtio',
45
+ },
46
+ bridge: {
47
+ name: `${paramScope}[interfaces_attributes][${nextId}][bridge]`,
48
+ value: bridges?.[0]?.iface || '',
49
+ },
50
+ tag: {
51
+ name: `${paramScope}[interfaces_attributes][${nextId}][tag]`,
52
+ value: '',
53
+ },
54
+ rate: {
55
+ name: `${paramScope}[interfaces_attributes][${nextId}][rate]`,
56
+ value: '',
57
+ },
58
+ queues: {
59
+ name: `${paramScope}[interfaces_attributes][${nextId}][queues]`,
60
+ value: '',
61
+ },
62
+ firewall: {
63
+ name: `${paramScope}[interfaces_attributes][${nextId}][firewall]`,
64
+ value: '0',
65
+ },
66
+ link_down: {
67
+ name: `${paramScope}[interfaces_attributes][${nextId}][link_down]`,
68
+ value: '0',
69
+ },
70
+ };
71
+ setNextId(prevId => {
72
+ if (availableIds.length > 0) {
73
+ setAvailableIds(availableIds.slice(1));
74
+ } else {
75
+ prevId += 1;
76
+ }
77
+ setUsedIds(prevIds => new Set(prevIds).add(netId));
78
+ const newId = availableIds.length > 0 ? availableIds[0] : prevId;
79
+ const newInterface = {
80
+ id: newId,
81
+ data: initData,
82
+ networks: network,
83
+ };
84
+
85
+ setInterfaces(prevInterfaces => [...prevInterfaces, newInterface]);
86
+ return prevId;
87
+ });
88
+ },
89
+ [bridges, network, paramScope, availableIds, nextId, getLowestAvailableId]
90
+ );
91
+
92
+ const removeInterface = idToRemove => {
93
+ const newInterfaces = interfaces.filter(nic => nic.id !== idToRemove);
94
+ setInterfaces(newInterfaces);
95
+ setAvailableIds([...availableIds, idToRemove].sort((a, b) => a - b));
96
+ setUsedIds(prevIds => {
97
+ const newIds = new Set(prevIds);
98
+ newIds.delete(idToRemove);
99
+ return newIds;
100
+ });
101
+ };
102
+
103
+ const updateNetworkData = (id, updatedData) => {
104
+ setInterfaces(
105
+ interfaces.map(net =>
106
+ net.id === id ? { ...net, data: updatedData } : net
107
+ )
108
+ );
109
+ };
110
+
111
+ return (
112
+ <div>
113
+ <PageSection padding={{ default: 'noPadding' }}>
114
+ <Button onClick={addInterface} variant="secondary">
115
+ {__('Add Interface')}
116
+ </Button>
117
+ {interfaces.map(nic => (
118
+ <div key={nic.id} style={{ position: 'relative' }}>
119
+ <div
120
+ style={{
121
+ marginTop: '10px',
122
+ display: 'flex',
123
+ justifyContent: 'space-between',
124
+ alignItems: 'center',
125
+ }}
126
+ >
127
+ <Title headingLevel="h4">
128
+ {sprintf(__('Nic %(nicId)s'), { nicId: nic.id })}
129
+ </Title>
130
+ <button onClick={() => removeInterface(nic.id)} type="button">
131
+ <TimesIcon />
132
+ </button>
133
+ </div>
134
+ <NetworkInterface
135
+ id={nic.id}
136
+ data={nic.data}
137
+ bridges={bridges}
138
+ networks={nic.networks}
139
+ updateNetworkData={updateNetworkData}
140
+ existingInterfaces={interfaces}
141
+ />
142
+ </div>
143
+ ))}
144
+ </PageSection>
145
+ </div>
146
+ );
147
+ };
148
+
149
+ ProxmoxServerNetwork.propTypes = {
150
+ network: PropTypes.object,
151
+ bridges: PropTypes.array,
152
+ paramScope: PropTypes.string,
153
+ };
154
+
155
+ ProxmoxServerNetwork.defaultProps = {
156
+ network: {},
157
+ bridges: [],
158
+ paramScope: '',
159
+ };
160
+
161
+ export default ProxmoxServerNetwork;
@@ -0,0 +1,105 @@
1
+ import React, { useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+ import InputField from '../common/FormInputs';
5
+ import ProxmoxComputeSelectors from '../ProxmoxComputeSelectors';
6
+
7
+ const ProxmoxServerOptions = ({ options }) => {
8
+ const [opts, setOpts] = useState(options);
9
+
10
+ const handleChange = e => {
11
+ const { name, type, checked, value: targetValue } = e.target;
12
+ let value;
13
+ if (type === 'checkbox') {
14
+ value = checked ? '1' : '0';
15
+ } else {
16
+ value = targetValue;
17
+ }
18
+ const updatedKey = Object.keys(opts).find(key => opts[key].name === name);
19
+ setOpts(prevOpts => ({
20
+ ...prevOpts,
21
+ [updatedKey]: { ...prevOpts[updatedKey], value },
22
+ }));
23
+ };
24
+
25
+ return (
26
+ <div>
27
+ <InputField
28
+ name={opts?.boot?.name}
29
+ label={__('Boot device order')}
30
+ info={__(
31
+ 'Order your devices, e.g. order=net0;ide2;scsi0. Default empty (any)'
32
+ )}
33
+ value={opts?.boot?.value}
34
+ onChange={handleChange}
35
+ />
36
+ <InputField
37
+ name={opts?.onboot?.name}
38
+ label={__('Start at boot')}
39
+ type="checkbox"
40
+ value={opts?.onboot?.value}
41
+ checked={opts?.onboot?.value === '1'}
42
+ onChange={handleChange}
43
+ />
44
+ <InputField
45
+ name={opts?.agent?.name}
46
+ label={__('Qemu Agent')}
47
+ type="checkbox"
48
+ value={opts?.agent?.value}
49
+ checked={opts?.agent?.value === '1'}
50
+ onChange={handleChange}
51
+ />
52
+ <InputField
53
+ name={opts?.kvm?.name}
54
+ label={__('KVM')}
55
+ info={__('Enable/disable KVM hardware virtualization')}
56
+ type="checkbox"
57
+ value={opts?.kvm?.value}
58
+ checked={opts?.kvm?.value === '1'}
59
+ onChange={handleChange}
60
+ />
61
+ <InputField
62
+ name={opts?.vga?.name}
63
+ label={__('VGA')}
64
+ type="select"
65
+ value={opts?.vga?.value}
66
+ options={ProxmoxComputeSelectors.proxmoxVgasMap}
67
+ onChange={handleChange}
68
+ />
69
+ <InputField
70
+ name={opts?.scsihw?.name}
71
+ label={__('SCSI Controller')}
72
+ type="select"
73
+ value={opts?.scsihw?.value}
74
+ options={ProxmoxComputeSelectors.proxmoxScsiControllersMap}
75
+ onChange={handleChange}
76
+ />
77
+ <InputField
78
+ name={opts?.bios?.name}
79
+ label={__('BIOS')}
80
+ type="select"
81
+ options={ProxmoxComputeSelectors.proxmoxBiosMap}
82
+ value={opts?.bios?.value}
83
+ onChange={handleChange}
84
+ />
85
+ <InputField
86
+ name={opts?.ostype?.name}
87
+ label={__('OS Type')}
88
+ type="select"
89
+ options={ProxmoxComputeSelectors.proxmoxOperatingSystemsMap}
90
+ value={opts?.ostype?.value}
91
+ onChange={handleChange}
92
+ />
93
+ </div>
94
+ );
95
+ };
96
+
97
+ ProxmoxServerOptions.propTypes = {
98
+ options: PropTypes.object,
99
+ };
100
+
101
+ ProxmoxServerOptions.defaultProps = {
102
+ options: {},
103
+ };
104
+
105
+ export default ProxmoxServerOptions;