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>

Reply via email to