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 2019/12/06 19:23:06 UTC
[cloudstack-primate] branch master updated: infra: custom SSL cert
setup form (#54)
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 aaf212f infra: custom SSL cert setup form (#54)
aaf212f is described below
commit aaf212f25337eff1eeef3f876bb37218eea2123f
Author: Ritchie Vincent <rf...@gmail.com>
AuthorDate: Fri Dec 6 19:22:53 2019 +0000
infra: custom SSL cert setup form (#54)
This fixes #33
Signed-off-by: Rohit Yadav <ro...@shapeblue.com>
---
src/config/router.js | 8 +-
src/views/AutogenView.vue | 9 +-
src/views/infra/InfraSummary.vue | 299 ++++++++++++++++++++++++++++++++++-----
3 files changed, 269 insertions(+), 47 deletions(-)
diff --git a/src/config/router.js b/src/config/router.js
index 28e61b8..51a61e9 100644
--- a/src/config/router.js
+++ b/src/config/router.js
@@ -49,13 +49,13 @@ export function generateRouterMap (section) {
var route = {
name: child.name,
path: '/' + child.name,
+ hidden: child.hidden,
meta: {
title: child.title,
name: child.name,
keepAlive: true,
icon: child.icon,
docHelp: child.docHelp,
- hidden: child.hidden,
permission: child.permission,
resourceType: child.resourceType,
params: child.params ? child.params : {},
@@ -69,13 +69,13 @@ export function generateRouterMap (section) {
children: [
{
path: '/' + child.name + '/:id',
+ hidden: child.hidden,
meta: {
title: child.title,
name: child.name,
keepAlive: true,
icon: child.icon,
docHelp: child.docHelp,
- hidden: child.hidden,
permission: child.permission,
resourceType: child.resourceType,
params: child.params ? child.params : {},
@@ -96,6 +96,7 @@ export function generateRouterMap (section) {
map.children.push({
name: action.api,
icon: child.icon,
+ hidden: true,
path: '/action/' + action.api,
meta: {
title: child.title,
@@ -103,8 +104,7 @@ export function generateRouterMap (section) {
keepAlive: true,
permission: [action.api]
},
- component: action.component,
- hidden: true
+ component: action.component
})
})
}
diff --git a/src/views/AutogenView.vue b/src/views/AutogenView.vue
index 6ecb3e7..4e07402 100644
--- a/src/views/AutogenView.vue
+++ b/src/views/AutogenView.vue
@@ -17,7 +17,7 @@
<template>
<div>
- <a-card class="mobile-breadcrumb">
+ <a-card class="breadcrumb-card">
<a-row>
<a-col :span="14">
<breadcrumb style="padding-top: 6px" />
@@ -402,7 +402,8 @@ export default {
// handle error
this.$notification.error({
message: 'Request Failed',
- description: error.response.headers['x-description']
+ description: error.response.headers['x-description'],
+ duration: 0
})
if (error.response.status === 431) {
this.$router.push({ path: '/exception/404' })
@@ -514,7 +515,7 @@ export default {
this.fetchData()
} else if (result.jobstatus === 2) {
this.fetchData()
- } else {
+ } else if (result.jobstatus === 0) {
this.$message
.loading(this.$t(action.label) + ' in progress for ' + this.resource.name, 3)
.then(() => this.pollActionCompletion(jobId, action))
@@ -636,7 +637,7 @@ export default {
<style scoped>
-.mobile-breadcrumb {
+.breadcrumb-card {
margin-left: -24px;
margin-right: -24px;
margin-top: -16px;
diff --git a/src/views/infra/InfraSummary.vue b/src/views/infra/InfraSummary.vue
index f2a057d..d2af424 100644
--- a/src/views/infra/InfraSummary.vue
+++ b/src/views/infra/InfraSummary.vue
@@ -17,36 +17,125 @@
<template>
<a-row :gutter="24">
- <a-col :md="18">
- <a-card>
- <breadcrumb />
- </a-card>
- </a-col>
- <a-col
- :md="6" >
- <a-card>
- <a-button
- style="margin-left: 10px; float: right"
- @click="fetchData()"
- icon="reload"
- :loading="loading"
- type="primary">
- {{ $t('Refresh') }}
- </a-button>
- <a-button
- style="margin-left: 10px; float: right"
- @click="sslFormVisible = true"
- icon="safety-certificate">
- {{ $t('SSL Certificate') }}
- </a-button>
- <a-modal
- :title="$t('SSL Certificate')"
- v-model="sslFormVisible"
- @ok="handle">
- <p>Some contents...</p>
- <p>Some contents...</p>
- <p>Some contents...</p>
- </a-modal>
+ <a-col :md="24">
+ <a-card class="breadcrumb-card">
+ <a-col :md="14">
+ <breadcrumb style="padding-top: 6px" />
+ </a-col>
+ <a-col :md="10">
+ <a-button
+ style="margin-left: 10px; float: right"
+ @click="fetchData()"
+ icon="reload"
+ :loading="loading"
+ type="primary">
+ {{ $t('Refresh') }}
+ </a-button>
+ <a-button
+ style="margin-left: 10px; float: right"
+ @click="sslFormVisible = true"
+ icon="safety-certificate">
+ {{ $t('SSL Certificate') }}
+ </a-button>
+ <a-modal
+ :title="$t('SSL Certificate')"
+ :visible="sslFormVisible"
+ :footer="null"
+ @cancel="sslModalClose">
+ <p>
+ Please submit a new X.509 compliant SSL certificate chain to be updated to each console proxy and secondary storage virtual instance:
+ </p>
+
+ <a-form @submit.prevent="handleSslFormSubmit" ref="sslForm" :form="form">
+ <a-form-item label="Root certificate" :required="true">
+ <a-textarea
+ id="rootCert"
+ rows="2"
+ placeholder="Root certificate"
+ :autoFocus="true"
+ name="rootCert"
+ v-decorator="[
+ 'root',
+ {rules: [{ required: true, message: 'Required' }], validateTrigger:'change'}
+ ]"
+ ></a-textarea>
+ </a-form-item>
+
+ <transition-group name="fadeInUp" tag="div">
+ <a-form-item
+ v-for="(item, index) in intermediateCertificates"
+ :key="`key-${index}`"
+ class="intermediate-certificate"
+ :label="`Intermediate certificate ${index + 1}`">
+ <a-textarea
+ :id="`intermediateCert${index}`"
+ rows="2"
+ :placeholder="`Intermediate certificate ${index + 1}`"
+ :name="`intermediateCert${index}`"
+ v-decorator="[
+ `intermediate${index + 1}`,
+ {validateTrigger:'change'}
+ ]"
+ ></a-textarea>
+ </a-form-item>
+ </transition-group>
+
+ <a-form-item>
+ <a-button @click="addIntermediateCert">
+ <a-icon type="plus-circle" />
+ Add intermediate certificate
+ </a-button>
+ </a-form-item>
+
+ <a-form-item label="Server certificate" :required="true">
+ <a-textarea
+ id="serverCert"
+ rows="2"
+ placeholder="Server certificate"
+ name="serverCert"
+ v-decorator="[
+ 'server',
+ {rules: [{ required: true, message: 'Required' }], validateTrigger:'change'}
+ ]"
+ ></a-textarea>
+ </a-form-item>
+
+ <a-form-item label="PKCS#8 Private Key" :required="true">
+ <a-textarea
+ id="pkcsKey"
+ rows="2"
+ placeholder="PKCS#8 Private Key"
+ name="pkcsKey"
+ v-decorator="[
+ 'pkcs',
+ {rules: [{ required: true, message: 'Required' }], validateTrigger:'change'}
+ ]"
+ ></a-textarea>
+ </a-form-item>
+
+ <a-form-item label="DNS Domain Suffix (i.e., xyz.com)" :required="true">
+ <a-input
+ id="dnsSuffix"
+ placeholder="DNS Domain Suffix (i.e., xyz.com)"
+ name="dnsSuffix"
+ v-decorator="[
+ 'dns',
+ {rules: [{ required: true, message: 'Required' }], validateTrigger:'change'}
+ ]"
+ ></a-input>
+ </a-form-item>
+
+ <a-form-item class="controls">
+ <a-button @click="this.sslModalClose" type="danger" class="close-button">
+ Cancel
+ </a-button>
+ <a-button type="primary" htmlType="submit" :loading="sslFormSubmitting">
+ Submit
+ </a-button>
+ </a-form-item>
+ </a-form>
+ </a-modal>
+ </a-col>
</a-card>
</a-col>
<a-col
@@ -86,9 +175,15 @@ export default {
routes: {},
sections: ['zones', 'pods', 'clusters', 'hosts', 'storagepools', 'imagestores', 'systemvms', 'routers', 'cpusockets', 'managementservers', 'alerts'],
sslFormVisible: false,
- stats: {}
+ stats: {},
+ intermediateCertificates: [],
+ sslFormSubmitting: false,
+ maxCerts: 0
}
},
+ beforeCreate () {
+ this.form = this.$form.createForm(this)
+ },
mounted () {
this.fetchData()
},
@@ -115,17 +210,143 @@ export default {
this.loading = false
})
},
- handleSslForm (e) {
- console.log(e)
+
+ resetSslFormData () {
+ this.form.resetFields()
+ this.intermediateCertificates = []
+ this.sslFormSubmitting = false
+ this.sslFormVisible = false
+ },
+
+ sslModalClose () {
+ this.resetSslFormData()
+ },
+
+ addIntermediateCert () {
+ this.intermediateCertificates.push('')
+ },
+
+ pollActionCompletion (jobId, count) {
+ api('queryAsyncJobResult', { jobid: jobId }).then(json => {
+ const result = json.queryasyncjobresultresponse
+ if (result.jobstatus === 1 && this.maxCerts === count) {
+ console.log(result)
+ console.log(this.maxCerts)
+ console.log(count)
+ this.$message.success('Certificate Uploaded: ' + result.jobresult.customcertificate.message)
+ this.$notification.success({
+ message: 'Certificate Uploaded',
+ description: result.jobresult.customcertificate.message || 'Certificate successfully uploaded'
+ })
+ } else if (result.jobstatus === 2) {
+ this.$notification.error({
+ message: 'Certificate Upload Failed',
+ description: result.jobresult.errortext || 'Failed to update SSL Certificate. Failed to pass certificate validation check',
+ duration: 0
+ })
+ } else if (result.jobstatus === 0) {
+ this.$message
+ .loading('Certificate upload in progress: ' + count, 2)
+ .then(() => this.pollActionCompletion(jobId, count))
+ }
+ }).catch(e => {
+ console.log('Error encountered while fetching async job result' + e)
+ })
+ },
+
+ handleSslFormSubmit () {
+ this.sslFormSubmitting = true
+
+ this.form.validateFields(errors => {
+ if (errors) {
+ this.sslFormSubmitting = false
+ return
+ }
+
+ const formValues = this.form.getFieldsValue()
+
+ this.maxCerts = 2 + Object.keys(formValues).length
+ let count = 1
+ let data = {
+ id: count,
+ certificate: formValues.root,
+ domainsuffix: formValues.dns,
+ name: 'root'
+ }
+ api('uploadCustomCertificate', {}, 'POST', data).then(response => {
+ this.pollActionCompletion(response.uploadcustomcertificateresponse.jobid, count)
+ }).then(() => {
+ this.sslModalClose()
+ })
+
+ Object.keys(formValues).forEach(key => {
+ if (key.includes('intermediate')) {
+ count = count + 1
+ const data = {
+ id: count,
+ certificate: formValues[key],
+ domainsuffix: formValues.dns,
+ name: key
+ }
+ api('uploadCustomCertificate', {}, 'POST', data).then(response => {
+ this.pollActionCompletion(response.uploadcustomcertificateresponse.jobid, count)
+ }).then(() => {
+ this.sslModalClose()
+ })
+ }
+ })
+
+ count = count <= 2 ? 3 : count + 1
+ data = {
+ id: count,
+ certificate: formValues.server,
+ domainsuffix: formValues.dns,
+ privatekey: formValues.pkcs
+ }
+ api('uploadCustomCertificate', {}, 'POST', data).then(response => {
+ this.pollActionCompletion(response.uploadcustomcertificateresponse.jobid, count)
+ }).then(() => {
+ this.sslModalClose()
+ })
+ })
}
}
}
</script>
-<style lang="less" scoped>
-.chart-card-inner {
- text-align: center;
- white-space: nowrap;
- overflow: hidden;
-}
+<style lang="scss" scoped>
+
+ .breadcrumb-card {
+ margin-left: -36px;
+ margin-right: -36px;
+ margin-top: -16px;
+ margin-bottom: 12px;
+ }
+
+ .chart-card-inner {
+ text-align: center;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+ .intermediate-certificate {
+ opacity: 1;
+ transform: none;
+ transition: opacity 0.2s ease 0s, transform 0.5s ease;
+ will-change: transform;
+ }
+ .intermediate-certificate.fadeInUp-enter-active {
+ opacity: 0;
+ transform: translateY(10px);
+ transition: none;
+ }
+ .controls {
+ display: flex;
+ justify-content: flex-end;
+ }
+ .close-button {
+ margin-right: 20px;
+ }
+ .ant-form-item {
+ margin-bottom: 10px;
+ }
</style>