feat: update edit health monitor

1. refactor listener detail and actions code to optimize requests
2. fix remove health monitor
3. hide admin_state_up form item when disable health monitor in the lb step create page
4. support updating admin_state_up when editing health monitor
5. support admin_state_up info in the health monitor card in the lisenter detail page

Change-Id: Id1a9c32ddae09b1ae3dfb613bd7468a372aa5478
This commit is contained in:
zhangjingwei 2023-11-15 10:47:27 +08:00
parent 73653da708
commit b2801a7913
14 changed files with 157 additions and 118 deletions

View File

@ -0,0 +1,10 @@
---
features:
- |
Update editing health monitor for load balancer:
* Fix remove health monitor.
* Support editing admin_state_up when editing health monitor.
* Support display admin_state_up info in the heath monitor info card in the listener detail page.

View File

@ -998,7 +998,6 @@
"Fingerprint": "Fingerprint", "Fingerprint": "Fingerprint",
"Finish Resize": "Finish Resize", "Finish Resize": "Finish Resize",
"Finland": "Finland", "Finland": "Finland",
"First time edit automatically creates health monitor When pool does not have a health monitor": "First time edit automatically creates health monitor When pool does not have a health monitor",
"Fixed IP": "Fixed IP", "Fixed IP": "Fixed IP",
"Fixed IP Address": "Fixed IP Address", "Fixed IP Address": "Fixed IP Address",
"Fixed IPs": "Fixed IPs", "Fixed IPs": "Fixed IPs",

View File

@ -998,7 +998,6 @@
"Fingerprint": "", "Fingerprint": "",
"Finish Resize": "Resize 완료", "Finish Resize": "Resize 완료",
"Finland": "", "Finland": "",
"First time edit automatically creates health monitor When pool does not have a health monitor": "Pool에 Heath monitor가 없을 때 처음 편집하면 Heath monitor가 자동으로 생성됩니다.",
"Fixed IP": "고정 IP", "Fixed IP": "고정 IP",
"Fixed IP Address": "고정 IP 주소", "Fixed IP Address": "고정 IP 주소",
"Fixed IPs": "고정 IP", "Fixed IPs": "고정 IP",

View File

@ -998,7 +998,6 @@
"Fingerprint": "指纹", "Fingerprint": "指纹",
"Finish Resize": "完成调整", "Finish Resize": "完成调整",
"Finland": "芬兰", "Finland": "芬兰",
"First time edit automatically creates health monitor When pool does not have a health monitor": "资源池无健康检查器时,首次编辑会自动创建健康检查器",
"Fixed IP": "内网IP", "Fixed IP": "内网IP",
"Fixed IP Address": "内网IP地址", "Fixed IP Address": "内网IP地址",
"Fixed IPs": "内网IP", "Fixed IPs": "内网IP",

View File

@ -40,7 +40,8 @@ export class CreatePool extends ModalAction {
static policy = 'os_load-balancer_api:pool:post'; static policy = 'os_load-balancer_api:pool:post';
static allowed = async (item, containerProps) => { static allowed = async (item, containerProps) => {
let { detail: lbDetail } = containerProps || {}; const { detail } = containerProps || {};
let lbDetail = item.loadBalancer || detail;
if (!lbDetail) { if (!lbDetail) {
lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]); lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]);
} }

View File

@ -40,7 +40,8 @@ export default class DeleteAction extends ConfirmAction {
policy = 'os_load-balancer_api:listener:delete'; policy = 'os_load-balancer_api:listener:delete';
allowed = async (item, containerProps) => { allowed = async (item, containerProps) => {
let { detail: lbDetail } = containerProps || {}; const { detail } = containerProps || {};
let lbDetail = item.loadBalancer || detail;
if (!lbDetail) { if (!lbDetail) {
lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]); lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]);
} }

View File

@ -40,7 +40,8 @@ export default class DeletePoolAction extends ConfirmAction {
policy = 'os_load-balancer_api:pool:delete'; policy = 'os_load-balancer_api:pool:delete';
allowedCheckFunc = async (item, containerProps) => { allowedCheckFunc = async (item, containerProps) => {
let { detail: lbDetail } = containerProps || {}; const { detail } = containerProps || {};
let lbDetail = item.loadBalancer || detail;
if (!lbDetail) { if (!lbDetail) {
lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]); lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]);
} }

View File

