Merge "feature: Add openstack service monitor page"

This commit is contained in:
Zuul 2021-12-02 01:43:57 +00:00 committed by Gerrit Code Review
commit 8f449b1149
6 changed files with 427 additions and 193 deletions

View File

@ -617,6 +617,14 @@ const renderMenu = (t) => {
children: [], children: [],
hasBreadcrumb: true, hasBreadcrumb: true,
}, },
{
path: '/monitor-center/openstack-service-admin',
name: t('OpenStack Service'),
key: 'monitorOpenstackServiceAdmin',
level: 1,
children: [],
hasBreadcrumb: true,
},
], ],
}, },
{ {

View File

@ -0,0 +1,85 @@
// Copyright 2021 99cloud
//
// 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.
import React from 'react';
import { Col, Collapse, List, Tooltip } from 'antd';
import { CheckCircleTwoTone, InfoCircleTwoTone } from '@ant-design/icons';
import styles from './index.less';
const { Panel } = Collapse;
const statusToIcon = {
up: (
<CheckCircleTwoTone
style={{ fontSize: 24, marginLeft: 36 }}
twoToneColor="#52C41A"
/>
),
// <WarningTwoTone style={{ fontSize: 24, marginLeft: 36 }} twoToneColor="#FAAD14" />,
down: (
<InfoCircleTwoTone
style={{ fontSize: 24, marginLeft: 36 }}
twoToneColor="#EB354D"
/>
),
};
const Services = (props) => {
const { serviceMap } = props;
return (
<Collapse defaultActiveKey={serviceMap.map((item) => item.key)} ghost>
{serviceMap.map((item) => (
<Panel
header={<span className={styles.header}>{item.title}</span>}
key={item.key}
>
<List
bordered
dataSource={item.data}
className={styles.list}
loading={item.isLoading}
renderItem={(it) => (
<List.Item className={styles.item}>
<Col className={styles.title} span={6}>
{it.engine_id ? (
<Tooltip title={it.engine_id}>
<span>{it.serviceName}</span>
</Tooltip>
) : (
it.serviceName
)}
</Col>
<Col className={styles.title} span={6}>
{it.hostname}
</Col>
<Col className={styles.status} span={6}>
<span>{t('Current Status')}</span>
{statusToIcon[it.state]}
</Col>
<Col className={styles.status} span={6}>
<span>{t('Last 24H Status')} </span>
{it[`${it.serviceName}24`]
? statusToIcon[it[`${it.serviceName}24`]]
: statusToIcon.up}
</Col>
</List.Item>
)}
/>
</Panel>
))}
</Collapse>
);
};
export default Services;

View File

@ -0,0 +1,87 @@
// Copyright 2021 99cloud
//
// 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.
import React, { Component } from 'react';
import { observer } from 'mobx-react';
import { OpenstackServiceStore } from 'stores/prometheus/openstack-service';
import { SyncOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import Services from './Services';
import styles from '../PhysicalNode/index.less';
@observer
class OpenstackService extends Component {
constructor(props) {
super(props);
this.store = new OpenstackServiceStore();
}
componentDidMount() {
this.getData();
}
getData = async () => {
// await this.store.getNodes();
await this.store.getChartData();
};
handleRefresh = () => {
this.getData();
};
render() {
const { nova_service, network_service, other_service, cinder_service } =
this.store;
const serviceMap = [
{
key: 'nova_service',
title: t('Nova Service'),
...nova_service,
},
{
key: 'network_service',
title: t('Neutron Service'),
...network_service,
},
{
key: 'cinder_service',
title: t('Cinder Service'),
...cinder_service,
},
{
key: 'other_service',
title: t('Other Service'),
...other_service,
},
];
return (
<div className={styles.outer}>
<div className={styles.inner}>
<div className={styles.header}>
<Button
type="default"
icon={<SyncOutlined />}
onClick={this.handleRefresh}
/>
{/* <NodeSelect style={{ display: 'inline', marginLeft: 20 }} store={this.store} /> */}
<Services serviceMap={serviceMap} />
</div>
</div>
</div>
);
}
}
export default OpenstackService;

View File

@ -0,0 +1,32 @@
.header {
font-size: 16px;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
line-height: 22px;
}
.list {
background-color: #FFFFFF;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.05);
border: none;
.item {
height: 76px;
.title {
display: flex;
font-size: 16px;
font-weight: 400;
color: rgba(0, 0, 0, 0.65);
}
.status {
display: flex;
font-size: 14px;
font-weight: 400;
color: rgba(0, 0, 0, 0.65);
}
}
}

View File

@ -16,6 +16,7 @@ import BaseLayout from 'layouts/Basic';
import E404 from 'pages/base/containers/404'; import E404 from 'pages/base/containers/404';
import PhysicalNode from '../containers/PhysicalNode'; import PhysicalNode from '../containers/PhysicalNode';
import StorageCluster from '../containers/StorageCluster'; import StorageCluster from '../containers/StorageCluster';
import OpenstackService from '../containers/OpenstackService';
import Overview from '../containers/Overview'; import Overview from '../containers/Overview';
const PATH = '/monitor-center'; const PATH = '/monitor-center';
@ -35,6 +36,11 @@ export default [
component: StorageCluster, component: StorageCluster,
exact: true, exact: true,
}, },
{
path: `${PATH}/openstack-service-admin`,
component: OpenstackService,
exact: true,
},
{ path: '*', component: E404 }, { path: '*', component: E404 },
], ],
}, },

