You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2020/01/21 11:04:34 UTC

[cloudstack-primate] branch master updated: network: Static NAT enable form (#119)

This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack-primate.git


The following commit(s) were added to refs/heads/master by this push:
     new 0cb23ed  network: Static NAT enable form (#119)
0cb23ed is described below

commit 0cb23ed5a8c1c9c517d2136d5bf12890c529fd8b
Author: Ritchie Vincent <rf...@gmail.com>
AuthorDate: Tue Jan 21 11:04:25 2020 +0000

    network: Static NAT enable form (#119)
    
    Add static NAT form for public IP
---
 src/components/view/ResourceView.vue  |   1 +
 src/config/section/network.js         |   8 +-
 src/views/network/EnableStaticNat.vue | 277 ++++++++++++++++++++++++++++++++++
 3 files changed, 280 insertions(+), 6 deletions(-)

diff --git a/src/components/view/ResourceView.vue b/src/components/view/ResourceView.vue
index a1c4bf7..2dc572e 100644
--- a/src/components/view/ResourceView.vue
+++ b/src/components/view/ResourceView.vue
@@ -110,6 +110,7 @@ export default {
     },
     showHideTab (tab) {
       if ('networkServiceFilter' in tab) {
+        if (this.resource.virtualmachineid && tab.name !== 'Firewall') return false
         return this.networkService && this.networkService.service &&
           tab.networkServiceFilter(this.networkService.service)
       } else if ('show' in tab) {
diff --git a/src/config/section/network.js b/src/config/section/network.js
index a2a429a..e1f57cc 100644
--- a/src/config/section/network.js
+++ b/src/config/section/network.js
@@ -260,12 +260,8 @@ export default {
           label: 'Enable Static NAT',
           dataView: true,
           show: (record) => { return !record.virtualmachineid && !record.issourcenat },
-          args: ['ipaddressid', 'virtualmachineid', 'vmguestip'],
-          mapping: {
-            ipaddressid: {
-              value: (record) => { return record.id }
-            }
-          }
+          popup: true,
+          component: () => import('@/views/network/EnableStaticNat.vue')
         },
         {
           api: 'disableStaticNat',
diff --git a/src/views/network/EnableStaticNat.vue b/src/views/network/EnableStaticNat.vue
new file mode 100644
index 0000000..30cbb62
--- /dev/null
+++ b/src/views/network/EnableStaticNat.vue
@@ -0,0 +1,277 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+<template>
+  <a-list class="list" :loading="loading">
+    <div slot="header" class="list__header">
+      <a-input-search
+        placeholder="Search"
+        v-model="searchQuery"
+        @search="fetchData" />
+    </div>
+
+    <a-list-item
+      v-for="vm in vmsList"
+      :key="vm.id"
+      class="list__item"
+      :class="{ 'list__item--selected' : selectedVm && selectedVm.id === vm.id }">
+
+      <div class="list__outer-container">
+        <div class="list__container" @click="() => handleSelectItem(vm)">
+          <div class="list__row">
+            <div class="list__title">{{ $t('name') }}</div>
+            <div>{{ vm.name }}</div>
+          </div>
+          <div class="list__row">
+            <div class="list__title">{{ $t('instancename') }}</div>
+            <div>{{ vm.instancename }}</div>
+          </div>
+          <div class="list__row">
+            <div class="list__title">{{ $t('displayname') }}</div>
+            <div>{{ vm.displayname }}</div>
+          </div>
+          <div class="list__row">
+            <div class="list__title">{{ $t('account') }}</div>
+            <div>{{ vm.account }}</div>
+          </div>
+          <div class="list__row">
+            <div class="list__title">{{ $t('zonenamelabel') }}</div>
+            <div>{{ vm.zonename }}</div>
+          </div>
+          <div class="list__row">
+            <div class="list__title">{{ $t('state') }}</div>
+            <div>{{ vm.state }}</div>
+          </div>
+          <a-radio
+            class="list__radio"
+            :checked="selectedVm && selectedVm.id === vm.id"
+            @change="fetchNics"></a-radio>
+        </div>
+
+        <a-select
+          v-if="nicsList.length && selectedVm && selectedVm.id === vm.id"
+          class="nic-select"
+          :defaultValue="selectedNic.ipaddress">
+          <a-select-option
+            @click="selectedNic = item"
+            v-for="item in nicsList"
+            :key="item.id">
+            {{ item.ipaddress }}
+          </a-select-option>
+        </a-select>
+      </div>
+
+    </a-list-item>
+
+    <div slot="footer" class="list__footer">
+      <a-button @click="handleClose">{{ $t('cancel') }}</a-button>
+      <a-button @click="handleSubmit" type="primary" :disabled="!selectedVm || !selectedNic">{{ $t('ok') }}</a-button>
+    </div>
+
+  </a-list>
+</template>
+
+<script>
+import { api } from '@/api'
+
+export default {
+  props: {
+    resource: {
+      type: Object,
+      required: true
+    }
+  },
+  inject: ['parentFetchData'],
+  data () {
+    return {
+      loading: false,
+      vmsList: [],
+      selectedVm: null,
+      nicsList: [],
+      searchQuery: null,
+      selectedNic: null
+    }
+  },
+  mounted () {
+    this.fetchData()
+  },
+  methods: {
+    fetchData () {
+      this.loading = true
+      api('listVirtualMachines', {
+        page: 1,
+        pageSize: 500,
+        listAll: true,
+        networkid: this.resource.associatednetworkid,
+        account: this.resource.account,
+        domainid: this.resource.domainid,
+        keyword: this.searchQuery
+      }).then(response => {
+        this.vmsList = response.listvirtualmachinesresponse.virtualmachine
+        this.loading = false
+      }).catch(error => {
+        this.$notification.error({
+          message: `Error ${error.response.status}`,
+          description: error.response.data.errorresponse.errortext
+        })
+        this.loading = false
+      })
+    },
+    fetchNics () {
+      this.loading = true
+      this.nicsList = []
+      api('listNics', {
+        virtualmachineid: this.selectedVm.id,
+        networkid: this.resource.associatednetworkid
+      }).then(response => {
+        this.nicsList = response.listnicsresponse.nic
+
+        let secondaryIps = this.nicsList.map(item => item.secondaryip)
+
+        if (secondaryIps[0]) {
+          secondaryIps = secondaryIps[0]
+          this.nicsList = [...this.nicsList, ...secondaryIps]
+        }
+
+        this.selectedNic = this.nicsList[0]
+        this.loading = false
+      }).catch(error => {
+        this.$notification.error({
+          message: `Error ${error.response.status}`,
+          description: error.response.data.errorresponse.errortext
+        })
+        this.loading = false
+      })
+    },
+    handleSelectItem (vm) {
+      this.selectedVm = vm
+      this.fetchNics()
+    },
+    handleSubmit () {
+      this.loading = true
+      api('enableStaticNat', {
+        ipaddressid: this.resource.id,
+        virtualmachineid: this.selectedVm.id,
+        vmguestip: this.selectedNic.ipaddress
+      }).then(() => {
+        this.parentFetchData()
+        this.loading = false
+        this.handleClose()
+      }).catch(error => {
+        this.$notification.error({
+          message: `Error ${error.response.status}`,
+          description: error.response.data.errorresponse.errortext
+        })
+        this.loading = false
+        this.handleClose()
+      })
+    },
+    handleClose () {
+      this.$parent.$parent.close()
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+
+  .list {
+    max-height: 95vh;
+    width: 95vw;
+    overflow-y: scroll;
+    margin: -24px;
+
+    @media (min-width: 1000px) {
+      max-height: 70vh;
+      width: 60vw;
+    }
+
+    &__header,
+    &__footer {
+      padding-right: 20px;
+      padding-left: 20px;
+    }
+
+    &__footer {
+      display: flex;
+      justify-content: flex-end;
+
+      button {
+        &:not(:last-child) {
+          margin-right: 10px;
+        }
+      }
+    }
+
+    &__item {
+      padding-right: 20px;
+      padding-left: 20px;
+
+      &--selected {
+        background-color: #e6f7ff;
+      }
+
+    }
+
+    &__title {
+      font-weight: bold;
+    }
+
+    &__outer-container {
+      width: 100%;
+      display: flex;
+      flex-direction: column;
+    }
+
+    &__container {
+      display: flex;
+      flex-direction: column;
+      width: 100%;
+      cursor: pointer;
+
+      @media (min-width: 760px) {
+        flex-direction: row;
+        align-items: center;
+      }
+
+    }
+
+    &__row {
+      margin-bottom: 10px;
+
+      @media (min-width: 760px) {
+        margin-right: 20px;
+        margin-bottom: 0;
+      }
+    }
+
+    &__radio {
+
+      @media (min-width: 760px) {
+        margin-left: auto;
+      }
+
+    }
+
+  }
+
+  .nic-select {
+    margin-top: 10px;
+    margin-right: auto;
+    min-width: 150px;
+  }
+</style>