Merge pull request #4 from alibaba/develop

Develop
This commit is contained in:
yanlinly 2018-11-05 16:40:42 +08:00 committed by GitHub
commit 4956e20e8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 263 additions and 66 deletions

View File

@ -155,6 +155,8 @@ public class NacosNamingService implements NamingService {
beatInfo.setIp(instance.getIp());
beatInfo.setPort(instance.getPort());
beatInfo.setCluster(instance.getCluster().getName());
beatInfo.setWeight(instance.getWeight());
beatInfo.setMetadata(instance.getMetadata());
beatReactor.addBeatInfo(serviceName, beatInfo);

View File

@ -17,6 +17,8 @@ package com.alibaba.nacos.client.naming.beat;
import com.alibaba.fastjson.JSON;
import java.util.Map;
/**
* @author dungu.zpf
*/
@ -24,8 +26,10 @@ public class BeatInfo {
private int port;
private String ip;
private double weight;
private String dom;
private String cluster;
private Map<String, String> metadata;
@Override
public String toString() {
@ -63,4 +67,20 @@ public class BeatInfo {
public void setPort(int port) {
this.port = port;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}

View File

@ -15,16 +15,38 @@
*/
package com.alibaba.nacos.client;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.junit.Ignore;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
/**
* @author dungu.zpf
*/
public class NamingTest {
@Test
public void testServiceList() {
@Ignore
public void testServiceList() throws Exception {
NamingService namingService = NacosFactory.createNamingService("127.0.0.1:8848");
Instance instance = new Instance();
instance.setIp("1.1.1.1");
instance.setPort(80);
instance.setWeight(2);
Map<String, String> map = new HashMap<String, String>();
map.put("env", "prod");
map.put("version", "2.0");
instance.setMetadata(map);
namingService.registerInstance("dungu.test.1", instance);
Thread.sleep(1000000000L);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -31,4 +31,4 @@
"husky": "^0.12.0",
"roadhog": "^2.0.0"
}
}
}

View File

@ -490,6 +490,10 @@ module.exports = {
"com.alibaba.nacos.page.serviceManagement.table.column.health_status": "健康实例数",
"com.alibaba.nacos.page.serviceManagement.table.column.operation": "操作",
"com.alibaba.nacos.page.serviceManagement.detail": "详情",
"com.alibaba.nacos.page.serviceManagement.delete": "删除",
"com.alibaba.nacos.page.serviceManagement.prompt": "提示",
"com.alibaba.nacos.page.serviceManagement.prompt_delete": "确定要删除当前服务吗?",
"com.alibaba.nacos.page.serviceManagement.create": "创建服务",
"com.alibaba.nacos.page.serviceManagement.query": "查询",
"serviceManagement": "服务列表",
"com.alibaba.nacos.page.serviceDetail.service_details": "服务详情",
@ -502,6 +506,7 @@ module.exports = {
"com.alibaba.nacos.page.serviceDetail.health_check_pattern.client": "客户端",
"com.alibaba.nacos.page.serviceDetail.health_check_pattern.none": "禁止",
"com.alibaba.nacos.page.serviceDetail.metadata": "元数据",
"com.alibaba.nacos.page.serviceDetail.create_service": "创建服务",
"com.alibaba.nacos.page.serviceDetail.update_service": "更新服务",
"com.alibaba.nacos.page.serviceDetail.cluster": "集群",
"com.alibaba.nacos.page.serviceDetail.edit_cluster": "集群配置",
@ -1001,9 +1006,14 @@ module.exports = {
"com.alibaba.nacos.page.serviceManagement.table.column.health_status": "Healthy Instance Count",
"com.alibaba.nacos.page.serviceManagement.table.column.operation": "Operation",
"com.alibaba.nacos.page.serviceManagement.detail": "Details",
"com.alibaba.nacos.page.serviceManagement.delete": "Delete",
"com.alibaba.nacos.page.serviceManagement.prompt": "Confirm",
"com.alibaba.nacos.page.serviceManagement.prompt_delete": "Do you want to delete the service?",
"com.alibaba.nacos.page.serviceManagement.create": "Create Service",
"com.alibaba.nacos.page.serviceManagement.query": "Search",
"serviceManagement": "Service Management",
"com.alibaba.nacos.page.serviceDetail.service_details": "Service Details",
"com.alibaba.nacos.page.serviceDetail.create_service": "Create Service",
"com.alibaba.nacos.page.serviceDetail.edit_service": "Edit Service",
"com.alibaba.nacos.page.serviceDetail.back": "Back",
"com.alibaba.nacos.page.serviceDetail.service_name": "Service Name",

View File

@ -12,9 +12,9 @@
*/
import React from 'react';
import { request } from '../../../globalLib';
import { Dialog, Form, Input, Select, Message } from '@alifd/next';
import { I18N, DIALOG_FORM_LAYOUT } from './constant'
import {request} from '../../../globalLib';
import {Dialog, Form, Input, Select, Message} from '@alifd/next';
import {I18N, DIALOG_FORM_LAYOUT} from './constant'
const FormItem = Form.Item;
const Option = Select.Option
@ -24,54 +24,61 @@ class EditServiceDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
isCreate: false,
editService: {},
editServiceDialogVisible: false
}
this.show = this.show.bind(this)
}
show(editService) {
const { metadata = {} } = editService
show(editService = {}) {
const {metadata = {}, name} = editService
if (Object.keys(metadata).length) {
editService.metadataText = Object.keys(metadata).map(k => `${k}=${metadata[k]}`).join(',')
}
this.setState({ editService, editServiceDialogVisible: true })
this.setState({editService, editServiceDialogVisible: true, isCreate: !name})
}
hide() {
this.setState({ editServiceDialogVisible: false })
this.setState({editServiceDialogVisible: false})
}
onConfirm() {
const {isCreate} = this.state
const editService = Object.assign({}, this.state.editService)
const { name, protectThreshold, healthCheckMode, metadataText } = editService
const {name, protectThreshold, healthCheckMode, metadataText} = editService
request({
method: 'POST',
url: '/nacos/v1/ns/service/update',
data: { serviceName: name, protectThreshold, healthCheckMode, metadata: metadataText },
method: isCreate ? 'PUT' : 'POST',
url: `/nacos/v1/ns/service/${isCreate ? 'create' : 'update'}`,
data: {serviceName: name, protectThreshold, healthCheckMode, metadata: metadataText},
dataType: 'text',
beforeSend: () => this.setState({ loading: true }),
beforeSend: () => this.setState({loading: true}),
success: res => {
if (res !== 'ok') {
Message.error(res)
return
}
this.props.getServiceDetail()
if (isCreate) {
this.props.queryServiceList()
} else {
this.props.getServiceDetail()
}
},
complete: () => this.setState({ loading: false })
error: res => Message.error(res.responseText || res.statusText),
complete: () => this.setState({loading: false})
})
this.hide()
}
onChangeCluster(changeVal) {
const { editService = {} } = this.state
const {editService = {}} = this.state
this.setState({
editService: Object.assign({}, editService, changeVal)
})
}
render() {
const { editService, editServiceDialogVisible } = this.state
const {isCreate, editService, editServiceDialogVisible} = this.state
const {
name,
protectThreshold,
@ -81,7 +88,7 @@ class EditServiceDialog extends React.Component {
return (
<Dialog
className="service-detail-edit-dialog"
title={I18N.UPDATE_SERVICE}
title={isCreate ? I18N.CREATE_SERVICE : I18N.UPDATE_SERVICE}
visible={editServiceDialogVisible}
onOk={() => this.onConfirm()}
onCancel={() => this.hide()}
@ -89,20 +96,28 @@ class EditServiceDialog extends React.Component {
>
<Form {...DIALOG_FORM_LAYOUT}>
<FormItem label={`${I18N.SERVICE_NAME}:`}>
<p>{name}</p>
{
!isCreate
? <p>{name}</p>
: <Input
className="in-text"
value={name}
onChange={name => this.onChangeCluster({name})}
/>
}
</FormItem>
<FormItem label={`${I18N.PROTECT_THRESHOLD}:`}>
<Input
className="in-text"
value={protectThreshold}
onChange={protectThreshold => this.onChangeCluster({ protectThreshold })}
onChange={protectThreshold => this.onChangeCluster({protectThreshold})}
/>
</FormItem>
<FormItem label={`${I18N.HEALTH_CHECK_PATTERN}:`}>
<Select
className="in-select"
defaultValue={healthCheckMode}
onChange={healthCheckMode => this.onChangeCluster({ healthCheckMode })}
onChange={healthCheckMode => this.onChangeCluster({healthCheckMode})}
>
<Option value="server">{I18N.HEALTH_CHECK_PATTERN_SERVICE}</Option>
<Option value="client">{I18N.HEALTH_CHECK_PATTERN_CLIENT}</Option>
@ -113,7 +128,7 @@ class EditServiceDialog extends React.Component {
<Input
className="in-text"
value={metadataText}
onChange={metadataText => this.onChangeCluster({ metadataText })}
onChange={metadataText => this.onChangeCluster({metadataText})}
/>
</FormItem>
</Form>

View File

@ -59,6 +59,10 @@ I18N.METADATA = getI18N('metadata')
* 更新服务
*/
I18N.UPDATE_SERVICE = getI18N('update_service')
/**
* 创建服务
*/
I18N.CREATE_SERVICE = getI18N('create_service')
/**
* 集群
*/

View File

@ -13,14 +13,15 @@
import React from 'react';
import RegionGroup from '../../../components/RegionGroup/index';
import { request, aliwareIntl } from '../../../globalLib';
import { Button, Field, Form, Grid, Input, Loading, Pagination, Table } from '@alifd/next';
import { I18N, STATUS_COLOR_MAPPING } from './constant'
import {request, aliwareIntl} from '../../../globalLib';
import {Button, Field, Form, Grid, Input, Loading, Pagination, Table, Dialog, Message} from '@alifd/next';
import EditServiceDialog from '../ServiceDetail/EditServiceDialog'
import {I18N, STATUS_COLOR_MAPPING} from './constant'
import './ServiceList.less'
const FormItem = Form.Item;
const { Row, Col } = Grid;
const { Column } = Table
const {Row, Col} = Grid;
const {Column} = Table
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
class ServiceList extends React.Component {
@ -38,20 +39,24 @@ class ServiceList extends React.Component {
}
openLoading() {
this.setState({ loading: true })
this.setState({loading: true})
}
closeLoading() {
this.setState({ loading: false })
this.setState({loading: false})
}
openEditServiceDialog() {
this.refs.editServiceDialog.show(this.state.service)
}
queryServiceList() {
const { currentPage, pageSize, keyword } = this.state
const {currentPage, pageSize, keyword} = this.state
const parameter = [`startPg=${currentPage}`, `pgSize=${pageSize}`, `keyword=${keyword}`]
request({
url: `/nacos/v1/ns/catalog/serviceList?${parameter.join('&')}`,
beforeSend: () => this.openLoading(),
success: ({ count = 0, serviceList = [] } = {}) => this.setState({
success: ({count = 0, serviceList = []} = {}) => this.setState({
dataSource: serviceList,
total: count
}),
@ -68,20 +73,44 @@ class ServiceList extends React.Component {
setTimeout(() => this.queryServiceList());
}
rowColor = ({ status }) => ({ className: `row-bg-${STATUS_COLOR_MAPPING[status]}` })
deleteService(serviceName) {
Dialog.confirm({
title: I18N.PROMPT,
content: I18N.PROMPT_DELETE,
onOk: () => {
request({
method: 'DELETE',
url: `/nacos/v1/ns/service/remove?serviceName=${serviceName}`,
dataType: 'text',
beforeSend: () => this.openLoading(),
success: res => {
if (res !== 'ok') {
Message.error(res)
return
}
this.props.queryServiceList()
},
error: res => Message.error(res.responseText || res.statusText),
complete: () => this.closeLoading()
})
}
});
}
rowColor = ({status}) => ({className: `row-bg-${STATUS_COLOR_MAPPING[status]}`})
render() {
const { keyword } = this.state
const { init, getValue } = this.field;
const {keyword} = this.state
const {init, getValue} = this.field;
this.init = init;
this.getValue = getValue;
const locale = { empty: I18N.PUBNODEDATA }
const locale = {empty: I18N.PUBNODEDATA}
return (
<div className="main-container service-management">
<Loading
shape="flower"
style={{ position: 'relative' }}
style={{position: 'relative'}}
visible={this.state.loading}
tip="Loading..."
color="#333"
@ -90,61 +119,77 @@ class ServiceList extends React.Component {
left={I18N.SERVICE_LIST}
namespaceCallBack={this.getQueryLater.bind(this)}
/>
<Row className="demo-row" style={{ marginBottom: 10, padding: 0 }}>
<Row className="demo-row" style={{marginBottom: 10, padding: 0}}>
<Col span="24">
<Form inline field={this.field}>
<FormItem label={I18N.SERVICE_NAME}>
<Input
placeholder={I18N.ENTER_SERVICE_NAME}
style={{ width: 200 }}
style={{width: 200}}
value={keyword}
onChange={keyword => this.setState({ keyword })}
onChange={keyword => this.setState({keyword})}
/>
</FormItem>
<FormItem label="">
<Button
type="primary"
onClick={() => this.setState({ currentPage: 1 }, () => this.queryServiceList())}
style={{ marginRight: 10 }}
onClick={() => this.setState({currentPage: 1}, () => this.queryServiceList())}
style={{marginRight: 10}}
>{I18N.QUERY}</Button>
</FormItem>
<FormItem label="" style={{float: 'right'}}>
<Button type="secondary"
onClick={() => this.openEditServiceDialog()}>{I18N.CREATE}</Button>
</FormItem>
</Form>
</Col>
</Row>
<Row style={{ padding: 0 }}>
<Col span="24" style={{ padding: 0 }}>
<Row style={{padding: 0}}>
<Col span="24" style={{padding: 0}}>
<Table
dataSource={this.state.dataSource}
fixedHeader={true}
maxBodyHeight={530}
locale={locale}
language={aliwareIntl.currentLanguageCode}
className={r => this.rowColor[r.status]}
getRowProps={this.rowColor}
getRowProps={row => this.rowColor(row)}
>
<Column title={I18N.COLUMN_SERVICE_NAME} dataIndex="name" />
<Column title={I18N.COLUMN_CLUSTER_COUNT} dataIndex="clusterCount" />
<Column title={I18N.COLUMN_IP_COUNT} dataIndex="ipCount" />
<Column title={I18N.COLUMN_HEALTH_STATUS} dataIndex="status" />
<Column title={I18N.COLUMN_SERVICE_NAME} dataIndex="name"/>
<Column title={I18N.COLUMN_CLUSTER_COUNT} dataIndex="clusterCount"/>
<Column title={I18N.COLUMN_IP_COUNT} dataIndex="ipCount"/>
<Column title={I18N.COLUMN_HEALTH_STATUS} dataIndex="status"/>
<Column title={I18N.COLUMN_OPERATION} align="center" cell={(value, index, record) => (
<Button
type="normal"
onClick={() => this.props.history.push(`/serviceDetail?name=${record.name}`)}
>{I18N.DETAIL}</Button>
)} />
<div>
<Button
type="normal"
onClick={() => this.props.history.push(`/serviceDetail?name=${record.name}`)}
>{I18N.DETAIL}</Button>
<Button
style={{marginLeft: 12}}
type="normal"
onClick={() => this.deleteService(record.name)}
>{I18N.DELETE}</Button>
</div>
)}/>
</Table>
</Col>
</Row>
<div style={{ marginTop: 10, textAlign: 'right' }}>
<div style={{marginTop: 10, textAlign: 'right'}}>
<Pagination
current={this.state.currentPage}
total={this.state.total}
pageSize={this.state.pageSize}
onChange={currentPage => this.setState({ currentPage }, () => this.queryServiceList())}
onChange={currentPage => this.setState({currentPage}, () => this.queryServiceList())}
language={aliwareIntl.currentLanguageCode}
/>
</div>
</Loading>
<EditServiceDialog
ref="editServiceDialog"
openLoading={() => this.openLoading()}
closeLoading={() => this.closeLoading()}
queryServiceList={() => this.setState({currentPage: 1}, () => this.queryServiceList())}
/>
</div>
);
}

View File

@ -59,6 +59,26 @@ I18N.COLUMN_OPERATION = getI18N('table.column.operation')
* 详情
*/
I18N.DETAIL = getI18N('detail')
/**
* 删除
*/
I18N.DELETE = getI18N('delete')
/**
* 提示
*/
I18N.PROMPT = getI18N('prompt')
/**
* 提示
*/
I18N.PROMPT_DELETE = getI18N('prompt_delete')
/**
* 删除
*/
I18N.DELETE = getI18N('delete')
/**
* 创建服务
*/
I18N.CREATE = getI18N('create')
export const STATUS_COLOR_MAPPING = {
: 'green',

View File

@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
* @author xxc
*/
@SpringBootApplication
public class NamingApp {
public static void main(String[] args) {

View File

@ -17,6 +17,8 @@ package com.alibaba.nacos.naming.healthcheck;
import com.alibaba.fastjson.JSON;
import java.util.Map;
/**
* Metrics info of server
*
@ -33,6 +35,8 @@ public class RsInfo {
private String dom;
private String ak;
private String cluster;
private double weight;
private Map<String, String> metadata;
public String getDom() {
return dom;
@ -114,6 +118,22 @@ public class RsInfo {
this.mem = mem;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
public String toString() {
return JSON.toJSONString(this);
}

View File

@ -29,9 +29,7 @@ import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.*;
/**
* @author nacos
@ -117,6 +115,8 @@ public class UtilsAndCommons {
public static final ScheduledExecutorService INIT_CONFIG_EXECUTOR;
public static final Executor RAFT_PUBLISH_EXECUTOR;
static {
// custom serializer and deserializer for fast-json
SerializeConfig.getGlobalInstance()
@ -181,6 +181,17 @@ public class UtilsAndCommons {
}
});
RAFT_PUBLISH_EXECUTOR
= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("nacos.naming.raft.publisher");
t.setDaemon(true);
return t;
}
});
}
public static String getAllExceptionMsg(Throwable e) {

View File

@ -308,7 +308,8 @@ public class ApiCommands {
IpAddress ipAddress = new IpAddress();
ipAddress.setPort(port);
ipAddress.setIp(ip);
ipAddress.setWeight(1);
ipAddress.setWeight(clientBeat.getWeight());
ipAddress.setMetadata(clientBeat.getMetadata());
ipAddress.setClusterName(clusterName);
if (!virtualClusterDomain.allIPs().contains(ipAddress)) {
@ -553,11 +554,20 @@ public class ApiCommands {
if (virtualClusterDomain == null) {
regDom(request);
Lock lock = domainsManager.addLock(dom);
Condition condition = domainsManager.addCondtion(dom);
UtilsAndCommons.RAFT_PUBLISH_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
try {
regDom(request);
} catch (Exception e) {
Loggers.SRV_LOG.error("REG-SERIVCE", "register service failed, service:" + dom, e);
}
}
});
try {
lock.lock();
condition.await(5000, TimeUnit.MILLISECONDS);

View File

@ -15,10 +15,15 @@
*/
package com.alibaba.nacos.naming.core;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.naming.healthcheck.RsInfo;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
/**
* @author dungu.zpf
*/
@ -50,4 +55,18 @@ public class IpAddressTest {
Assert.assertEquals(2, ipAddress.getWeight(), 0.001);
Assert.assertEquals("TEST1", ipAddress.getClusterName());
}
@Test
public void rsInfo() {
RsInfo info = new RsInfo();
Map<String, String> metadata = new HashMap<>();
metadata.put("version", "2222");
info.setMetadata(metadata);
System.out.println(JSON.toJSONString(info));
String json = JSON.toJSONString(info);
RsInfo info1 = JSON.parseObject(json, RsInfo.class);
System.out.println(info1);
}
}