Skip to content

Commit

Permalink
[CE-458] Refine delete cluster api
Browse files Browse the repository at this point in the history
Move delete cluster task into celery task for quick handle.
Use supervisor instead of celeryd can restart celery when process is
crashed.
Add more info in chain list in operator dashboard.
Can auto refresh chain info when processing.

Change-Id: If4ee7b13bc18ea95bbb8a63b31ba175d3eb9ce83
Signed-off-by: Haitao Yue <[email protected]>
  • Loading branch information
hightall committed Sep 2, 2018
1 parent b215f47 commit 81301e1
Show file tree
Hide file tree
Showing 16 changed files with 217 additions and 49 deletions.
4 changes: 2 additions & 2 deletions docker/baseimage/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ set -x
# Based thie file on https://github.com/docker-library/mongo/blob/master/3.4/Dockerfile &
# https://docs.mongodb.com/manual/tutorial/install-mongodb-enterprise-on-ubuntu/#install-mongodb-enterprise

#set -x \
# && apt-get update && apt-get install -y --no-install-recommends circus && rm -rf /var/lib/apt/lists/*
set -x \
&& apt-get update && apt-get install -y supervisor && rm -rf /var/lib/apt/lists/*
3 changes: 2 additions & 1 deletion docker/operator-dashboard/Dockerfile.in
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
FROM hyperledger/cello-baseimage:latest

COPY src /app
COPY src/celery.conf /etc/supervisor/conf.d/
RUN cd /app/ && \
pip install -r requirements.txt && \
rm -rf /tmp/cello

CMD bash /app/celery.sh && if [ "$DEBUG" = "True" ]; then python dashboard.py ; else gunicorn -w 1 --worker-class eventlet -b 0.0.0.0:8080 dashboard:app ;fi
CMD /etc/init.d/supervisor start && if [ "$DEBUG" = "True" ]; then python dashboard.py ; else gunicorn -w 1 --worker-class eventlet -b 0.0.0.0:8080 dashboard:app ;fi
8 changes: 8 additions & 0 deletions src/celery.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[program:celery]
environment=C_FORCE_ROOT="yes"
command=/usr/local/bin/celery worker --autoscale=20,5 -l info -A dashboard.celery
directory=/app
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/celery.log
redirect_stderr=true
12 changes: 0 additions & 12 deletions src/celery.sh

This file was deleted.

6 changes: 6 additions & 0 deletions src/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class ReleaseClusterException(Exception):
pass


class DeleteClusterException(Exception):
pass
14 changes: 3 additions & 11 deletions src/resources/cluster_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
FabricPreNetworkConfig, FabricV1NetworkConfig

from modules import cluster_handler, host_handler
from tasks import release_cluster
from tasks import release_cluster, delete_cluster

logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
Expand Down Expand Up @@ -295,16 +295,8 @@ def cluster_delete():
else:
logger.debug("cluster delete with id={0}, col_name={1}".format(
cluster_id, col_name))
if col_name == "active":
result = cluster_handler.delete(id=cluster_id)
else:
result = cluster_handler.delete_released(id=cluster_id)
if result:
return make_ok_resp()
else:
error_msg = "Failed to delete cluster {}".format(cluster_id)
logger.warning(error_msg)
return make_fail_resp(error=error_msg)
delete_cluster.delay(cluster_id, col_name)
return make_ok_resp()


@bp_cluster_api.route('/clusters', methods=['GET', 'POST'])
Expand Down
2 changes: 2 additions & 0 deletions src/static/dashboard/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@
"Chain.Label.ConsensusPlugin": "Consensus Plugin",
"Chain.Label.Owner": "Owner",
"Chain.Label.CreateTime": "Create Time",
"Chain.Label.Status": "Status",
"Chain.Label.Health": "Health",
"Chain.Create.Title": "Create New Chain",
"Chain.Create.Validate.Required.Host": "Must select a host",
"Chain.Create.Label.Host": "Host",
Expand Down
2 changes: 2 additions & 0 deletions src/static/dashboard/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@
"Chain.Label.ConsensusPlugin": "共识",
"Chain.Label.Owner": "使用者",
"Chain.Label.CreateTime": "创建时间",
"Chain.Label.Status": "状态",
"Chain.Label.Health": "健康",
"Chain.Create.Title": "创建新的链",
"Chain.Create.Validate.Required.Host": "必须选择一个主机",
"Chain.Create.Label.Host": "主机",
Expand Down
85 changes: 82 additions & 3 deletions src/static/dashboard/src/models/chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import { routerRedux } from 'dva/router';
import { IntlProvider, defineMessages } from 'react-intl';
import { message } from 'antd';
import { queryChains, operateChain, deleteChain, createChain } from '../services/chain';
import { getLocale } from '../utils/utils';
import { queryChains, operateChain, deleteChain, createChain, getChain } from '../services/chain';
import { getLocale, sleep } from '../utils/utils';

const currentLocale = getLocale();
const intlProvider = new IntlProvider(
Expand Down Expand Up @@ -42,15 +42,59 @@ export default {

state: {
chains: [],
canQueryChain: false,
},

effects: {
*fetchChains({ payload }, { call, put }) {
const response = yield call(queryChains, payload);
const chains = response.data || [];
yield put({
type: 'setChains',
payload: response.data,
payload: chains,
});
yield *chains.map((chain) => {
if (['creating', 'deleting'].indexOf(chain.status) >= 0 || ['', 'FAIL'].indexOf(chain.health) >= 0) {
return put({
type: 'getChain',
payload: {
id: chain.id,
},
})
} else {
return true;
}
})
},
*getChain({ payload }, { select, call, put}) {
const response = yield call(getChain, payload.id);
const canQueryChain = yield select(state => state.chain.canQueryChain);
if (response.code === 200) {
yield put({
type: 'updateChain',
payload: {
id: payload.id,
data: response.data,
},
});
const chain = response.data;
if (canQueryChain && (['creating', 'deleting'].indexOf(chain.status) >= 0 || ['', 'FAIL'].indexOf(chain.health) >= 0)) {
yield sleep(5000);
yield put({
type: 'getChain',
payload: {
id: chain.id,
},
})
}
} else if (response.code === 404) {
yield put({
type: 'removeChain',
payload: {
id: payload.id,
},
})
}
},
*operateChain({ payload }, { call, put }) {
const response = yield call(operateChain, payload);
Expand Down Expand Up @@ -92,5 +136,40 @@ export default {
chains: action.payload,
};
},
updateChain(state, action) {
const { id, data } = action.payload;
const { chains } = state;
chains.forEach((chain, index) => {
if (chain.id === id) {
chains[index] = data;
return false;
}
});
return {
...state,
chains,
}
},
removeChain(state, action) {
const { id } = action.payload;
const { chains } = state;
chains.forEach((chain, index) => {
if (chain.id === id) {
chains.splice(index, 1);
return false;
}
});
return {
...state,
chains,
}
},
setCanQuery(state, action) {
const { canQueryChain } = action.payload;
return {
...state,
canQueryChain,
}
},
},
};
59 changes: 56 additions & 3 deletions src/static/dashboard/src/routes/Chain/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { connect } from 'dva';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { List, Card, Button, Dropdown, Menu, Icon, Badge, Modal, Radio } from 'antd';
import { routerRedux } from 'dva/router';
import moment from 'moment';
import PageHeaderLayout from '../../layouts/PageHeaderLayout';
import styles from './style.less';

Expand Down Expand Up @@ -64,6 +65,18 @@ const messages = defineMessages({
id: 'Chain.Label.CreateTime',
defaultMessage: 'Create Time',
},
status: {
id: 'Chain.Label.Status',
defaultMessage: 'Status',
},
health: {
id: 'Chain.Label.Health',
defaultMessage: 'Health',
},
host: {
id: 'Chain.Create.Label.Host',
defaultMessage: 'Host',
},
},
radio: {
option: {
Expand Down Expand Up @@ -93,8 +106,22 @@ const messages = defineMessages({
}))
class Chain extends PureComponent {
componentDidMount() {
this.props.dispatch({
type: 'chain/setCanQuery',
payload: {
canQueryChain: true,
},
});
this.loadChains();
}
componentWillUnmount() {
this.props.dispatch({
type: 'chain/setCanQuery',
payload: {
canQueryChain: false,
},
});
};
onClickAddChain = () => {
this.props.dispatch(
routerRedux.push({
Expand Down Expand Up @@ -162,6 +189,18 @@ class Chain extends PureComponent {
};
function badgeStatus(status) {
switch (status) {
case 'running':
return 'success';
case 'creating':
case 'deleting':
return 'processing';
case 'stopped':
default:
return 'default';
}
}
function badgeHealth(health) {
switch (health) {
case 'OK':
return 'success';
case 'FAIL':
Expand All @@ -172,7 +211,7 @@ class Chain extends PureComponent {
return 'default';
}
}
const ListContent = ({ data: { user_id, create_ts, health } }) => (
const ListContent = ({ data: { user_id, create_ts, health, status } }) => (
<div className={styles.listContent}>
<div className={styles.listContentItem}>
<span>
Expand All @@ -184,10 +223,23 @@ class Chain extends PureComponent {
<span>
<FormattedMessage {...messages.label.createTime} />
</span>
<p>{create_ts}</p>
<p>{moment(create_ts).format("YYYY-MM-DD HH:mm:ss")}</p>
</div>
<div className={styles.listContentItem}>
<Badge className={styles['status-badge']} status={badgeStatus(health)} text={health === '' ? 'Waiting' : health} />
<span>
<FormattedMessage {...messages.label.status} />
</span>
<p>
<Badge className={styles['status-badge']} status={badgeStatus(status)} text={status} />
</p>
</div>
<div className={styles.listContentItem}>
<span>
<FormattedMessage {...messages.label.health} />
</span>
<p>
<Badge className={styles['status-badge']} status={badgeHealth(health)} text={health === '' ? 'Waiting' : health} />
</p>
</div>
</div>
);
Expand Down Expand Up @@ -264,6 +316,7 @@ class Chain extends PureComponent {
description={
<div>
<p>
<FormattedMessage {...messages.label.host} />: {item.host} &nbsp;&nbsp;
<FormattedMessage {...messages.label.networkType} />: {item.network_type}
</p>
<p>
Expand Down
4 changes: 4 additions & 0 deletions src/static/dashboard/src/services/chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ export async function createChain(params) {
body: params,
});
}

export async function getChain(id) {
return request(`${urls.cluster.crud}/${id}`)
}
4 changes: 4 additions & 0 deletions src/static/dashboard/src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,7 @@ export function getLocale() {
export function getLang() {
return (window.localStorage && localStorage.getItem('language')) || (navigator.language || navigator.browserLanguage).toLowerCase();
}

export async function sleep(sleep_time_ms) {
return new Promise(resolve => setTimeout(resolve, sleep_time_ms));
}
3 changes: 2 additions & 1 deletion src/static/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"echarts-for-react": "^1.1.6",
"react-draft-wysiwyg": "^1.8.1",
"react-helmet": "^5.0.0",
"echarts": "^3.4.0"
"echarts": "^3.4.0",
"moment": "^2.22.2"
},
"devDependencies": {
"atool-build": "^0.7.6",
Expand Down
16 changes: 0 additions & 16 deletions src/tasks.py

This file was deleted.

5 changes: 5 additions & 0 deletions src/tasks/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright IBM Corp, All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
from . cluster import release_cluster, delete_cluster
Loading

0 comments on commit 81301e1

Please sign in to comment.