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

sureshanaparti pushed a commit to branch 4.16
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.16 by this push:
     new 0f926b5  UI: Add s3 provider option to create secondary storage (#5726)
0f926b5 is described below

commit 0f926b5d68975e93f924e41ae6f4b137868f58c1
Author: Hoang Nguyen <[email protected]>
AuthorDate: Mon Jan 10 20:31:53 2022 +0700

    UI: Add s3 provider option to create secondary storage (#5726)
    
    * add s3 provider option to create secondary storage
    
    * fixes label name
    
    * add storagepolicy for swift provider
---
 ui/public/locales/en.json                          |   3 +
 ui/src/views/infra/AddSecondaryStorage.vue         | 178 +++++++++++++++++++--
 ui/src/views/infra/zone/StaticInputsForm.vue       |  24 ++-
 ui/src/views/infra/zone/ZoneWizardAddResources.vue |  33 ++--
 ui/src/views/infra/zone/ZoneWizardLaunchZone.vue   |   6 +
 5 files changed, 212 insertions(+), 32 deletions(-)

diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 9dbbd85..ad01734 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -2949,6 +2949,9 @@
 "message.error.retrieve.kubeconfig": "Unable to retrieve Kubernetes cluster 
config",
 "message.error.s3nfs.path": "Please enter S3 NFS Path",
 "message.error.s3nfs.server": "Please enter S3 NFS Server",
+"message.error.swift.account":  "Please enter account",
+"message.error.swift.key": "Please enter key",
+"message.error.swift.username":  "Please enter username",
 "message.error.save.setting": "There was an error saving this setting.",
 "message.error.sbdomain": "Please enter SMB Domain",
 "message.error.sbdomain.password": "Please enter SMB Domain Password",
diff --git a/ui/src/views/infra/AddSecondaryStorage.vue 
b/ui/src/views/infra/AddSecondaryStorage.vue
index 0d34e6f..f7b6203 100644
--- a/ui/src/views/infra/AddSecondaryStorage.vue
+++ b/ui/src/views/infra/AddSecondaryStorage.vue
@@ -42,7 +42,7 @@
             >{{ prov }}</a-select-option>
           </a-select>
         </a-form-item>
-        <div v-if="provider !== 'Swift'">
+        <div v-if="!['Swift', 'S3'].includes(provider)">
           <a-form-item :label="$t('label.zone')">
             <a-select
               v-decorator="[
@@ -163,6 +163,91 @@
             />
           </a-form-item>
         </div>
+        <div v-if="provider === 'S3'">
+          <a-form-item :label="$t('label.zone')">
+            <a-select
+              v-decorator="[
+                'zone',
+                {
+                  initialValue: this.zoneSelected,
+                  rules: [{ required: true, message: 
`${$t('label.required')}`}]
+                }]"
+              @change="val => { zoneSelected = val }"
+              showSearch
+              optionFilterProp="children"
+              :filterOption="(input, option) => {
+                return 
option.componentOptions.propsData.label.toLowerCase().indexOf(input.toLowerCase())
 >= 0
+              }" >
+              <a-select-option
+                :value="zone.id"
+                v-for="(zone) in zones"
+                :key="zone.id"
+                :label="zone.name">
+                <span>
+                  <resource-icon v-if="zone.icon" 
:image="zone.icon.base64image" size="1x" style="margin-right: 5px"/>
+                  <a-icon v-else type="global" style="margin-right: 5px" />
+                  {{ zone.name }}
+                </span>
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+          <a-form-item :label="$t('label.s3.access.key')">
+            <a-input
+              v-decorator="[
+                'secondaryStorageAccessKey',
+                {
+                  rules: [{ required: true, message: `${$t('label.required')}` 
}]
+                }]"/>
+          </a-form-item>
+          <a-form-item :label="$t('label.s3.secret.key')">
+            <a-input
+              v-decorator="[
+                'secondaryStorageSecretKey',
+                {
+                  rules: [{ required: true, message: `${$t('label.required')}` 
}]
+                }]"/>
+          </a-form-item>
+          <a-form-item :label="$t('label.s3.bucket')">
+            <a-input
+              v-decorator="[
+                'secondaryStorageBucket',
+                {
+                  rules: [{ required: true, message: `${$t('label.required')}` 
}]
+                }]"/>
+          </a-form-item>
+          <a-form-item :label="$t('label.s3.endpoint')">
+            <a-input v-decorator="['secondaryStorageEndpoint']"/>
+          </a-form-item>
+          <a-form-item :label="$t('label.s3.use.https')">
+            <a-switch v-decorator="['secondaryStorageHttps', { initialValue: 
true }]" :default-checked="true" />
+          </a-form-item>
+          <a-form-item :label="$t('label.s3.connection.timeout')">
+            <a-input v-decorator="['secondaryStorageConnectionTimeout']"/>
+          </a-form-item>
+          <a-form-item :label="$t('label.s3.max.error.retry')">
+            <a-input v-decorator="['secondaryStorageMaxError']"/>
+          </a-form-item>
+          <a-form-item :label="$t('label.s3.socket.timeout')">
+            <a-input v-decorator="['secondaryStorageSocketTimeout']"/>
+          </a-form-item>
+          <a-form-item 
:label="$t('label.create.nfs.secondary.staging.storage')">
+            <a-switch v-decorator="['secondaryStorageNFSStaging']" 
@change="val => secondaryStorageNFSStaging = val" />
+          </a-form-item>
+        </div>
+        <div v-if="secondaryStorageNFSStaging">
+          <a-form-item :label="$t('label.s3.nfs.server')">
+            <a-input
+              v-decorator="['secondaryStorageNFSServer', {
+                rules: [{ required: true, message: `${$t('label.required')}` }]
+              }]"/>
+          </a-form-item>
+          <a-form-item :label="$t('label.s3.nfs.path')">
+            <a-input
+              v-decorator="['secondaryStorageNFSPath', {
+                rules: [{ required: true, message: `${$t('label.required')}` }]
+              }]"/>
+          </a-form-item>
+        </div>
         <div :span="24" class="action-button">
           <a-button @click="closeModal">{{ $t('label.cancel') }}</a-button>
           <a-button type="primary" ref="submit" @click="handleSubmit">{{ 
$t('label.ok') }}</a-button>
@@ -189,11 +274,12 @@ export default {
   inject: ['parentFetchData'],
   data () {
     return {
-      providers: ['NFS', 'SMB/CIFS', 'Swift'],
+      providers: ['NFS', 'SMB/CIFS', 'S3', 'Swift'],
       provider: '',
       zones: [],
       zoneSelected: '',
-      loading: false
+      loading: false,
+      secondaryStorageNFSStaging: false
     }
   },
   beforeCreate () {
@@ -245,7 +331,7 @@ export default {
     handleSubmit (e) {
       e.preventDefault()
       if (this.loading) return
-      this.form.validateFieldsAndScroll((err, values) => {
+      this.form.validateFieldsAndScroll(async (err, values) => {
         if (err) {
           return
         }
@@ -283,26 +369,100 @@ export default {
             data['details[' + index.toString() + '].key'] = key
             data['details[' + index.toString() + '].value'] = swiftParams[key]
           })
+        } else if (provider === 'S3') {
+          let detailIdx = 0
+          const s3Params = {
+            accesskey: values.secondaryStorageAccessKey,
+            secretkey: values.secondaryStorageSecretKey,
+            bucket: values.secondaryStorageBucket,
+            usehttps: values.secondaryStorageHttps ? 
values.secondaryStorageHttps : false
+          }
+          Object.keys(s3Params).forEach((key, index) => {
+            data['details[' + index.toString() + '].key'] = key
+            data['details[' + index.toString() + '].value'] = s3Params[key]
+            detailIdx = index
+          })
+
+          if (values.secondaryStorageEndpoint && 
values.secondaryStorageEndpoint.length > 0) {
+            detailIdx++
+            data['details[' + detailIdx.toString() + '].key'] = 'endpoint'
+            data['details[' + detailIdx.toString() + '].value'] = 
values.secondaryStorageEndpoint
+          }
+
+          if (values.secondaryStorageConnectionTimeout && 
values.secondaryStorageConnectionTimeout.length > 0) {
+            detailIdx++
+            data['details[' + detailIdx.toString() + '].key'] = 
'connectiontimeout'
+            data['details[' + detailIdx.toString() + '].value'] = 
values.secondaryStorageConnectionTimeout
+          }
+
+          if (values.secondaryStorageMaxError && 
values.secondaryStorageMaxError.length > 0) {
+            detailIdx++
+            data['details[' + detailIdx.toString() + '].key'] = 'maxerrorretry'
+            data['details[' + detailIdx.toString() + '].value'] = 
values.secondaryStorageMaxError
+          }
+
+          if (values.secondaryStorageSocketTimeout && 
values.secondaryStorageSocketTimeout.length > 0) {
+            detailIdx++
+            data['details[' + detailIdx.toString() + '].key'] = 'sockettimeout'
+            data['details[' + detailIdx.toString() + '].value'] = 
values.secondaryStorageSocketTimeout
+          }
         }
 
-        data.url = url
+        if (provider !== 'S3') {
+          data.url = url
+        }
         data.provider = provider
-        if (values.zone && provider !== 'Swift') {
+        if (values.zone && !['Swift', 'S3'].includes(provider)) {
           data.zoneid = values.zone
         }
 
+        const nfsParams = {}
+        if (values.secondaryStorageNFSStaging) {
+          const nfsServer = values.secondaryStorageNFSServer
+          const path = values.secondaryStorageNFSPath
+          const nfsUrl = this.nfsURL(nfsServer, path)
+
+          nfsParams.provider = 'nfs'
+          nfsParams.zoneid = values.zone
+          nfsParams.url = nfsUrl
+        }
+
         this.loading = true
-        api('addImageStore', data).then(json => {
+
+        try {
+          await this.addImageStore(data)
+
+          if (values.secondaryStorageNFSStaging) {
+            await this.createSecondaryStagingStore(nfsParams)
+          }
           this.$notification.success({
             message: this.$t('label.add.secondary.storage'),
             description: this.$t('label.add.secondary.storage')
           })
+          this.loading = false
           this.closeModal()
           this.parentFetchData()
-        }).catch(error => {
+        } catch (error) {
           this.$notifyError(error)
-        }).finally(() => {
           this.loading = false
+        }
+      })
+    },
+    addImageStore (params) {
+      return new Promise((resolve, reject) => {
+        api('addImageStore', params).then(json => {
+          resolve()
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+    createSecondaryStagingStore (params) {
+      return new Promise((resolve, reject) => {
+        api('createSecondaryStagingStore', params).then(json => {
+          resolve()
+        }).catch(error => {
+          reject(error)
         })
       })
     }
diff --git a/ui/src/views/infra/zone/StaticInputsForm.vue 
b/ui/src/views/infra/zone/StaticInputsForm.vue
index 97590a3..dc93c09 100644
--- a/ui/src/views/infra/zone/StaticInputsForm.vue
+++ b/ui/src/views/infra/zone/StaticInputsForm.vue
@@ -216,21 +216,19 @@ export default {
       if (!conditions || Object.keys(conditions).length === 0) {
         return true
       }
-      let isShow = false
+      let isShow = true
       Object.keys(conditions).forEach(key => {
-        const condition = conditions[key]
-        const fieldVal = this.form.getFieldValue(key)
-          ? this.form.getFieldValue(key)
-          : (this.prefillContent[key] ? this.prefillContent[key].value : null)
-        if (Array.isArray(condition) && condition.includes(fieldVal)) {
-          isShow = true
-          return false
-        } else if (!Array.isArray(condition) && fieldVal === condition) {
-          isShow = true
-          return false
+        if (isShow) {
+          const condition = conditions[key]
+          const fieldVal = this.form.getFieldValue(key)
+            ? this.form.getFieldValue(key)
+            : (this.prefillContent[key] ? this.prefillContent[key].value : 
null)
+          if (Array.isArray(condition) && !condition.includes(fieldVal)) {
+            isShow = false
+          } else if (!Array.isArray(condition) && fieldVal !== condition) {
+            isShow = false
+          }
         }
-
-        return true
       })
 
       return isShow
diff --git a/ui/src/views/infra/zone/ZoneWizardAddResources.vue 
b/ui/src/views/infra/zone/ZoneWizardAddResources.vue
index 5804676..ee16e26 100644
--- a/ui/src/views/infra/zone/ZoneWizardAddResources.vue
+++ b/ui/src/views/infra/zone/ZoneWizardAddResources.vue
@@ -570,7 +570,7 @@ export default {
           }
         },
         {
-          title: 'label.s3.access_key',
+          title: 'label.s3.access.key',
           key: 'secondaryStorageAccessKey',
           required: true,
           placeHolder: 'message.error.access.key',
@@ -579,7 +579,7 @@ export default {
           }
         },
         {
-          title: 'label.s3.secret_key',
+          title: 'label.s3.secret.key',
           key: 'secondaryStorageSecretKey',
           required: true,
           placeHolder: 'message.error.secret.key',
@@ -605,7 +605,7 @@ export default {
           }
         },
         {
-          title: 'label.s3.use_https',
+          title: 'label.s3.use.https',
           key: 'secondaryStorageHttps',
           required: false,
           switch: true,
@@ -615,7 +615,7 @@ export default {
           }
         },
         {
-          title: 'label.s3.connection_timeoutt',
+          title: 'label.s3.connection.timeout',
           key: 'secondaryStorageConnectionTimeout',
           required: false,
           display: {
@@ -623,7 +623,7 @@ export default {
           }
         },
         {
-          title: 'label.s3.max_error_retry',
+          title: 'label.s3.max.error.retry',
           key: 'secondaryStorageMaxError',
           required: false,
           display: {
@@ -631,7 +631,7 @@ export default {
           }
         },
         {
-          title: 'label.s3.socket_timeout',
+          title: 'label.s3.socket.timeout',
           key: 'secondaryStorageSocketTimeout',
           required: false,
           display: {
@@ -653,7 +653,8 @@ export default {
           required: true,
           placeHolder: 'message.error.s3nfs.server',
           display: {
-            secondaryStorageProvider: ['S3']
+            secondaryStorageProvider: ['S3'],
+            secondaryStorageNFSStaging: true
           }
         },
         {
@@ -662,7 +663,8 @@ export default {
           required: true,
           placeHolder: 'message.error.s3nfs.path',
           display: {
-            secondaryStorageProvider: ['S3']
+            secondaryStorageProvider: ['S3'],
+            secondaryStorageNFSStaging: true
           }
         },
         {
@@ -677,7 +679,8 @@ export default {
         {
           title: 'label.account',
           key: 'secondaryStorageAccount',
-          required: false,
+          required: true,
+          placeHolder: 'message.error.swift.account',
           display: {
             secondaryStorageProvider: ['Swift']
           }
@@ -685,7 +688,8 @@ export default {
         {
           title: 'label.username',
           key: 'secondaryStorageUsername',
-          required: false,
+          required: true,
+          placeHolder: 'message.error.swift.username',
           display: {
             secondaryStorageProvider: ['Swift']
           }
@@ -693,6 +697,15 @@ export default {
         {
           title: 'label.key',
           key: 'secondaryStorageKey',
+          required: true,
+          placeHolder: 'message.error.swift.key',
+          display: {
+            secondaryStorageProvider: ['Swift']
+          }
+        },
+        {
+          title: 'label.storagepolicy',
+          key: 'secondaryStoragePolicy',
           required: false,
           display: {
             secondaryStorageProvider: ['Swift']
diff --git a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue 
b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue
index eb18181..d22cd35 100644
--- a/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue
+++ b/ui/src/views/infra/zone/ZoneWizardLaunchZone.vue
@@ -1471,6 +1471,12 @@ export default {
           params['details[' + index.toString() + '].value'] = 
this.prefillContent.secondaryStorageKey.value
           index++
         }
+        if (this.prefillContent.secondaryStoragePolicy &&
+          this.prefillContent.secondaryStoragePolicy.value.length > 0) {
+          params['details[' + index.toString() + '].key'] = 'storagepolicy'
+          params['details[' + index.toString() + '].value'] = 
this.prefillContent.secondaryStoragePolicy.value
+          index++
+        }
       }
 
       try {

Reply via email to