Forward broker requests to the given broker (#142)
*Motivation*
In #141 we added the support to handle forwarded request in the backend. This change modifies the frontend to attach `x-pulsar-cluster` for cluster related admin requests and `x-pulsar-broker` for broker related admin requests.
This change is based on #141
diff --git a/front-end/src/api/brokerStats.js b/front-end/src/api/brokerStats.js
index 1913b1e..40f3385 100644
--- a/front-end/src/api/brokerStats.js
+++ b/front-end/src/api/brokerStats.js
@@ -17,13 +17,20 @@
export function fetchBrokerStatsTopics(broker) {
return request({
- url: SPRING_BASE_URL_V2 + `/broker-stats/topics?broker=` + broker,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-pulsar-broker': broker
+ },
+ url: `/admin/v2/broker-stats/topics`,
method: 'get'
})
}
export function fetchBrokerStatsMetrics(broker) {
return request({
+ headers: {
+ 'x-pulsar-broker': broker
+ },
url: SPRING_BASE_URL_V2 + `/broker-stats/metrics?broker=` + broker,
method: 'get'
})
diff --git a/front-end/src/api/brokers.js b/front-end/src/api/brokers.js
index ddc26f1..cdac134 100644
--- a/front-end/src/api/brokers.js
+++ b/front-end/src/api/brokers.js
@@ -19,6 +19,9 @@
export function fetchBrokers(cluster) {
return request({
+ headers: {
+ 'x-pulsar-cluster': cluster
+ },
url: SPRING_BASE_URL_V2 + `/brokers/${cluster}`,
method: 'get'
})
@@ -26,41 +29,59 @@
export function fetchBrokersByDirectBroker(cluster) {
return request({
+ headers: {
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/brokers/${cluster}`,
method: 'get'
})
}
-export function fetchBrokersConfiguration() {
+export function fetchBrokersConfiguration(broker) {
return request({
+ headers: {
+ 'x-pulsar-broker': broker
+ },
url: BASE_URL_V2 + `/brokers/configuration`,
method: 'get'
})
}
-export function fetchBrokersRuntimeConfiguration() {
+export function fetchBrokersRuntimeConfiguration(broker) {
return request({
+ headers: {
+ 'x-pulsar-broker': broker
+ },
url: BASE_URL_V2 + `/brokers/configuration/runtime`,
method: 'get'
})
}
-export function fetchBrokersInternalConfiguration() {
+export function fetchBrokersInternalConfiguration(cluster) {
return request({
+ headers: {
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/brokers/internal-configuration`,
method: 'get'
})
}
-export function fetchBrokersDynamicConfiguration() {
+export function fetchBrokersDynamicConfiguration(cluster) {
return request({
+ headers: {
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/brokers/configuration/values`,
method: 'get'
})
}
-export function updateBrokersDynamicConfiguration(configName, configValue) {
+export function updateBrokersDynamicConfiguration(cluster, configName, configValue) {
return request({
+ headers: {
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/brokers/configuration/${configName}/${configValue}`,
method: 'post'
})
@@ -68,13 +89,19 @@
export function fetchBrokersOwnedNamespaces(cluster, broker) {
return request({
+ headers: {
+ 'x-pulsar-broker': broker
+ },
url: BASE_URL_V2 + `/brokers/${cluster}/${broker}/ownedNamespaces`,
method: 'get'
})
}
-export function fetchBrokersHealth() {
+export function fetchBrokersHealth(broker) {
return request({
+ headers: {
+ 'x-pulsar-broker': broker
+ },
url: BASE_URL_V2 + `/brokers/health`,
method: 'get'
})
diff --git a/front-end/src/api/clusters.js b/front-end/src/api/clusters.js
index ac6f59e..b25b78b 100644
--- a/front-end/src/api/clusters.js
+++ b/front-end/src/api/clusters.js
@@ -27,6 +27,7 @@
export function fetchClusterConfig(cluster) {
return request({
+ headers: { 'x-pulsar-cluster': cluster },
url: BASE_URL_V2 + `/clusters/${cluster}`,
method: 'get'
})
@@ -34,6 +35,7 @@
export function putCluster(cluster, data) {
return request({
+ headers: { 'x-pulsar-cluster': cluster },
url: BASE_URL_V2 + `/clusters/${cluster}`,
method: 'put',
data
@@ -42,6 +44,7 @@
export function updateCluster(cluster, data) {
return request({
+ headers: { 'x-pulsar-cluster': cluster },
url: BASE_URL_V2 + `/clusters/${cluster}`,
method: 'post',
data
@@ -50,6 +53,7 @@
export function deleteCluster(cluster) {
return request({
+ headers: { 'x-pulsar-cluster': cluster },
url: BASE_URL_V2 + `/clusters/${cluster}`,
method: 'delete'
})
@@ -57,7 +61,10 @@
export function updateClusterPeer(cluster, data) {
return request({
- headers: { 'Content-Type': 'application/json' },
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/clusters/${cluster}/peers`,
method: 'post',
data
@@ -66,6 +73,7 @@
export function getClusterPeer(cluster) {
return request({
+ headers: { 'x-pulsar-cluster': cluster },
url: BASE_URL_V2 + `/clusters/${cluster}/peers`,
method: 'get'
})
@@ -73,6 +81,7 @@
export function listClusterDomainName(cluster) {
return request({
+ headers: { 'x-pulsar-cluster': cluster },
url: BASE_URL_V2 + `/clusters/${cluster}/failureDomains`,
method: 'get'
})
@@ -80,6 +89,7 @@
export function getClusterDomainName(cluster, domainName) {
return request({
+ headers: { 'x-pulsar-cluster': cluster },
url: BASE_URL_V2 + `/clusters/${cluster}/failureDomains/${domainName}`,
method: 'get'
})
@@ -87,7 +97,10 @@
export function createClusterDomainName(cluster, domainName, data) {
return request({
- headers: { 'Content-Type': 'application/json' },
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/clusters/${cluster}/failureDomains/${domainName}`,
method: 'post',
data
@@ -96,7 +109,10 @@
export function updateClusterDomainName(cluster, domainName, data) {
return request({
- headers: { 'Content-Type': 'application/json' },
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/clusters/${cluster}/failureDomains/${domainName}`,
method: 'post',
data
@@ -105,7 +121,10 @@
export function deleteClusterDomainName(cluster, domainName) {
return request({
- headers: { 'Content-Type': 'application/json' },
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/clusters/${cluster}/failureDomains/${domainName}`,
method: 'post'
})
diff --git a/front-end/src/api/isolationPolicies.js b/front-end/src/api/isolationPolicies.js
index ca40afd..984601a 100644
--- a/front-end/src/api/isolationPolicies.js
+++ b/front-end/src/api/isolationPolicies.js
@@ -17,6 +17,9 @@
export function fetchIsolationPolicies(cluster) {
return request({
+ headers: {
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/clusters/${cluster}/namespaceIsolationPolicies`,
method: 'get'
})
@@ -24,7 +27,10 @@
export function updateIsolationPolicies(cluster, policyName, data) {
return request({
- headers: { 'Content-Type': 'application/json' },
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/clusters/${cluster}/namespaceIsolationPolicies/${policyName}`,
method: 'post',
data
@@ -33,7 +39,10 @@
export function deleteIsolationPolicies(cluster, policyName) {
return request({
- headers: { 'Content-Type': 'application/json' },
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-pulsar-cluster': cluster
+ },
url: BASE_URL_V2 + `/clusters/${cluster}/namespaceIsolationPolicies/${policyName}`,
method: 'delete'
})
diff --git a/front-end/src/api/namespaces.js b/front-end/src/api/namespaces.js
index 1d28d1c..a4bbffa 100644
--- a/front-end/src/api/namespaces.js
+++ b/front-end/src/api/namespaces.js
@@ -182,8 +182,20 @@
}
export function unloadBundle(tenantNamespace, bundle) {
+ return unloadBundleImpl('', '', tenantNamespace, bundle)
+}
+
+export function unloadBundleOnBroker(broker, tenantNamespace, bundle) {
+ return unloadBundleImpl('', broker, tenantNamespace, bundle)
+}
+
+export function unloadBundleImpl(cluster, broker, tenantNamespace, bundle) {
return request({
- headers: { 'Content-Type': 'application/json' },
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-pulsar-cluster': cluster,
+ 'x-pulsar-broker': broker
+ },
url: BASE_URL_V2 + `/namespaces/${tenantNamespace}/${bundle}/unload`,
method: 'put'
})
diff --git a/front-end/src/utils/http.js b/front-end/src/utils/http.js
new file mode 100644
index 0000000..f676394
--- /dev/null
+++ b/front-end/src/utils/http.js
@@ -0,0 +1,17 @@
+/*
+ * Licensed 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.
+ */
+
+export function isValidResponse(response) {
+ return response.status === 200 || response.status === 204
+}
diff --git a/front-end/src/utils/request.js b/front-end/src/utils/request.js
index efa76a2..df7d81f 100644
--- a/front-end/src/utils/request.js
+++ b/front-end/src/utils/request.js
@@ -44,13 +44,6 @@
// response interceptor
service.interceptors.response.use(
- // response => response,
- /**
- * 下面的注释为通过在response里,自定义code来标示请求状态
- * 当code返回如下情况则说明权限有问题,登出并返回到登录页
- * 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
- * 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
- */
response => {
// const res = response.data
if (response.status < 500 && response.status >= 200) {
@@ -60,7 +53,6 @@
}
},
error => {
- console.log('err' + error) // for debug
let message = ''
if (error.response.status === 404) {
if (error.response.data.length <= 0) {
@@ -76,11 +68,16 @@
}
} else if (error.response.status === 400) {
if (error.response.data.hasOwnProperty('message') && error.response.data.message.indexOf('no active environment') > 0) {
- router.replace({ path: '/environments' })
+ router.replace({
+ path: '/environments'
+ })
return
}
} else {
- message = error.response.data.reason
+ message = error.response.data
+ if (message.indexOf('Trying to subscribe with incompatible') >= 0) {
+ message = 'Incompatible schema detected while heartbeating'
+ }
}
Message({
message: message,
diff --git a/front-end/src/views/management/brokers/broker.vue b/front-end/src/views/management/brokers/broker.vue
index 053da9f..6f59657 100644
--- a/front-end/src/views/management/brokers/broker.vue
+++ b/front-end/src/views/management/brokers/broker.vue
@@ -94,11 +94,13 @@
import { fetchBrokerStatsMetrics, fetchBrokerStatsTopics } from '@/api/brokerStats'
import { fetchBrokersHealth, fetchBrokers } from '@/api/brokers'
import { fetchIsolationPolicies } from '@/api/isolationPolicies'
-import { unloadBundle } from '@/api/namespaces'
+import { unloadBundleOnBroker } from '@/api/namespaces'
import { fetchBrokersRuntimeConfiguration } from '@/api/brokers'
import jsonEditor from '@/components/JsonEditor'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
import MdInput from '@/components/MDinput'
+import { isValidResponse } from '@/utils/http'
+
const defaultForm = {
cluster: '',
broker: ''
@@ -140,6 +142,16 @@
fetchBrokerStatsTopics(this.postForm.broker).then(response => {
if (!response.data) return
this.brokerStatsTopic = response.data
+ if ((typeof this.brokerStatsTopic) === 'string') {
+ // failed to fetch broker stats
+ this.brokerStatsTopic = {}
+ this.$notify({
+ title: 'error',
+ message: 'Failed to fetch broker stats from broker ' + this.postForm.broker,
+ type: 'error',
+ duration: 3000
+ })
+ }
for (var tenantNamespace in this.brokerStatsTopic) {
var tn = tenantNamespace.split('/')
for (var bundle in this.brokerStatsTopic[tenantNamespace]) {
@@ -233,18 +245,27 @@
})
},
handleUnloadBundle(row) {
- unloadBundle(row.tenant + '/' + row.namespace, row.bundle).then(response => {
- this.$notify({
- title: 'success',
- message: 'Unload bundle success',
- type: 'success',
- duration: 3000
- })
+ unloadBundleOnBroker(this.postForm.broker, row.tenant + '/' + row.namespace, row.bundle).then(response => {
+ if (isValidResponse(response)) {
+ this.$notify({
+ title: 'success',
+ message: 'Successfully unload namespace bundle from the broker',
+ type: 'success',
+ duration: 3000
+ })
+ } else {
+ this.$notify({
+ title: 'error',
+ message: 'Failed to unload namespace bundle from the broker : ' + response.data,
+ type: 'error',
+ duration: 3000
+ })
+ }
})
},
handleHeartBeat() {
- fetchBrokersHealth().then(response => {
- if (response.data === 'ok') {
+ fetchBrokersHealth(this.postForm.broker).then(response => {
+ if (isValidResponse(response)) {
this.$notify({
title: 'success',
message: 'Health Check success',
@@ -254,7 +275,7 @@
} else {
this.$notify({
title: 'error',
- message: 'Health Check failed',
+ message: 'Health Check failed: \n' + response.data,
type: 'error',
duration: 3000
})
@@ -262,7 +283,7 @@
})
},
handleRuntimeConfig() {
- fetchBrokersRuntimeConfiguration().then(response => {
+ fetchBrokersRuntimeConfiguration(this.postForm.broker).then(response => {
this.dialogFormVisible = true
this.jsonValue = response.data
})