View File

@ -77,64 +77,70 @@ export class OpenstackServiceStore extends MonitorBase {
isLoading: true, isLoading: true,
data: [], data: [],
}); });
const [currentState, last24State, libvirtdState, libvirtd24State] =
await Promise.all(getPromises.call(this, 'openstackService.novaService'));
const {
data: { result: currentStateResult },
} = currentState;
const tmp = []; const tmp = [];
currentStateResult.forEach((service) => { try {
const [currentState, last24State, libvirtdState, libvirtd24State] =
await Promise.all(
getPromises.call(this, 'openstackService.novaService')
);
const { const {
metric: { data: { result: currentStateResult },
service: serviceName = '', } = currentState;
adminState = '', currentStateResult.forEach((service) => {
hostname = '', const {
} = {}, metric: {
} = service; service: serviceName = '',
tmp.push({ adminState = '',
hostname, hostname = '',
serviceName, } = {},
state: adminState === 'enabled' ? 'up' : 'down', } = service;
tmp.push({
hostname,
serviceName,
state: adminState === 'enabled' ? 'up' : 'down',
});
}); });
}); const {
const { data: { result: last24HResult },
data: { result: last24HResult }, } = last24State;
} = last24State; last24HResult.forEach((service) => {
last24HResult.forEach((service) => { const { metric: { service: serviceName = '', hostname = '' } = {} } =
const { metric: { service: serviceName = '', hostname = '' } = {} } = service;
service; const idx = tmp.findIndex(
const idx = tmp.findIndex( (item) =>
(item) => item.serviceName === serviceName && item.hostname === hostname item.serviceName === serviceName && item.hostname === hostname
); );
tmp[idx][`${serviceName}24`] = 'down'; tmp[idx][`${serviceName}24`] = 'down';
});
const {
data: { result: data },
} = libvirtdState;
data.forEach((item) => {
const { metric, value } = item;
tmp.push({
// hard code
serviceName: 'nova_libvirt',
hostname: metric.hostname,
state: value[1] === 'enabled' ? 'up' : 'down',
}); });
}); const {
const { data: { result: data },
data: { result: libvirtd24Result }, } = libvirtdState;
} = libvirtd24State; data.forEach((item) => {
libvirtd24Result.forEach((service) => { const { metric, value } = item;
const { metric: { hostname = '' } = {} } = service; tmp.push({
const idx = tmp.findIndex( // hard code
(item) => serviceName: 'nova_libvirt',
item.serviceName === 'nova_libvirt' && item.hostname === hostname hostname: metric.hostname,
); state: value[1] === 'enabled' ? 'up' : 'down',
tmp[idx].nova_libvirt24 = 'down'; });
}); });
set(this.nova_service, { const {
isLoading: false, data: { result: libvirtd24Result },
data: tmp, } = libvirtd24State;
}); libvirtd24Result.forEach((service) => {
const { metric: { hostname = '' } = {} } = service;
const idx = tmp.findIndex(
(item) =>
item.serviceName === 'nova_libvirt' && item.hostname === hostname
);
tmp[idx].nova_libvirt24 = 'down';
});
} finally {
set(this.nova_service, {
isLoading: false,
data: tmp,
});
}
}; };
@action @action
@ -143,42 +149,46 @@ export class OpenstackServiceStore extends MonitorBase {
isLoading: true, isLoading: true,
data: [], data: [],
}); });
const [currentState, last24State] = await Promise.all(
getPromises.call(this, 'openstackService.networkService')
);
const {
data: { result: currentStateResult },
} = currentState;
const tmp = []; const tmp = [];
currentStateResult.forEach((service) => { try {
const { const [currentState, last24State] = await Promise.all(
metric: { getPromises.call(this, 'openstackService.networkService')
service: serviceName = '',
adminState = '',
hostname = '',
} = {},
} = service;
tmp.push({
serviceName,
hostname,
state: adminState,
});
});
const {
data: { result: last24HResult },
} = last24State;
last24HResult.forEach((service) => {
const { metric: { service: serviceName = '', hostname = '' } = {} } =
service;
const idx = tmp.findIndex(
(item) => item.serviceName === serviceName && item.hostname === hostname
); );
tmp[idx][`${serviceName}24`] = 'down'; const {
}); data: { result: currentStateResult },
set(this.network_service, { } = currentState;
isLoading: false, currentStateResult.forEach((service) => {
data: tmp, const {
}); metric: {
service: serviceName = '',
adminState = '',
hostname = '',
} = {},
} = service;
tmp.push({
serviceName,
hostname,
state: adminState,
});
});
const {
data: { result: last24HResult },
} = last24State;
last24HResult.forEach((service) => {
const { metric: { service: serviceName = '', hostname = '' } = {} } =
service;
const idx = tmp.findIndex(
(item) =>
item.serviceName === serviceName && item.hostname === hostname
);
tmp[idx][`${serviceName}24`] = 'down';
});
} finally {
set(this.network_service, {
isLoading: false,
data: tmp,
});
}
}; };
@action @action
@ -187,42 +197,46 @@ export class OpenstackServiceStore extends MonitorBase {
isLoading: true, isLoading: true,
data: [], data: [],
}); });
const [currentState, last24State] = await Promise.all(
getPromises.call(this, 'openstackService.cinderService')
);
const {
data: { result: currentStateResult },
} = currentState;
const tmp = []; const tmp = [];
currentStateResult.forEach((service) => { try {
const { const [currentState, last24State] = await Promise.all(
metric: { getPromises.call(this, 'openstackService.cinderService')
service: serviceName = '',
adminState = '',
hostname = '',
} = {},
} = service;
tmp.push({
serviceName,
hostname,
state: adminState === 'enabled' ? 'up' : 'down',
});
});
const {
data: { result: last24HResult },
} = last24State;
last24HResult.forEach((service) => {
const { metric: { service: serviceName = '', hostname = '' } = {} } =
service;
const idx = tmp.findIndex(
(item) => item.serviceName === serviceName && item.hostname === hostname
); );
tmp[idx][`${serviceName}24`] = 'down'; const {
}); data: { result: currentStateResult },
set(this.cinder_service, { } = currentState;
isLoading: false, currentStateResult.forEach((service) => {
data: tmp, const {
}); metric: {
service: serviceName = '',
adminState = '',
hostname = '',
} = {},
} = service;
tmp.push({
serviceName,
hostname,
state: adminState === 'enabled' ? 'up' : 'down',
});
});
const {
data: { result: last24HResult },
} = last24State;
last24HResult.forEach((service) => {
const { metric: { service: serviceName = '', hostname = '' } = {} } =
service;
const idx = tmp.findIndex(
(item) =>
item.serviceName === serviceName && item.hostname === hostname
);
tmp[idx][`${serviceName}24`] = 'down';
});
} finally {
set(this.cinder_service, {
isLoading: false,
data: tmp,
});
}
}; };
@action @action
@ -232,80 +246,82 @@ export class OpenstackServiceStore extends MonitorBase {
data: [], data: [],
}); });
const tmp = []; const tmp = [];
let results = await Promise.all( try {
getPromises.call(this, 'openstackService.otherService') let results = await Promise.all(
); getPromises.call(this, 'openstackService.otherService')
results.forEach((result) => { );
const { results.forEach((result) => {
data: { result: data }, const {
} = result; data: { result: data },
data.forEach((d) => { } = result;
const { metric, value } = d; data.forEach((d) => {
tmp.push({ const { metric, value } = d;
serviceName: serviceNameMap[metric.__name__], tmp.push({
hostname: metric.instance, serviceName: serviceNameMap[metric.__name__],
state: value[1] === '1' ? 'up' : 'down', hostname: metric.instance,
state: value[1] === '1' ? 'up' : 'down',
});
}); });
}); });
}); results = await Promise.all(
results = await Promise.all( getPromises.call(this, 'openstackService.otherServiceMinOverTime')
getPromises.call(this, 'openstackService.otherServiceMinOverTime') );
); results.forEach((result, index) => {
results.forEach((result, index) => { const {
const { data: { result: last24HResult },
data: { result: last24HResult }, } = result;
} = result; last24HResult.forEach((service) => {
last24HResult.forEach((service) => { const { metric: { instance = '' } = {} } = service;
const { metric: { instance = '' } = {} } = service; const idx = tmp.findIndex(
const idx = tmp.findIndex( (item) =>
(item) => item.serviceName === indexToServiceName[index] &&
item.serviceName === indexToServiceName[index] && item.hostname === instance
item.hostname === instance );
); tmp[idx][`${indexToServiceName[index]}24`] = 'down';
tmp[idx][`${indexToServiceName[index]}24`] = 'down'; });
}); });
}); // const [heatResponse, heat24Response] = await Promise.all(
// const [heatResponse, heat24Response] = await Promise.all( // getPromises.call(this, 'openstackService.heatMinOverTime')
// getPromises.call(this, 'openstackService.heatMinOverTime') // );
// ); // const {
// const { // data: { result: heatResults },
// data: { result: heatResults }, // } = heatResponse;
// } = heatResponse; // heatResults.forEach((item) => {
// heatResults.forEach((item) => { // const {
// const { // metric: {
// metric: { // host = '',
// host = '', // binary = '',
// binary = '', // engine_id = '',
// engine_id = '', // services_status = '',
// services_status = '', // } = {},
// } = {}, // } = item;
// } = item; // tmp.push({
// tmp.push({ // serviceName: binary,
// serviceName: binary, // host,
// host, // state: services_status,
// state: services_status, // engine_id,
// engine_id, // });
// }); // });
// }); // const {
// const { // data: { result: heat24Results },
// data: { result: heat24Results }, // } = heat24Response;
// } = heat24Response; // heat24Results.forEach((result) => {
// heat24Results.forEach((result) => { // const { metric: { binary = '', engine_id = '', host = '' } = {} } =
// const { metric: { binary = '', engine_id = '', host = '' } = {} } = // result;
// result; // const idx = tmp.findIndex(
// const idx = tmp.findIndex( // (item) =>
// (item) => // item.serviceName === binary &&
// item.serviceName === binary && // item.host === host &&
// item.host === host && // item.engine_id === engine_id
// item.engine_id === engine_id // );
// ); // tmp[idx][`${binary}24`] = 'down';
// tmp[idx][`${binary}24`] = 'down'; // });
// }); } finally {
set(this.other_service, {
set(this.other_service, { isLoading: false,
isLoading: false, data: tmp,
data: tmp, });
}); }
}; };
} }