This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch 4.20
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.20 by this push:
new 951649c420a Support iprange while creating remote access vpn (#12063)
951649c420a is described below
commit 951649c420a96256826533d262f9df8017c9b9b2
Author: Manoj Kumar <[email protected]>
AuthorDate: Tue Dec 9 16:26:16 2025 +0530
Support iprange while creating remote access vpn (#12063)
---
ui/public/locales/en.json | 3 +
ui/src/views/network/VpnDetails.vue | 140 ++++++++++++++++++++++--------------
2 files changed, 90 insertions(+), 53 deletions(-)
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 8f2e1bb5c05..00c81104e75 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -1879,6 +1879,7 @@
"label.release.dedicated.pod": "Release dedicated Pod",
"label.release.dedicated.zone": "Release dedicated Zone",
"label.releasing.ip": "Releasing IP",
+"label.remote.access.vpn.specify.iprange": "Specify IP Range of remote VPN",
"label.remote.instances": "Remote Instances",
"label.remove": "Remove",
"label.remove.annotation": "Remove comment",
@@ -3055,6 +3056,7 @@
"message.enable.vpn.processing": "Enabling VPN...",
"message.enabled.vpn": "Your remote access VPN is currently enabled and can be
accessed via the IP.",
"message.enabled.vpn.ip.sec": "Your IPSec pre-shared key is",
+"message.enabled.vpn.ip.range": "Your VPN IP Range is",
"message.enabling.security.group.provider": "Enabling security group provider",
"message.enter.valid.nic.ip": "Please enter a valid IP address for NIC",
"message.error.access.key": "Please enter access key.",
@@ -3380,6 +3382,7 @@
"message.releasing.dedicated.host": "Releasing dedicated host...",
"message.releasing.dedicated.pod": "Releasing dedicated Pod...",
"message.releasing.dedicated.zone": "Releasing dedicated Zone...",
+"message.remote.access.vpn.iprange.description": "The range of IP addresses to
allocate to VPN clients. The first IP in the range will be taken by the VPN
server. (Optional)",
"message.remove.annotation": "Are you sure you want to delete the comment?",
"message.remove.egress.rule.failed": "Removing egress rule failed",
"message.remove.egress.rule.processing": "Deleting egress rule...",
diff --git a/ui/src/views/network/VpnDetails.vue
b/ui/src/views/network/VpnDetails.vue
index 206f776aa8c..d4c7a87ec79 100644
--- a/ui/src/views/network/VpnDetails.vue
+++ b/ui/src/views/network/VpnDetails.vue
@@ -16,71 +16,93 @@
// under the License.
<template>
- <div v-if="remoteAccessVpn">
- <div>
- <p>{{ $t('message.enabled.vpn') }} <strong>{{ remoteAccessVpn.publicip
}}</strong></p>
- <p>{{ $t('message.enabled.vpn.ip.sec') }} <strong>{{
remoteAccessVpn.presharedkey }}</strong></p>
- <a-divider/>
- <a-button><router-link :to="{ path: '/vpnuser'}">{{
$t('label.manage.vpn.user') }}</router-link></a-button>
- <a-button
- style="margin-left: 10px"
- type="primary"
- danger
- @click="disableVpn = true"
- :disabled="!('deleteRemoteAccessVpn' in $store.getters.apis)">
- {{ $t('label.disable.vpn') }}
- </a-button>
- </div>
+ <div class="vpn-details">
+ <div v-if="remoteAccessVpn">
+ <div>
+ <p>{{ $t('message.enabled.vpn') }} <strong>{{ remoteAccessVpn.publicip
}}</strong></p>
+ <p>{{ $t('message.enabled.vpn.ip.sec') }} <strong>{{
remoteAccessVpn.presharedkey }}</strong></p>
+ <p>{{ $t('message.enabled.vpn.ip.range') }} <strong>{{
remoteAccessVpn.iprange }}</strong></p>
+ <a-divider/>
+ <a-button><router-link :to="{ path: '/vpnuser'}">{{
$t('label.manage.vpn.user') }}</router-link></a-button>
+ <a-button
+ style="margin-left: 10px"
+ type="primary"
+ danger
+ @click="disableVpn = true"
+ :disabled="!('deleteRemoteAccessVpn' in $store.getters.apis)">
+ {{ $t('label.disable.vpn') }}
+ </a-button>
+ </div>
- <a-modal
- :visible="disableVpn"
- :footer="null"
- :title="$t('label.disable.vpn')"
- :closable="true"
- :maskClosable="false"
- @cancel="disableVpn = false">
- <div v-ctrl-enter="handleDisableVpn">
- <p>{{ $t('message.disable.vpn') }}</p>
+ <a-modal
+ :visible="disableVpn"
+ :footer="null"
+ :title="$t('label.disable.vpn')"
+ :closable="true"
+ :maskClosable="false"
+ @cancel="disableVpn = false">
+ <div v-ctrl-enter="handleDisableVpn">
+ <p>{{ $t('message.disable.vpn') }}</p>
- <a-divider />
+ <a-divider />
- <div class="actions">
- <a-button @click="() => disableVpn = false">{{ $t('label.cancel')
}}</a-button>
- <a-button type="primary" @click="handleDisableVpn">{{
$t('label.yes') }}</a-button>
+ <div class="actions">
+ <a-button @click="() => disableVpn = false">{{ $t('label.cancel')
}}</a-button>
+ <a-button type="primary" @click="handleDisableVpn">{{
$t('label.yes') }}</a-button>
+ </div>
</div>
- </div>
- </a-modal>
+ </a-modal>
- </div>
- <div v-else>
- <a-button :disabled="!('createRemoteAccessVpn' in $store.getters.apis)"
type="primary" @click="enableVpn = true">
- {{ $t('label.enable.vpn') }}
- </a-button>
+ </div>
+ <div v-else>
+ <a-button :disabled="!('createRemoteAccessVpn' in $store.getters.apis)"
type="primary" @click="enableVpn = true">
+ {{ $t('label.enable.vpn') }}
+ </a-button>
- <a-modal
- :visible="enableVpn"
- :footer="null"
- :title="$t('label.enable.vpn')"
- :maskClosable="false"
- :closable="true"
- @cancel="enableVpn = false">
- <div v-ctrl-enter="handleCreateVpn">
- <p>{{ $t('message.enable.vpn') }}</p>
+ <a-modal
+ :visible="enableVpn"
+ :footer="null"
+ :title="$t('label.enable.vpn')"
+ :maskClosable="false"
+ :closable="true"
+ @cancel="enableVpn = false">
+ <div v-ctrl-enter="handleCreateVpn">
+ <p>{{ $t('message.enable.vpn') }}</p>
+ <a-form-item>
+ <a-checkbox v-model:checked="specifyIpRange">
+ {{ $t('label.remote.access.vpn.specify.iprange') }}
+ </a-checkbox>
+ </a-form-item>
+ <a-form-item
+ v-if="specifyIpRange"
+ name="iprange"
+ :colon="false"
+ ref="iprange">
+ <template #label>
+ <tooltip-label :title="$t('label.ip.range')"
:tooltip="$t('message.remote.access.vpn.iprange.description')"/>
+ </template>
+ <a-input
+ v-model:value="vpnIpRange"
+ :placeholder="'10.1.2.1-10.1.2.8'"
+ />
+ </a-form-item>
- <a-divider />
+ <a-divider />
- <div class="actions">
- <a-button @click="() => enableVpn = false">{{ $t('label.cancel')
}}</a-button>
- <a-button type="primary" ref="submit" @click="handleCreateVpn">{{
$t('label.yes') }}</a-button>
+ <div class="actions">
+ <a-button @click="() => enableVpn = false">{{ $t('label.cancel')
}}</a-button>
+ <a-button type="primary" ref="submit" @click="handleCreateVpn">{{
$t('label.yes') }}</a-button>
+ </div>
</div>
- </div>
- </a-modal>
+ </a-modal>
+ </div>
</div>
</template>
<script>
import { api } from '@/api'
+import TooltipLabel from '@/components/widgets/TooltipLabel'
export default {
props: {
@@ -89,12 +111,17 @@ export default {
required: true
}
},
+ components: {
+ TooltipLabel
+ },
data () {
return {
remoteAccessVpn: null,
enableVpn: false,
disableVpn: false,
- isSubmitted: false
+ isSubmitted: false,
+ specifyIpRange: false,
+ vpnIpRange: ''
}
},
inject: ['parentFetchData', 'parentToggleLoading'],
@@ -130,11 +157,15 @@ export default {
this.isSubmitted = true
this.parentToggleLoading()
this.enableVpn = false
- api('createRemoteAccessVpn', {
+ const params = {
publicipid: this.resource.id,
domainid: this.resource.domainid,
account: this.resource.account
- }).then(response => {
+ }
+ if (this.specifyIpRange && this.vpnIpRange?.trim()) {
+ params.iprange = this.vpnIpRange.trim()
+ }
+ api('createRemoteAccessVpn', params).then(response => {
this.$pollJob({
jobId: response.createremoteaccessvpnresponse.jobid,
successMethod: result => {
@@ -227,4 +258,7 @@ export default {
}
}
}
+ .vpn-details {
+ padding: 8px 0;
+ }
</style>