Skip to content

Fix adding public IP validations #4272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 15 additions & 72 deletions packages/playground/src/components/node_details.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,8 @@
>
<v-toolbar color="primary">
<div class="d-flex justify-center">
<v-btn
icon
dark
@click="() => $emit('close-dialog', false)"
>
<v-icon color="anchor">
mdi-close
</v-icon>
<v-btn icon dark @click="() => $emit('close-dialog', false)">
<v-icon color="anchor"> mdi-close </v-icon>
</v-btn>
</div>
</v-toolbar>
Expand All @@ -33,87 +27,37 @@
<template v-else-if="isError">
<v-card class="d-flex justify-center align-center h-screen">
<div class="text-center w-100 pa-3">
<v-icon
variant="tonal"
color="error"
style="font-size: 50px"
icon="mdi-close-circle-outline"
/>
<v-icon variant="tonal" color="error" style="font-size: 50px" icon="mdi-close-circle-outline" />
<p class="mt-4 mb-4 font-weight-bold text-error">
{{ errorMessage }}
</p>
<v-btn
class="mr-4"
text="Try Again"
@click="requestNode"
/>
<v-btn
color="error"
text="Cancel"
@click="(val: boolean) => closeDialog(val)"
/>
<v-btn class="mr-4" text="Try Again" @click="requestNode" />
<v-btn color="error" text="Cancel" @click="(val: boolean) => closeDialog(val)" />
</div>
</v-card>
</template>

<template v-else>
<v-card>
<node-resources-charts
:node="node"
:is-live-stats="isLiveStats"
:hint-message="errorLoadingStatsMessage"
/>
<v-row
class="pa-8 mt-5"
justify-md="start"
justify-sm="center"
>
<v-col
cols="12"
md="6"
sm="12"
>
<node-resources-charts :node="node" :is-live-stats="isLiveStats" :hint-message="errorLoadingStatsMessage" />
<v-row class="pa-8 mt-5" justify-md="start" justify-sm="center">
<v-col cols="12" md="6" sm="12">
<node-details-card :node="node" />
<farm-details-card
class="mt-5"
:node="node"
/>
<interfaces-details-card
class="mt-5"
:node="node"
/>
<farm-details-card class="mt-5" :node="node" />
<interfaces-details-card class="mt-5" :node="node" />
<public-config-details-card
v-if="node.publicConfig && node.publicConfig.domain"
class="mt-5"
:node="node"
/>