@ -31,7 +31,8 @@ export class Edit extends Base {
static policy = 'os_load-balancer_api:listener:put'; static policy = 'os_load-balancer_api:listener:put';
static allowed = async (item, containerProps) => { static allowed = async (item, containerProps) => {
let { detail: lbDetail } = containerProps || {}; const { detail } = containerProps || {};
let lbDetail = item.loadBalancer || detail;
if (!lbDetail) { if (!lbDetail) {
lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]); lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]);
} }

View File

@ -20,14 +20,17 @@ import globalHealthMonitorStore, {
import { healthProtocols } from 'resources/octavia/lb'; import { healthProtocols } from 'resources/octavia/lb';
import { PoolStore } from 'stores/octavia/pool'; import { PoolStore } from 'stores/octavia/pool';
import globalLbaasStore from 'stores/octavia/loadbalancer'; import globalLbaasStore from 'stores/octavia/loadbalancer';
import { ListenerStore } from 'stores/octavia/listener';
export class EditHealthMonitor extends ModalAction { export class EditHealthMonitor extends ModalAction {
init() { init() {
this.store = new HealthMonitorStore(); this.store = new HealthMonitorStore();
this.listenerStore = new ListenerStore();
this.poolStore = new PoolStore(); this.poolStore = new PoolStore();
this.state = { this.state = {
defaultData: true, enableHealthMonitor: false,
admin_state_up: false, dataLoading: true,
healthMonitor: null,
}; };
} }
@ -58,31 +61,40 @@ export class EditHealthMonitor extends ModalAction {
} }
get defaultValue() { get defaultValue() {
const { operating_status, type, delay, timeout, max_retries } = const { healthMonitor } = this.state;
this.store.detail; if (!healthMonitor) {
const { defaultData, admin_state_up } = this.state; return {
if (defaultData && operating_status && this.formRef.current) { delay: 5,
this.formRef.current.setFieldsValue({ timeout: 3,
admin_state_up, max_retries: 3,
operating_status, enableHealthMonitor: false,
type, admin_state_up: true,
delay, };
timeout,
max_retries,
});
this.setState({ defaultData: false });
} }
const {
admin_state_up,
operating_status,
type,
delay,
timeout,
max_retries,
} = healthMonitor;
return { return {
delay: 5, enableHealthMonitor: true,
timeout: 3, admin_state_up,
max_retries: 3, operating_status,
type,
delay,
timeout,
max_retries,
}; };
} }
static policy = 'os_load-balancer_api:healthmonitor:put'; static policy = 'os_load-balancer_api:healthmonitor:put';
static allowed = async (item, containerProps) => { static allowed = async (item, containerProps) => {
let { detail: lbDetail } = containerProps || {}; const { detail } = containerProps || {};
let lbDetail = item.loadBalancer || detail;
if (!lbDetail) { if (!lbDetail) {
lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]); lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]);
} }
@ -94,52 +106,45 @@ export class EditHealthMonitor extends ModalAction {
}; };
async getHealthMonitor() { async getHealthMonitor() {
const { default_pool_id } = this.item; const detail = await this.listenerStore.fetchDetail(this.item);
const pool = await this.poolStore.fetchDetail({ id: default_pool_id }); const { healthMonitor } = detail;
const { healthmonitor_id } = pool; this.setState(
if (healthmonitor_id) { {
const { admin_state_up } = await this.store.fetchDetail({ healthMonitor,
id: healthmonitor_id, enableHealthMonitor: !!healthMonitor,
}); dataLoading: false,
this.setState({ admin_state_up }); },
this.formRef.current.setFieldsValue({ admin_state_up }); () => {
} this.updateDefaultValue();
} }
);
get tips() {
const { healthmonitor_id } = this.poolStore.detail || {};
if (!healthmonitor_id) {
return t(
'First time edit automatically creates health monitor When pool does not have a health monitor'
);
}
return '';
} }
get formItems() { get formItems() {
const { admin_state_up } = this.state; const { enableHealthMonitor, dataLoading, healthMonitor } = this.state;
const { healthmonitor_id } = this.poolStore.detail || {}; if (dataLoading) {
return [
{
name: 'loading',
type: 'loading',
},
];
}
return [ return [
{ {
name: 'admin_state_up', name: 'enableHealthMonitor',
label: t('Enable Health Monitor'), label: t('Enable Health Monitor'),
type: 'radio', type: 'radio',
required: true, required: true,
// onlyRadio: true,
// isWrappedValue: true,
options: [ options: [
{ {
label: t('Yes'), label: t('Yes'),
value: true, value: true,
}, },
...(healthmonitor_id {
? [ label: t('No'),
{ value: false,
label: t('No'), },
value: false,
},
]
: []),
], ],
}, },
{ {
@ -147,9 +152,9 @@ export class EditHealthMonitor extends ModalAction {
label: t('HealthMonitor Type'), label: t('HealthMonitor Type'),
type: 'select', type: 'select',
options: this.filteredProtocolOptions, options: this.filteredProtocolOptions,
hidden: !admin_state_up && healthmonitor_id, hidden: !enableHealthMonitor,
required: true, required: true,
disabled: !!healthmonitor_id, disabled: !!healthMonitor,
}, },
{ {
name: 'delay', name: 'delay',
@ -157,7 +162,7 @@ export class EditHealthMonitor extends ModalAction {
type: 'input-int', type: 'input-int',
min: 0, min: 0,
extra: t('Maximum interval time for each health check response'), extra: t('Maximum interval time for each health check response'),
hidden: !admin_state_up && healthmonitor_id, hidden: !enableHealthMonitor,
required: true, required: true,
}, },
{ {
@ -168,7 +173,7 @@ export class EditHealthMonitor extends ModalAction {
extra: t( extra: t(
'The timeout period of waiting for the return of the health check request, the check timeout will be judged as a check failure' 'The timeout period of waiting for the return of the health check request, the check timeout will be judged as a check failure'
), ),
hidden: !admin_state_up && healthmonitor_id, hidden: !enableHealthMonitor,
required: true, required: true,
}, },
{ {
@ -179,21 +184,39 @@ export class EditHealthMonitor extends ModalAction {
extra: t( extra: t(
'That is, after how many consecutive failures of the health check, the health check status of the back-end cloud server is changed from normal to abnormal' 'That is, after how many consecutive failures of the health check, the health check status of the back-end cloud server is changed from normal to abnormal'
), ),
hidden: !admin_state_up && healthmonitor_id, hidden: !enableHealthMonitor,
required: true, required: true,
}, },
{
name: 'admin_state_up',
label: t('Admin State Up'),
type: 'switch',
tip: t('Defines the admin state of the health monitor.'),
hidden: !enableHealthMonitor,
},
]; ];
} }
onSubmit = (values) => { onSubmit = (values) => {
const { default_pool_id } = this.item; const { default_pool_id } = this.item;
const { healthmonitor_id: id } = this.poolStore.detail || {}; const { healthMonitor } = this.state;
const { id } = healthMonitor || {};
const { enableHealthMonitor, type, ...others } = values;
if (id) { if (id) {
const { type, ...others } = values; if (!enableHealthMonitor) {
return globalHealthMonitorStore.delete({ id });
}
return globalHealthMonitorStore.edit({ id }, others); return globalHealthMonitorStore.edit({ id }, others);
} }
values.pool_id = default_pool_id; if (!enableHealthMonitor) {
return globalHealthMonitorStore.create(values); return Promise.resolve();
}
const data = {
type,
...others,
pool_id: default_pool_id,
};
return globalHealthMonitorStore.create(data);
}; };
} }

View File

@ -63,7 +63,8 @@ export class EditPoolInfo extends ModalAction {
static policy = 'os_load-balancer_api:pool:put'; static policy = 'os_load-balancer_api:pool:put';
static allowed = async (item, containerProps) => { static allowed = async (item, containerProps) => {
let { detail: lbDetail } = containerProps || {}; const { detail } = containerProps || {};
let lbDetail = item.loadBalancer || detail;
if (!lbDetail) { if (!lbDetail) {
lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]); lbDetail = await globalLbaasStore.pureFetchDetail(item.loadbalancers[0]);
} }

View File

@ -13,38 +13,12 @@
// limitations under the License. // limitations under the License.
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import globalListenerStore from 'stores/octavia/listener';
import Base from 'containers/BaseDetail'; import Base from 'containers/BaseDetail';
import { HealthMonitorStore } from 'stores/octavia/health-monitor';
import { getInsertHeaderCard } from 'resources/octavia/lb'; import { getInsertHeaderCard } from 'resources/octavia/lb';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { algorithmDict } from 'resources/octavia/pool'; import { algorithmDict } from 'resources/octavia/pool';
export class BaseDetail extends Base { export class BaseDetail extends Base {
componentDidMount() {
this.fetchData();
const { default_pool: { healthmonitor_id } = {} } = this.detailData;
if (healthmonitor_id) {
this.fetchHealthMonitor();
}
}
get shouldFetchDetail() {
return true;
}
init() {
this.store = globalListenerStore;
this.healthmonitorStore = new HealthMonitorStore();
}
fetchHealthMonitor = async () => {
const {
default_pool: { healthmonitor_id },
} = this.detailData;
await this.healthmonitorStore.fetchDetail({ id: healthmonitor_id });
};
get leftCards() { get leftCards() {
const cards = [this.PoolInfo, this.healthMonitor]; const cards = [this.PoolInfo, this.healthMonitor];
const { insert_headers = {} } = this.detailData; const { insert_headers = {} } = this.detailData;
@ -100,32 +74,39 @@ export class BaseDetail extends Base {
} }
get healthMonitor() { get healthMonitor() {
const healthmonitor = this.healthmonitorStore.detail || {}; const healthMonitor = this.detailData.healthMonitor || {};
const { admin_state_up, type, delay, timeout, max_retries } = healthmonitor; const { type, delay, timeout, max_retries, admin_state_up } = healthMonitor;
const options = [ const options = [
{ {
label: t('Enable Health Monitor'), label: t('Enable Health Monitor'),
content: admin_state_up ? t('Yes') : t('No'), content: !isEmpty(healthMonitor) ? t('Yes') : t('No'),
},
{
label: t('Health Monitor Type'),
content: admin_state_up ? type : '-',
},
{
label: t('Delay Interval(s)'),
content: admin_state_up ? delay : '-',
},
{
label: t('Timeout(s)'),
content: admin_state_up ? timeout : '-',
},
{
label: t('Max Retries'),
content: admin_state_up ? max_retries : '-',
}, },
]; ];
if (Object.keys(healthmonitor).length === 0) { if (!isEmpty(healthMonitor)) {
options[0].content = '-'; options.push(
...[
{
label: t('Health Monitor Type'),
content: type,
},
{
label: t('Delay Interval(s)'),
content: delay,
},
{
label: t('Timeout(s)'),
content: timeout,
},
{
label: t('Max Retries'),
content: max_retries,
},
{
label: t('Admin State Up'),
content: admin_state_up ? t('On') : t('Off'),
},
]
);
} }
return { return {
title: t('Health Monitor'), title: t('Health Monitor'),

View File

@ -78,6 +78,10 @@ export class ListenerDetail extends Base {
]; ];
} }
get forceLoadingTabs() {
return ['detail'];
}
get tabs() { get tabs() {
const tabs = [ const tabs = [
{ {

View File

@ -122,6 +122,7 @@ export class HealthMonitorStep extends Base {
label: t('Admin State Up'), label: t('Admin State Up'),
type: 'switch', type: 'switch',
tip: t('Defines the admin state of the health monitor.'), tip: t('Defines the admin state of the health monitor.'),
hidden: !enableHealthMonitor,
}, },
]; ];
} }

View File

@ -24,6 +24,14 @@ export class ListenerStore extends Base {
return client.octavia.pools; return client.octavia.pools;
} }
get healthMonitorClient() {
return client.octavia.healthMonitors;
}
get lbClient() {
return client.octavia.loadbalancers;
}
get listFilterByProject() { get listFilterByProject() {
return true; return true;
} }
@ -66,11 +74,21 @@ export class ListenerStore extends Base {
caCertificateId: caId, caCertificateId: caId,
sniCertificateId: sniId, sniCertificateId: sniId,
}); });
const { loadbalancers = [] } = item;
const { loadbalancer } = await this.lbClient.show(loadbalancers[0].id);
item.loadBalancer = loadbalancer;
if (default_pool_id) { if (default_pool_id) {
// pool attach listener or loadbalancer // pool attach listener or loadbalancer
try { try {
const res = await this.poolClient.show(default_pool_id); const { pool } = await this.poolClient.show(default_pool_id);
item.default_pool = res.pool; item.default_pool = pool;
const { healthmonitor_id } = pool;
if (healthmonitor_id) {
const { healthmonitor } = await this.healthMonitorClient.show(
healthmonitor_id
);
item.healthMonitor = healthmonitor;
}
return item; return item;
} catch (err) { } catch (err) {
return item; return item;