Skip to content

Commit 4fb8f8a

Browse files
committed
Additional ports + better doc
1 parent 69bde4b commit 4fb8f8a

File tree

1 file changed

+152
-6
lines changed

1 file changed

+152
-6
lines changed

src/App.jsx

Lines changed: 152 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export default function HcpCliAssistant() {
2828
nodeAZ: "",
2929
nodeImageName: "",
3030
dnsNameservers: "",
31+
additionalPorts: "",
3132
});
3233

3334
const handleChange = (e) => {
@@ -44,6 +45,16 @@ export default function HcpCliAssistant() {
4445
return form.name.trim() !== "" && form.baseDomain.trim() !== "" && form.nodePoolReplicas.trim() !== "";
4546
case 1:
4647
return form.osCloudSet || form.openstackCredentialsFile.trim() !== "";
48+
case 2:
49+
if (form.additionalPorts) {
50+
try {
51+
const ports = JSON.parse(form.additionalPorts);
52+
return ports.every((port) => port.networkId.trim() !== "");
53+
} catch (e) {
54+
return false;
55+
}
56+
}
57+
return true;
4758
case 3:
4859
return form.nodeFlavor.trim() !== "";
4960
default:
@@ -97,6 +108,28 @@ export default function HcpCliAssistant() {
97108
--openstack-node-image-name ${form.nodeImageName}`;
98109
}
99110

111+
if (form.additionalPorts) {
112+
const ports = JSON.parse(form.additionalPorts);
113+
ports.forEach((port, index) => {
114+
let portConfig = `--openstack-node-additional-port=network-id:${port.networkId}`;
115+
116+
if (port.vnicType) {
117+
portConfig += `,vnic-type:${port.vnicType}`;
118+
}
119+
120+
if (port.addressPairs) {
121+
portConfig += `,address-pairs:${port.addressPairs}`;
122+
}
123+
124+
if (port.disablePortSecurity) {
125+
portConfig += `,disable-port-security:true`;
126+
}
127+
128+
cmd += ` \
129+
${portConfig}`;
130+
});
131+
}
132+
100133
cmd = cmd.replace(/\s+/g, ' ').trim();
101134

102135
return cmd;
@@ -133,16 +166,129 @@ export default function HcpCliAssistant() {
133166
</div>
134167
) : (
135168
<div className="space-y-4">
136-
{step === 0 && <><input type="text" name="name" placeholder="Cluster Name" value={form.name} onChange={handleChange} className="w-full p-2 border rounded" required /><input type="text" name="baseDomain" placeholder="Base Domain" value={form.baseDomain} onChange={handleChange} className="w-full p-2 border rounded" required /><input type="number" name="nodePoolReplicas" placeholder="Node Pool Replicas" value={form.nodePoolReplicas} onChange={handleChange} className="w-full p-2 border rounded" required /></>}
169+
{step === 0 && <><input type="text" name="name" placeholder="Cluster Name (required). Example: test" value={form.name} onChange={handleChange} className="w-full p-2 border rounded" required /><input type="text" name="baseDomain" placeholder="Base Domain (required). Example: mydomain.com" value={form.baseDomain} onChange={handleChange} className="w-full p-2 border rounded" required /><input type="number" name="nodePoolReplicas" placeholder="Node Pool Replicas (required)" value={form.nodePoolReplicas} onChange={handleChange} className="w-full p-2 border rounded" required /></>}
137170
{step === 1 && <><label className="block"><input type="checkbox" name="osCloudSet" checked={form.osCloudSet} onChange={handleChange} className="mr-2" />OS_CLOUD is set in the environment</label>{!form.osCloudSet && (
138171
<>
139-
<input type="text" name="openstackCaCertFile" placeholder="OpenStack CA Certificate File (optional)" value={form.openstackCaCertFile} onChange={handleChange} className="w-full p-2 border rounded" />
172+
<input type="text" name="openstackCredentialsFile" placeholder="OpenStack Credentials File (optional). Example: /tmp/clouds.yaml" value={form.openstackCredentialsFile} onChange={handleChange} className="w-full p-2 border rounded" />
173+
</>
174+
)}
175+
<input type="text" name="openstackCloud" placeholder="OpenStack Cloud (optional). Default: openstack" value={form.openstackCloud} onChange={handleChange} className="w-full p-2 border rounded" />
176+
<input type="text" name="openstackCaCertFile" placeholder="OpenStack CA Certificate File (optional). Example: /tmp/ca.cert" value={form.openstackCaCertFile} onChange={handleChange} className="w-full p-2 border rounded" /></>}
177+
{step === 2 && (
178+
<>
179+
<input type="text" name="externalNetworkId" placeholder="External Network ID (optional). Example: 64f629fd-f75b-4e66-96ad-94f6f2125ba4" value={form.externalNetworkId} onChange={handleChange} className="w-full p-2 border rounded" />
180+
<input type="text" name="ingressFloatingIp" placeholder="Ingress Floating IP (optional). Example: 192.168.100.7" value={form.ingressFloatingIp} onChange={handleChange} className="w-full p-2 border rounded" />
181+
<input type="text" name="dnsNameservers" placeholder="DNS Nameservers (optional). Example: 1.1.1.1,8.8.8.8" value={form.dnsNameservers} onChange={handleChange} className="w-full p-2 border rounded" />
182+
183+
<div className="mt-4">
184+
<h3 className="font-semibold mb-2">Additional Nodepool Ports (optional)</h3>
185+
{form.additionalPorts && JSON.parse(form.additionalPorts).map((port, index) => (
186+
<div key={index} className="p-3 border rounded mb-2">
187+
<div className="flex items-center justify-between mb-2">
188+
<span className="font-medium">Port {index + 1}</span>
189+
<button
190+
onClick={() => {
191+
const ports = JSON.parse(form.additionalPorts);
192+
ports.splice(index, 1);
193+
setForm({
194+
...form,
195+
additionalPorts: JSON.stringify(ports)
196+
});
197+
}}
198+
className="px-2 py-1 bg-red-500 text-white rounded"
199+
>
200+
Remove
201+
</button>
202+
</div>
203+
<div className="grid grid-cols-2 gap-2">
204+
<div>
205+
<label className="block text-sm">Network ID (required)</label>
206+
<input
207+
type="text"
208+
value={port.networkId || ""}
209+
onChange={(e) => {
210+
const ports = JSON.parse(form.additionalPorts);
211+
ports[index].networkId = e.target.value;
212+
setForm({
213+
...form,
214+
additionalPorts: JSON.stringify(ports)
215+
});
216+
}}
217+
className="w-full p-2 border rounded"
218+
required
219+
/>
220+
</div>
221+
<div>
222+
<label className="block text-sm">VNIC Type (optional)</label>
223+
<input
224+
type="text"
225+
value={port.vnicType || ""}
226+
onChange={(e) => {
227+
const ports = JSON.parse(form.additionalPorts);
228+
ports[index].vnicType = e.target.value;
229+
setForm({
230+
...form,
231+
additionalPorts: JSON.stringify(ports)
232+
});
233+
}}
234+
className="w-full p-2 border rounded"
235+
/>
236+
</div>
237+
<div>
238+
<label className="block text-sm">Address Pairs (optional)</label>
239+
<input
240+
type="text"
241+
value={port.addressPairs || ""}
242+
onChange={(e) => {
243+
const ports = JSON.parse(form.additionalPorts);
244+
ports[index].addressPairs = e.target.value;
245+
setForm({
246+
...form,
247+
additionalPorts: JSON.stringify(ports)
248+
});
249+
}}
250+
className="w-full p-2 border rounded"
251+
placeholder="ip_address=mac_address,ip_address=mac_address"
252+
/>
253+
</div>
254+
<div className="flex items-center">
255+
<label className="flex items-center text-sm">
256+
<input
257+
type="checkbox"
258+
checked={port.disablePortSecurity || false}
259+
onChange={(e) => {
260+
const ports = JSON.parse(form.additionalPorts);
261+
ports[index].disablePortSecurity = e.target.checked;
262+
setForm({
263+
...form,
264+
additionalPorts: JSON.stringify(ports)
265+
});
266+
}}
267+
className="mr-2"
268+
/>
269+
Disable Port Security
270+
</label>
271+
</div>
272+
</div>
273+
</div>
274+
))}
275+
<button
276+
onClick={() => {
277+
const ports = form.additionalPorts ? JSON.parse(form.additionalPorts) : [];
278+
ports.push({ networkId: "" });
279+
setForm({
280+
...form,
281+
additionalPorts: JSON.stringify(ports)
282+
});
283+
}}
284+
className="mt-2 px-3 py-2 bg-green-500 text-white rounded"
285+
>
286+
Add Port
287+
</button>
288+
</div>
140289
</>
141290
)}
142-
<input type="text" name="openstackCloud" placeholder="OpenStack Cloud (default: openstack)" value={form.openstackCloud} onChange={handleChange} className="w-full p-2 border rounded" />
143-
<input type="text" name="openstackCaCertFile" placeholder="OpenStack CA Certificate File (optional)" value={form.openstackCaCertFile} onChange={handleChange} className="w-full p-2 border rounded" /></>}
144-
{step === 2 && <><input type="text" name="externalNetworkId" placeholder="External Network ID" value={form.externalNetworkId} onChange={handleChange} className="w-full p-2 border rounded" /><input type="text" name="ingressFloatingIp" placeholder="Ingress Floating IP" value={form.ingressFloatingIp} onChange={handleChange} className="w-full p-2 border rounded" /><input type="text" name="dnsNameservers" placeholder="DNS Nameservers (comma-separated)" value={form.dnsNameservers} onChange={handleChange} className="w-full p-2 border rounded" /></>}
145-
{step === 3 && <><input type="text" name="nodeFlavor" placeholder="OpenStack Flavor name for the Nodepool" value={form.nodeFlavor} onChange={handleChange} className="w-full p-2 border rounded" required /><input type="text" name="nodeAZ" placeholder="Nova Availability Zone (optional)" value={form.nodeAZ} onChange={handleChange} className="w-full p-2 border rounded" /><input type="text" name="nodeImageName" placeholder="OpenStack Glance Image Name (optional)" value={form.nodeImageName} onChange={handleChange} className="w-full p-2 border rounded" /></>}
291+
{step === 3 && <><input type="text" name="nodeFlavor" placeholder="Flavor name for the Nodepool (Required)" value={form.nodeFlavor} onChange={handleChange} className="w-full p-2 border rounded" required /><input type="text" name="nodeAZ" placeholder="Nova Availability Zone (optional)" value={form.nodeAZ} onChange={handleChange} className="w-full p-2 border rounded" /><input type="text" name="nodeImageName" placeholder="Glance Image Name (optional)" value={form.nodeImageName} onChange={handleChange} className="w-full p-2 border rounded" /></>}
146292
</div>
147293
)}
148294

0 commit comments

Comments
 (0)