<cpu-benchmark-card
v-if="hasActiveProfile && node.healthy"
class="mt-5"
:node="node"
/>
<cpu-benchmark-card v-if="hasActiveProfile && node.healthy" class="mt-5" :node="node" />
</v-col>
<v-col
cols="12"
md="6"
sm="12"
>
<v-col cols="12" md="6" sm="12">
<country-details-card :node="node" />
<twin-details-card
class="mt-3"
:node="node"
/>
<gpu-details-card
v-if="node.gpus?.length"
class="mt-3"
:node="node"
/>
<i-perf-card
v-if="hasActiveProfile && node.healthy"
class="mt-3"
:node="node"
/>
<twin-details-card class="mt-3" :node="node" />
<gpu-details-card v-if="node.gpus?.length" class="mt-3" :node="node" />
<i-perf-card v-if="hasActiveProfile && node.healthy" class="mt-3" :node="node" />
</v-col>
</v-row>
</v-card>
Expand Down Expand Up @@ -143,7 +87,6 @@ import { getNode, getNodeStatusColor } from "@/utils/get_nodes";
import IPerfCard from "./node_details_cards/iperf_details_card.vue";
import NodeResourcesCharts from "./node_resources_charts.vue";
export default {

components: {
NodeResourcesCharts,
NodeDetailsCard,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<v-alert v-if="errorMessage" type="error" variant="tonal">
{{ errorMessage }}
</v-alert>

<v-alert v-if="!loading && count && items.length < count" type="error" variant="tonal">
Failed to load <strong>{{ count - items.length }}</strong> deployment{{ count - items.length > 1 ? "s" : "" }}.

Expand Down
102 changes: 46 additions & 56 deletions packages/playground/src/dashboard/components/add_ip.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
<v-container v-if="showDialogue">
<v-dialog v-model="showDialogue" max-width="600" attach="#modals">
<v-card>
<v-card-title class="bg-primary">
Add Public IP to Farm
</v-card-title>
<v-card-title class="bg-primary"> Add Public IP to Farm </v-card-title>
<v-card-text>
<form-validator ref="formValidator" v-model="valid">
<v-select
Expand Down Expand Up @@ -87,9 +85,7 @@
</v-card-text>
<v-dialog v-model="showIPs" max-width="600" attach="#modals">
<v-card>
<v-card-title class="bg-primary">
IPs range
</v-card-title>
<v-card-title class="bg-primary"> IPs range </v-card-title>
<v-card-text>
<v-row>
<v-col>
Expand All @@ -98,21 +94,18 @@
<v-row>
<v-col sm="4">
<p>Network:</p>
</v-col><v-col>
</v-col>
<v-col>
<p>{{ network }}</p>
</v-col>
</v-row>
</v-list-item>
<v-list-item>
<v-row>
<v-col sm="4">
IP Addresses:
</v-col>
<v-col sm="4"> IP Addresses: </v-col>
<v-col>
<v-chip v-for="ip in ipsRangeTable" :key="ip" type="warning" variant="tonal" class="ma-1">
{{
ip
}}
{{ ip }}
</v-chip>
</v-col>
</v-row>
Expand All @@ -124,28 +117,16 @@
</v-card-text>

<v-card-actions class="justify-end mb-1 mr-2">
<v-btn color="anchor" @click="showIPs = false">
Close
</v-btn>
<v-btn color="anchor" @click="showIPs = false"> Close </v-btn>
</v-card-actions>
</v-card>
</v-dialog>

<v-card-actions class="justify-end mb-1 mr-2">
<v-btn color="anchor" @click="showDialogue = false">
Close
</v-btn>
<v-btn color="anchor" @click="showDialogue = false"> Close </v-btn>

<v-btn :disabled="!valid || type === IPType.single || !toPublicIP" @click="showRange">
Show IPs Range
</v-btn>
<v-btn
color="secondary"
:loading="isAdding"
:disabled="!valid || isAdding"
@click="addFarmIp($props.farmId, gateway)"
@update:model-value="$emit('update:isAdded', $event)"
>
<v-btn :disabled="!valid || type === IPType.single || !toPublicIP" @click="showRange"> Show IPs Range </v-btn>
<v-btn color="secondary" :loading="isAdding" :disabled="isAdding || !valid" @click="handleAddFarmIp">
Add
</v-btn>
</v-card-actions>
Expand Down Expand Up @@ -176,7 +157,7 @@ export default {
},
},

setup(_, context) {
setup(props, context) {
const gridStore = useGrid();
const IPs = ref<string[]>();
const items = ref<string[]>([IPType.single, IPType.range]);
Expand All @@ -196,15 +177,6 @@ export default {
const ipsRangeTable = ref<string[]>([]);
const formValidator = ref();

watch(
[publicIP, toPublicIP, gateway],
async () => {
if (publicIP.value.length || toPublicIP.value.length || gateway.value.length)
await formValidator.value.validate();
},
{ deep: true },
);

watch(
type,
() => {
Expand All @@ -225,41 +197,43 @@ export default {
return undefined;
}
function toIpCheck() {
if (toPublicIP.value.split("/")[1] !== publicIP.value.split("/")[1]) {
if (!publicIP.value || !toPublicIP.value) {
return;
}

const fromParts = publicIP.value.split("/");
const toParts = toPublicIP.value.split("/");

if (toParts[1] !== fromParts[1]) {
return {
message: "Subnet is different.",
};
}

if (
parseInt(toPublicIP.value.split("/")[0].split(".")[3]) <= parseInt(publicIP.value.split("/")[0].split(".")[3])
toParts[0].substring(0, toParts[0].lastIndexOf(".")) != fromParts[0].substring(0, fromParts[0].lastIndexOf("."))
) {
return {
message: "To IP must be bigger than From IP.",
message: "IPs are not in the same network.",
};
}

if (
toPublicIP.value.substring(0, toPublicIP.value.lastIndexOf(".")) !=
publicIP.value.substring(0, publicIP.value.lastIndexOf("."))
) {
if (parseInt(toParts[0].split(".")[3]) <= parseInt(fromParts[0].split(".")[3])) {
return {
message: "IPs are not the same.",
message: "To IP must be bigger than From IP.",
};
}
if (
parseInt(toPublicIP.value.split("/")[0].split(".")[3]) -
parseInt(publicIP.value.split("/")[0].split(".")[3]) +
1 >
16
) {
if (parseInt(toParts[0].split(".")[3]) - parseInt(fromParts[0].split(".")[3]) + 1 > 16) {
return {
message: "Range must not exceed 16.",
};
}
}

function gatewayCheck() {
if (!gateway.value || !publicIP.value) {
return;
}

const firstIP = publicIP?.value.split("/")[0];
const lastIP = toPublicIP?.value.split("/")[0];
let isRange = false;
Expand All @@ -276,13 +250,13 @@ export default {
};
}

if (firstIP === gateway.value || lastIP === gateway.value) {
if (firstIP === gateway.value || (lastIP && lastIP === gateway.value)) {
return {
message: "IPs cannot be the same.",
};
}

if (type.value !== IPType.single) {
if (type.value !== IPType.single && lastIP) {
try {
const range = getIPRange(firstIP, lastIP);
if (range.includes(gateway.value)) {
Expand Down Expand Up @@ -335,6 +309,21 @@ export default {
});
}

async function handleAddFarmIp() {
if (!formValidator.value) {
createCustomToast("Form validation error. Please check your inputs.", ToastType.danger);
return;
}

const isValid = await formValidator.value.validate();
if (!isValid) {
createCustomToast("Please fix errors before submitting.", ToastType.danger);
return;
}

await addFarmIp(props.farmId, gateway.value);
}

async function addFarmIp(farmId: number, gw: string) {
try {
isAdding.value = true;
Expand Down Expand Up @@ -403,6 +392,7 @@ export default {

showRange,
addIPs,
handleAddFarmIp,
addFarmIp,
isExistingIp,
toIpCheck,
Expand Down