Merge branch '0.3.0' of https://github.com/alibaba/nacos into 0.3.0
# Conflicts: # console/src/main/resources/static/src/menu.js
This commit is contained in:
commit
d3f59f3b87
@ -36,6 +36,10 @@
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -125,4 +125,5 @@ public class Constants {
|
||||
|
||||
public static final String NAMING_INSTANCE_ID_SPLITTER = "#";
|
||||
public static final int NAMING_INSTANCE_ID_SEG_COUNT = 4;
|
||||
public static final String NAMING_HTTP_HEADER_SPILIER = "\\|";
|
||||
}
|
||||
|
@ -15,6 +15,13 @@
|
||||
*/
|
||||
package com.alibaba.nacos.api.naming.pojo;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -32,6 +39,14 @@ public abstract class AbstractHealthChecker implements Cloneable {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone all fields of this instance to another one
|
||||
*
|
||||
* @return Another instance with exactly the same fields.
|
||||
* @throws CloneNotSupportedException
|
||||
*/
|
||||
public abstract AbstractHealthChecker clone() throws CloneNotSupportedException;
|
||||
|
||||
public static class Http extends AbstractHealthChecker {
|
||||
public static final String TYPE = "HTTP";
|
||||
|
||||
@ -68,6 +83,25 @@ public abstract class AbstractHealthChecker implements Cloneable {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
@JSONField(serialize = false)
|
||||
public Map<String, String> getCustomHeaders() {
|
||||
if (StringUtils.isBlank(headers)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, String> headerMap = new HashMap<String, String>(16);
|
||||
for (String s : headers.split(Constants.NAMING_HTTP_HEADER_SPILIER)) {
|
||||
String[] splits = s.split(":");
|
||||
if (splits.length != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
headerMap.put(StringUtils.trim(splits[0]), StringUtils.trim(splits[1]));
|
||||
}
|
||||
|
||||
return headerMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(path, headers, expectedResponseCode);
|
||||
@ -93,6 +127,18 @@ public abstract class AbstractHealthChecker implements Cloneable {
|
||||
}
|
||||
return expectedResponseCode == other.getExpectedResponseCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http clone() throws CloneNotSupportedException {
|
||||
Http config = new Http();
|
||||
|
||||
config.setPath(this.getPath());
|
||||
config.setHeaders(this.getHeaders());
|
||||
config.setType(this.getType());
|
||||
config.setExpectedResponseCode(this.getExpectedResponseCode());
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Tcp extends AbstractHealthChecker {
|
||||
@ -112,6 +158,12 @@ public abstract class AbstractHealthChecker implements Cloneable {
|
||||
return obj instanceof Tcp;
|
||||
|
||||
}
|
||||
|
||||
public Tcp clone() throws CloneNotSupportedException {
|
||||
Tcp config = new Tcp();
|
||||
config.setType(this.type);
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Mysql extends AbstractHealthChecker {
|
||||
@ -173,9 +225,20 @@ public abstract class AbstractHealthChecker implements Cloneable {
|
||||
return strEquals(cmd, other.getCmd());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mysql clone() throws CloneNotSupportedException {
|
||||
Mysql config = new Mysql();
|
||||
config.setUser(this.getUser());
|
||||
config.setPwd(this.getPwd());
|
||||
config.setCmd(this.getCmd());
|
||||
config.setType(this.getType());
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean strEquals(String str1, String str2) {
|
||||
return str1 == null ? str2 == null : str1.equals(str2);
|
||||
}
|
||||
|
||||
private static boolean strEquals(String str1, String str2) {
|
||||
return str1 == null ? str2 == null : str1.equals(str2);
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ public class Instance {
|
||||
@JSONField(name = "valid")
|
||||
private boolean healthy = true;
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Cluster information of instance
|
||||
*/
|
||||
@ -146,6 +148,14 @@ public class Instance {
|
||||
this.metadata.put(key, value);
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
|
@ -43,6 +43,8 @@ public class HostReactor {
|
||||
|
||||
private Map<String, ServiceInfo> serviceInfoMap;
|
||||
|
||||
private Map<String, Object> updatingMap;
|
||||
|
||||
private PushRecver pushRecver;
|
||||
|
||||
private EventDispatcher eventDispatcher;
|
||||
@ -58,6 +60,7 @@ public class HostReactor {
|
||||
this.serverProxy = serverProxy;
|
||||
this.cacheDir = cacheDir;
|
||||
this.serviceInfoMap = new ConcurrentHashMap<String, ServiceInfo>(DiskCache.read(this.cacheDir));
|
||||
this.updatingMap = new ConcurrentHashMap<String, Object>();
|
||||
this.failoverReactor = new FailoverReactor(this, cacheDir);
|
||||
this.pushRecver = new PushRecver(this);
|
||||
}
|
||||
@ -218,12 +221,16 @@ public class HostReactor {
|
||||
|
||||
serviceInfoMap.put(serviceObj.getKey(), serviceObj);
|
||||
|
||||
updatingMap.put(serviceName, new Object());
|
||||
|
||||
if (allIPs) {
|
||||
updateService4AllIPNow(serviceName, clusters, env);
|
||||
} else {
|
||||
updateServiceNow(serviceName, clusters, env);
|
||||
}
|
||||
} else if (serviceObj.getHosts().isEmpty()) {
|
||||
updatingMap.remove(serviceName);
|
||||
|
||||
} else if (updatingMap.containsKey(serviceName)) {
|
||||
|
||||
if (updateHoldInterval > 0) {
|
||||
// hold a moment waiting for update finish
|
||||
|
@ -158,6 +158,7 @@ public class NamingProxy {
|
||||
params.put("ip", instance.getIp());
|
||||
params.put("port", String.valueOf(instance.getPort()));
|
||||
params.put("weight", String.valueOf(instance.getWeight()));
|
||||
params.put("enable", String.valueOf(instance.isEnabled()));
|
||||
params.put("healthy", String.valueOf(instance.isHealthy()));
|
||||
params.put("metadata", JSON.toJSONString(instance.getMetadata()));
|
||||
if (instance.getService() == null) {
|
||||
|
@ -110,7 +110,7 @@ window.i18ndoc = {
|
||||
"nacos.component.CloneDialog.target_space": "目标空间:",
|
||||
"com.alibaba.nacos.component.DiffEditorDialog.original_value": "原始值",
|
||||
"com.alibaba.nacos.page.configurationManagement.environment": "地域:",
|
||||
"nacos.page.configdetail.Description": "描述:",
|
||||
"nacos.page.configdetail.Description": "描述:",
|
||||
"com.alibaba.nacos.page.pushTrajectory.Data_Id_can_not_be_empty": "Data ID不能为空",
|
||||
"com.alibaba.nacos.page.listAllEnvironmental.Into_the": "进入",
|
||||
"com.alibaba.nacos.page.listeningToQuery._Push_state": "推送状态",
|
||||
@ -473,8 +473,42 @@ window.i18ndoc = {
|
||||
"com.alibaba.nacos.page.serviceManagement.service_list": "服务列表",
|
||||
"com.alibaba.nacos.page.serviceManagement.service_name": "服务名称",
|
||||
"com.alibaba.nacos.page.serviceManagement.please_enter_the_service_name": "请输入服务名称",
|
||||
"com.alibaba.nacos.page.serviceManagement.table.column.service_name": "服务名",
|
||||
"com.alibaba.nacos.page.serviceManagement.table.column.cluster_count": "集群数目",
|
||||
"com.alibaba.nacos.page.serviceManagement.table.column.ip_count": "IP数目",
|
||||
"com.alibaba.nacos.page.serviceManagement.table.column.health_status": "健康实例/所有实例",
|
||||
"com.alibaba.nacos.page.serviceManagement.table.column.operation": "操作",
|
||||
"com.alibaba.nacos.page.serviceManagement.query": "查询",
|
||||
"serviceManagement": "服务列表"
|
||||
"serviceManagement": "服务列表",
|
||||
"com.alibaba.nacos.page.serviceDetail.service_details": "服务详情",
|
||||
"com.alibaba.nacos.page.serviceDetail.edit_service": "编辑服务",
|
||||
"com.alibaba.nacos.page.serviceDetail.back": "返回",
|
||||
"com.alibaba.nacos.page.serviceDetail.service_name": "服务名",
|
||||
"com.alibaba.nacos.page.serviceDetail.protect_threshold": "保护阀值",
|
||||
"com.alibaba.nacos.page.serviceDetail.health_check_pattern": "健康检查模式",
|
||||
"com.alibaba.nacos.page.serviceDetail.health_check_pattern.service": "服务端",
|
||||
"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.update_service": "更新服务",
|
||||
"com.alibaba.nacos.page.serviceDetail.cluster": "集群",
|
||||
"com.alibaba.nacos.page.serviceDetail.edit_cluster": "集群配置",
|
||||
"com.alibaba.nacos.page.serviceDetail.port": "端口",
|
||||
"com.alibaba.nacos.page.serviceDetail.weight": "权重",
|
||||
"com.alibaba.nacos.page.serviceDetail.healthy": "健康状态",
|
||||
"com.alibaba.nacos.page.serviceDetail.operation": "操作",
|
||||
"com.alibaba.nacos.page.serviceDetail.editor": "编辑",
|
||||
"com.alibaba.nacos.page.serviceDetail.offline": "下线",
|
||||
"com.alibaba.nacos.page.serviceDetail.online": "上线",
|
||||
"com.alibaba.nacos.page.serviceDetail.check_type": "检查类型",
|
||||
"com.alibaba.nacos.page.serviceDetail.check_port": "检查端口",
|
||||
"com.alibaba.nacos.page.serviceDetail.use_ip_port_check": "使用IP端口检查",
|
||||
"com.alibaba.nacos.page.serviceDetail.check_path": "检查路径",
|
||||
"com.alibaba.nacos.page.serviceDetail.check_headers": "检查头",
|
||||
"com.alibaba.nacos.page.serviceDetail.update_cluster": "更新集群",
|
||||
"com.alibaba.nacos.page.serviceDetail.update_instance": "编辑实例",
|
||||
"com.alibaba.nacos.page.serviceDetail.whether_online": "是否上线",
|
||||
"serviceDetail": "服务详情"
|
||||
},
|
||||
"en-us": {
|
||||
"com.alibaba.nacos.layout.noenv.nacosversion":"1.0",
|
||||
@ -949,7 +983,41 @@ window.i18ndoc = {
|
||||
"com.alibaba.nacos.page.serviceManagement.service_list": "Service List",
|
||||
"com.alibaba.nacos.page.serviceManagement.service_name": "Service Name",
|
||||
"com.alibaba.nacos.page.serviceManagement.please_enter_the_service_name": "Enter Service Name",
|
||||
"com.alibaba.nacos.page.serviceManagement.table.column.service_name": "Service Name",
|
||||
"com.alibaba.nacos.page.serviceManagement.table.column.cluster_count": "Cluster Count",
|
||||
"com.alibaba.nacos.page.serviceManagement.table.column.ip_count": "IP Count",
|
||||
"com.alibaba.nacos.page.serviceManagement.table.column.health_status": "Healthy Instances/All Instances",
|
||||
"com.alibaba.nacos.page.serviceManagement.table.column.operation": "Operation",
|
||||
"com.alibaba.nacos.page.serviceManagement.query": "Search",
|
||||
"serviceManagement": "Service Management"
|
||||
"serviceManagement": "Service Management",
|
||||
"com.alibaba.nacos.page.serviceDetail.service_details": "Service Details",
|
||||
"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",
|
||||
"com.alibaba.nacos.page.serviceDetail.protect_threshold": "Protect Threshold",
|
||||
"com.alibaba.nacos.page.serviceDetail.health_check_pattern": "Health check pattern",
|
||||
"com.alibaba.nacos.page.serviceDetail.health_check_pattern.service": "Service",
|
||||
"com.alibaba.nacos.page.serviceDetail.health_check_pattern.client": "Client",
|
||||
"com.alibaba.nacos.page.serviceDetail.health_check_pattern.none": "None",
|
||||
"com.alibaba.nacos.page.serviceDetail.metadata": "Metadata",
|
||||
"com.alibaba.nacos.page.serviceDetail.update_service": "Update Service",
|
||||
"com.alibaba.nacos.page.serviceDetail.cluster": "Cluster",
|
||||
"com.alibaba.nacos.page.serviceDetail.edit_cluster": "Edit Cluster",
|
||||
"com.alibaba.nacos.page.serviceDetail.port": "Port",
|
||||
"com.alibaba.nacos.page.serviceDetail.weight": "Weight",
|
||||
"com.alibaba.nacos.page.serviceDetail.healthy": "Healthy",
|
||||
"com.alibaba.nacos.page.serviceDetail.operation": "Operation",
|
||||
"com.alibaba.nacos.page.serviceDetail.editor": "Edit",
|
||||
"com.alibaba.nacos.page.serviceDetail.offline": "Offline",
|
||||
"com.alibaba.nacos.page.serviceDetail.online": "Online",
|
||||
"com.alibaba.nacos.page.serviceDetail.check_type": "Check Type",
|
||||
"com.alibaba.nacos.page.serviceDetail.check_port": "Check Port",
|
||||
"com.alibaba.nacos.page.serviceDetail.use_ip_port_check": "Use port of IP",
|
||||
"com.alibaba.nacos.page.serviceDetail.check_path": "Check Path",
|
||||
"com.alibaba.nacos.page.serviceDetail.check_headers": "Check Headers",
|
||||
"com.alibaba.nacos.page.serviceDetail.update_cluster": "Update Cluster",
|
||||
"com.alibaba.nacos.page.serviceDetail.update_instance": "Update Instance",
|
||||
"com.alibaba.nacos.page.serviceDetail.whether_online": "Whether Online",
|
||||
"serviceDetail": "Service Details"
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
|
||||
|
||||
}
|
||||
.righttitle {
|
||||
height: 40px;
|
||||
@ -423,7 +423,7 @@ form.vertical-margin-lg .form-group {
|
||||
}*/
|
||||
|
||||
.xrange-container {
|
||||
position: relative;
|
||||
position: relative;
|
||||
border: 1px solid #ccc;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@ -464,7 +464,7 @@ form.vertical-margin-lg .form-group {
|
||||
min-width: 100px;
|
||||
display: inline-flex;
|
||||
margin-bottom: 8px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.xrange-layer {
|
||||
@ -493,7 +493,7 @@ form.vertical-margin-lg .form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
box-sizing: content-box !important;
|
||||
box-sizing: content-box !important;
|
||||
align-items: center; }
|
||||
.xrange-panel .quick-list > span {
|
||||
flex: 0 0 auto;
|
||||
@ -1037,6 +1037,9 @@ form.vertical-margin-lg .form-group {
|
||||
margin: 10px 0 10px 0;
|
||||
}
|
||||
.alert-success {
|
||||
border-color: #E0E0E0!important;
|
||||
border-color: #E0E0E0!important;
|
||||
}
|
||||
|
||||
.main-container{
|
||||
padding: 10px;
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ class HistoryRollback extends React.Component {
|
||||
return (
|
||||
<div style={{ padding: 10 }}>
|
||||
<Loading shape="flower" style={{ position: 'relative', width: "100%" }} visible={this.state.loading} tip="Loading..." color="#333">
|
||||
<RegionGroup left={<h5 style={{ borderLeft: '2px solid rgb(136, 183, 224)', textIndent: 8, lineHeight: '32px', marginTop: 8, fontSize: '16px' }}>{window.aliwareIntl.get('com.alibaba.nacos.page.historyRollback.to_configure')}</h5>} namespaceCallBack={this.cleanAndGetData.bind(this)} />
|
||||
<RegionGroup left={window.aliwareIntl.get('com.alibaba.nacos.page.historyRollback.to_configure')} namespaceCallBack={this.cleanAndGetData.bind(this)} />
|
||||
{/**<div className={'namespacewrapper'}>
|
||||
<NameSpaceList namespaceCallBack={this.cleanAndGetData.bind(this)} />
|
||||
</div>**/}
|
||||
|
@ -31,7 +31,9 @@ class Namespace extends React.Component {
|
||||
url: `/nacos/v1/console/namespaces`,
|
||||
success: res => {
|
||||
if (res.code === 200) {
|
||||
let data = res.data;
|
||||
let data = res.data || [];
|
||||
window.namespaceList = data;
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (data[i].type === 1) {
|
||||
this.setState({
|
||||
@ -86,6 +88,7 @@ class Namespace extends React.Component {
|
||||
success: res => {
|
||||
if (res !== null) {
|
||||
Dialog.alert({
|
||||
style: { width: "500px" },
|
||||
needWrapper: false,
|
||||
language: window.pageLanguage || 'zh-cn',
|
||||
title: window.aliwareIntl.get('nacos.page.namespace.Namespace_details'),
|
||||
@ -245,7 +248,7 @@ class Namespace extends React.Component {
|
||||
<div>
|
||||
<div style={{ textAlign: 'right', marginBottom: 10 }}>
|
||||
|
||||
<Button type="primary" style={{ marginRight: 20, marginTop: 10 }} onClick={this.addNameSpace.bind(this)}>{window.aliwareIntl.get('com.alibaba.nacos.page.namespace.add')}</Button>
|
||||
<Button type="primary" style={{ marginRight: 0, marginTop: 10 }} onClick={this.addNameSpace.bind(this)}>{window.aliwareIntl.get('com.alibaba.nacos.page.namespace.add')}</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Table dataSource={this.state.dataSource} locale={locale} language={window.aliwareIntl.currentLanguageCode}>
|
||||
|
@ -0,0 +1,155 @@
|
||||
import React from 'react';
|
||||
import {Dialog, Form, Input, Switch, Select, Message} from '@alifd/next';
|
||||
import {I18N, DIALOG_FORM_LAYOUT} from './constant'
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
|
||||
class EditClusterDialog extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
editCluster: {},
|
||||
editClusterDialogVisible: false
|
||||
}
|
||||
this.show = this.show.bind(this)
|
||||
}
|
||||
|
||||
show(editCluster) {
|
||||
const {metadata = {}} = editCluster
|
||||
editCluster.metadataText = Object.keys(metadata).map(k => `${k}=${metadata[k]}`).join(',')
|
||||
this.setState({
|
||||
editCluster,
|
||||
editClusterDialogVisible: true
|
||||
})
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.setState({editClusterDialogVisible: false})
|
||||
}
|
||||
|
||||
onConfirm() {
|
||||
const {openLoading, closeLoading, getServiceDetail} = this.props
|
||||
const {name, serviceName, metadataText, defaultCheckPort, useIPPort4Check, healthChecker} = this.state.editCluster
|
||||
window.request({
|
||||
method: 'POST',
|
||||
url: '/nacos/v1/ns/cluster/update',
|
||||
data: {
|
||||
serviceName,
|
||||
clusterName: name,
|
||||
metadata: metadataText,
|
||||
checkPort: defaultCheckPort,
|
||||
useInstancePort4Check: useIPPort4Check,
|
||||
healthChecker: JSON.stringify(healthChecker)
|
||||
},
|
||||
dataType: 'text',
|
||||
beforeSend: () => openLoading(),
|
||||
success: res => {
|
||||
if (res !== 'ok') {
|
||||
Message.error(res)
|
||||
return
|
||||
}
|
||||
this.hide()
|
||||
getServiceDetail()
|
||||
},
|
||||
complete: () => closeLoading()
|
||||
})
|
||||
}
|
||||
|
||||
onChangeCluster(changeVal) {
|
||||
const {editCluster = {}} = this.state
|
||||
this.setState({
|
||||
editCluster: Object.assign({}, editCluster, changeVal)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const {editCluster = {}, editClusterDialogVisible} = this.state
|
||||
const {
|
||||
healthChecker = {},
|
||||
useIPPort4Check,
|
||||
defaultCheckPort = '80',
|
||||
metadataText = ''
|
||||
} = editCluster
|
||||
const {type, path, headers} = healthChecker
|
||||
const healthCheckerChange = changeVal => this.onChangeCluster({
|
||||
healthChecker: Object.assign({}, healthChecker, changeVal)
|
||||
})
|
||||
return (
|
||||
<Dialog
|
||||
className="cluster-edit-dialog"
|
||||
title={I18N.UPDATE_CLUSTER}
|
||||
visible={editClusterDialogVisible}
|
||||
onOk={() => this.onConfirm()}
|
||||
onCancel={() => this.hide()}
|
||||
onClose={() => this.hide()}
|
||||
>
|
||||
<Form {...DIALOG_FORM_LAYOUT}>
|
||||
<FormItem label={`${I18N.CHECK_TYPE}:`}>
|
||||
<Select
|
||||
className="in-select"
|
||||
defaultValue={type}
|
||||
onChange={type => healthCheckerChange({type})}
|
||||
>
|
||||
<Option value="TCP">TCP</Option>
|
||||
<Option value="HTTP">HTTP</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.CHECK_PORT}:`}>
|
||||
<Input className="in-text"
|
||||
value={defaultCheckPort}
|
||||
onChange={defaultCheckPort => this.onChangeCluster({defaultCheckPort})}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.USE_IP_PORT_CHECK}:`}>
|
||||
<Switch
|
||||
checked={useIPPort4Check}
|
||||
onChange={useIPPort4Check => this.onChangeCluster({useIPPort4Check})}
|
||||
/>
|
||||
</FormItem>
|
||||
{
|
||||
type === 'HTTP'
|
||||
? (<div>
|
||||
<div className="next-row next-form-item next-left next-medium">
|
||||
<div className="next-col next-col-fixed-12 next-form-item-label">
|
||||
<label>{`${I18N.CHECK_PATH}:`}</label>
|
||||
</div>
|
||||
<div className="next-col next-col-12 next-form-item-control">
|
||||
<Input
|
||||
className="in-text"
|
||||
value={path}
|
||||
onChange={path => healthCheckerChange({path})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="next-row next-form-item next-left next-medium">
|
||||
<div className="next-col next-col-fixed-12 next-form-item-label">
|
||||
<label>{`${I18N.CHECK_HEADERS}:`}</label>
|
||||
</div>
|
||||
<div className="next-col next-col-12 next-form-item-control">
|
||||
<Input
|
||||
className="in-text"
|
||||
value={headers}
|
||||
onChange={headers => healthCheckerChange({headers})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>)
|
||||
: null
|
||||
}
|
||||
<FormItem label={`${I18N.METADATA}:`}>
|
||||
<Input
|
||||
className="in-text"
|
||||
value={metadataText}
|
||||
onChange={metadataText => this.onChangeCluster({metadataText})}
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 主体代码请写在此行上面的class中, 组件导出语句及其他信息请写在此行下面*****************************/
|
||||
export default EditClusterDialog;
|
@ -0,0 +1,102 @@
|
||||
import React from 'react';
|
||||
import {Dialog, Form, Input, Switch, Message} from '@alifd/next';
|
||||
import {I18N, DIALOG_FORM_LAYOUT} from './constant'
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
|
||||
class EditInstanceDialog extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
editInstance: {},
|
||||
editInstanceDialogVisible: false
|
||||
}
|
||||
this.show = this.show.bind(this)
|
||||
}
|
||||
|
||||
show(editInstance) {
|
||||
const {metadata = {}} = editInstance
|
||||
if (Object.keys(metadata).length) {
|
||||
editInstance.metadataText = Object.keys(metadata).map(k => `${k}=${metadata[k]}`).join(',')
|
||||
}
|
||||
this.setState({editInstance, editInstanceDialogVisible: true})
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.setState({editInstanceDialogVisible: false})
|
||||
}
|
||||
|
||||
onConfirm() {
|
||||
const {serviceName, clusterName, getInstanceList, openLoading, closeLoading} = this.props
|
||||
const {ip, port, weight, enabled, metadataText} = this.state.editInstance
|
||||
window.request({
|
||||
method: 'POST',
|
||||
url: '/nacos/v1/ns/instance/update',
|
||||
data: {serviceName, clusterName, ip, port, weight, enable: enabled, metadata: metadataText},
|
||||
dataType: 'text',
|
||||
beforeSend: () => openLoading(),
|
||||
success: res => {
|
||||
if (res !== 'ok') {
|
||||
Message.error(res)
|
||||
return
|
||||
}
|
||||
this.hide()
|
||||
getInstanceList()
|
||||
},
|
||||
complete: () => closeLoading()
|
||||
})
|
||||
}
|
||||
|
||||
onChangeCluster(changeVal) {
|
||||
const {editInstance = {}} = this.state
|
||||
this.setState({
|
||||
editInstance: Object.assign({}, editInstance, changeVal)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const {editInstanceDialogVisible, editInstance} = this.state
|
||||
return (
|
||||
<Dialog
|
||||
className="instance-edit-dialog"
|
||||
title={I18N.UPDATE_INSTANCE}
|
||||
visible={editInstanceDialogVisible}
|
||||
onOk={() => this.onConfirm()}
|
||||
onCancel={() => this.hide()}
|
||||
onClose={() => this.hide()}
|
||||
>
|
||||
<Form {...DIALOG_FORM_LAYOUT}>
|
||||
<FormItem label="IP:">
|
||||
<p>{editInstance.ip}</p>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.PORT}:`}>
|
||||
<p>{editInstance.port}</p>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.WEIGHT}:`}>
|
||||
<Input
|
||||
className="in-text"
|
||||
value={editInstance.weight}
|
||||
onChange={weight => this.onChangeCluster({weight})}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.WHETHER_ONLINE}:`}>
|
||||
<Switch
|
||||
checked={editInstance.enabled}
|
||||
onChange={enabled => this.onChangeCluster({enabled})}/>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.METADATA}:`}>
|
||||
<Input
|
||||
className="in-text"
|
||||
value={editInstance.metadataText}
|
||||
onChange={metadataText => this.onChangeCluster({metadataText})}
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 主体代码请写在此行上面的class中, 组件导出语句及其他信息请写在此行下面*****************************/
|
||||
export default EditInstanceDialog;
|
@ -0,0 +1,112 @@
|
||||
import React from 'react';
|
||||
import {Dialog, Form, Input, Select, Message} from '@alifd/next';
|
||||
import {I18N, DIALOG_FORM_LAYOUT} from './constant'
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
|
||||
class EditServiceDialog extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
editService: {},
|
||||
editServiceDialogVisible: false
|
||||
}
|
||||
this.show = this.show.bind(this)
|
||||
}
|
||||
|
||||
show(editService) {
|
||||
const {metadata = {}} = editService
|
||||
if (Object.keys(metadata).length) {
|
||||
editService.metadataText = Object.keys(metadata).map(k => `${k}=${metadata[k]}`).join(',')
|
||||
}
|
||||
this.setState({editService, editServiceDialogVisible: true})
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.setState({editServiceDialogVisible: false})
|
||||
}
|
||||
|
||||
onConfirm() {
|
||||
const editService = Object.assign({}, this.state.editService)
|
||||
const {name, protectThreshold, healthCheckMode, metadataText} = editService
|
||||
window.request({
|
||||
method: 'POST',
|
||||
url: '/nacos/v1/ns/service/update',
|
||||
data: {serviceName: name, protectThreshold, healthCheckMode, metadata: metadataText},
|
||||
dataType: 'text',
|
||||
beforeSend: () => this.setState({loading: true}),
|
||||
success: res => {
|
||||
if (res !== 'ok') {
|
||||
Message.error(res)
|
||||
return
|
||||
}
|
||||
this.props.getServiceDetail()
|
||||
},
|
||||
complete: () => this.setState({loading: false})
|
||||
})
|
||||
this.hide()
|
||||
}
|
||||
|
||||
onChangeCluster(changeVal) {
|
||||
const {editService = {}} = this.state
|
||||
this.setState({
|
||||
editService: Object.assign({}, editService, changeVal)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const {editService, editServiceDialogVisible} = this.state
|
||||
const {
|
||||
name,
|
||||
protectThreshold,
|
||||
healthCheckMode,
|
||||
metadataText
|
||||
} = editService
|
||||
return (
|
||||
<Dialog
|
||||
className="service-detail-edit-dialog"
|
||||
title={I18N.UPDATE_SERVICE}
|
||||
visible={editServiceDialogVisible}
|
||||
onOk={() => this.onConfirm()}
|
||||
onCancel={() => this.hide()}
|
||||
onClose={() => this.hide()}
|
||||
>
|
||||
<Form {...DIALOG_FORM_LAYOUT}>
|
||||
<FormItem label={`${I18N.SERVICE_NAME}:`}>
|
||||
<p>{name}</p>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.PROTECT_THRESHOLD}:`}>
|
||||
<Input
|
||||
className="in-text"
|
||||
value={protectThreshold}
|
||||
onChange={protectThreshold => this.onChangeCluster({protectThreshold})}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.HEALTH_CHECK_PATTERN}:`}>
|
||||
<Select
|
||||
className="in-select"
|
||||
defaultValue={healthCheckMode}
|
||||
onChange={healthCheckMode => this.onChangeCluster({healthCheckMode})}
|
||||
>
|
||||
<Option value="server">{I18N.HEALTH_CHECK_PATTERN_SERVICE}</Option>
|
||||
<Option value="client">{I18N.HEALTH_CHECK_PATTERN_CLIENT}</Option>
|
||||
<Option value="none">{I18N.HEALTH_CHECK_PATTERN_NONE}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.METADATA}:`}>
|
||||
<Input
|
||||
className="in-text"
|
||||
value={metadataText}
|
||||
onChange={metadataText => this.onChangeCluster({metadataText})}
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 主体代码请写在此行上面的class中, 组件导出语句及其他信息请写在此行下面*****************************/
|
||||
export default EditServiceDialog;
|
@ -0,0 +1,132 @@
|
||||
import React from 'react';
|
||||
import {Button, Pagination, Table} from '@alifd/next';
|
||||
import {I18N} from './constant'
|
||||
import EditInstanceDialog from "./EditInstanceDialog";
|
||||
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
|
||||
class InstanceTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
loading: false,
|
||||
instance: {count: 0, list: []},
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getInstanceList()
|
||||
}
|
||||
|
||||
openLoading() {
|
||||
this.setState({loading: true})
|
||||
}
|
||||
|
||||
closeLoading() {
|
||||
this.setState({loading: false})
|
||||
}
|
||||
|
||||
getInstanceList() {
|
||||
const {clusterName, serviceName} = this.props
|
||||
if (!clusterName) return
|
||||
const {pageSize, pageNum} = this.state
|
||||
window.request({
|
||||
url: '/nacos/v1/ns/catalog/instanceList',
|
||||
data: {
|
||||
serviceName,
|
||||
clusterName,
|
||||
pgSize: pageSize,
|
||||
startPg: pageNum
|
||||
},
|
||||
beforeSend: () => this.openLoading(),
|
||||
success: instance => this.setState({instance}),
|
||||
complete: () => this.closeLoading()
|
||||
})
|
||||
}
|
||||
|
||||
openInstanceDialog(instance) {
|
||||
this.refs.editInstanceDialog.show(instance)
|
||||
}
|
||||
|
||||
switchState(index, record) {
|
||||
const {instance} = this.state
|
||||
const {ip, port, weight, enabled} = record
|
||||
const {clusterName, serviceName} = this.props
|
||||
const newVal = Object.assign({}, instance)
|
||||
newVal.list[index]['enabled'] = !enabled
|
||||
window.request({
|
||||
method: 'POST',
|
||||
url: '/nacos/v1/ns/instance/update',
|
||||
data: {serviceName, clusterName, ip, port, weight, enable: !enabled},
|
||||
dataType: 'text',
|
||||
beforeSend: () => this.openLoading(),
|
||||
success: () => this.setState({instance: newVal}),
|
||||
complete: () => this.closeLoading()
|
||||
})
|
||||
}
|
||||
|
||||
onChangePage(pageNum) {
|
||||
this.setState({pageNum}, () => this.getInstanceList())
|
||||
}
|
||||
|
||||
render() {
|
||||
const {clusterName, serviceName} = this.props
|
||||
const {instance, pageSize, loading} = this.state
|
||||
return instance.count ? (
|
||||
<div>
|
||||
<Table dataSource={instance.list} loading={loading}>
|
||||
<Table.Column title="IP" dataIndex="ip"/>
|
||||
<Table.Column title={I18N.PORT} dataIndex="port"/>
|
||||
<Table.Column title={I18N.WEIGHT} dataIndex="weight"/>
|
||||
<Table.Column title={I18N.HEALTHY} dataIndex="healthy" cell={val => `${val}`}/>
|
||||
<Table.Column
|
||||
title={I18N.METADATA}
|
||||
dataIndex="metadata"
|
||||
cell={metadata => Object.keys(metadata).map(k => `${k}=${metadata[k]}`).join(',')}
|
||||
/>
|
||||
<Table.Column
|
||||
title={I18N.OPERATION}
|
||||
width={150}
|
||||
cell={(value, index, record) => (
|
||||
<div>
|
||||
<Button
|
||||
type="normal"
|
||||
className="edit-btn"
|
||||
onClick={() => this.openInstanceDialog(record)}
|
||||
>{I18N.EDITOR}</Button>
|
||||
<Button
|
||||
type={record.enabled ? 'normal' : 'secondary'}
|
||||
onClick={() => this.switchState(index, record)}
|
||||
>{I18N[record.enabled ? 'OFFLINE' : 'ONLINE']}</Button>
|
||||
</div>
|
||||
)}/>
|
||||
</Table>
|
||||
{
|
||||
instance.count > pageSize
|
||||
? (
|
||||
<Pagination
|
||||
className="pagination"
|
||||
total={instance.count}
|
||||
pageSize={pageSize}
|
||||
onChange={currentPage => this.onChangePage(currentPage)}
|
||||
/>
|
||||
)
|
||||
: null
|
||||
}
|
||||
<EditInstanceDialog
|
||||
ref="editInstanceDialog"
|
||||
serviceName={serviceName}
|
||||
clusterName={clusterName}
|
||||
openLoading={()=>this.openLoading()}
|
||||
closeLoading={()=>this.closeLoading()}
|
||||
getInstanceList={() => this.getInstanceList()}
|
||||
/>
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 主体代码请写在此行上面的class中, 组件导出语句及其他信息请写在此行下面*****************************/
|
||||
export default InstanceTable;
|
@ -0,0 +1,151 @@
|
||||
import React from 'react';
|
||||
import {Button, Card, Form, Loading} from '@alifd/next';
|
||||
import EditServiceDialog from './EditServiceDialog'
|
||||
import EditClusterDialog from './EditClusterDialog'
|
||||
import InstanceTable from './InstanceTable'
|
||||
import queryString from 'query-string'
|
||||
import {I18N} from './constant'
|
||||
import './ServiceDetail.less'
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const pageFormLayout = {
|
||||
labelCol: {fixedSpan: 10},
|
||||
wrapperCol: {span: 14}
|
||||
};
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
|
||||
class ServiceDetail extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
serviceName: queryString.parse(props.location.search).name,
|
||||
loading: false,
|
||||
currentPage: 1,
|
||||
clusters: [],
|
||||
instances: {},
|
||||
service: {},
|
||||
pageSize: 10,
|
||||
pageNum: {}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.state.serviceName) {
|
||||
this.props.history.goBack()
|
||||
return
|
||||
}
|
||||
this.getServiceDetail()
|
||||
}
|
||||
|
||||
getServiceDetail() {
|
||||
const {serviceName} = this.state
|
||||
window.request({
|
||||
url: `/nacos/v1/ns/catalog/serviceDetail?serviceName=${serviceName}`,
|
||||
beforeSend: () => this.openLoading(),
|
||||
success: ({clusters = [], service = {}}) => this.setState({service, clusters}),
|
||||
complete: () => this.closeLoading()
|
||||
})
|
||||
}
|
||||
|
||||
openLoading() {
|
||||
this.setState({loading: true})
|
||||
}
|
||||
|
||||
closeLoading() {
|
||||
this.setState({loading: false})
|
||||
}
|
||||
|
||||
openEditServiceDialog() {
|
||||
this.refs.editServiceDialog.show(this.state.service)
|
||||
}
|
||||
|
||||
openClusterDialog(cluster) {
|
||||
this.refs.editClusterDialog.show(cluster)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {serviceName, loading, service = {}, clusters} = this.state
|
||||
const {metadata = {}} = service
|
||||
const metadataText = Object.keys(metadata).map(key => `${key}=${metadata[key]}`).join(',')
|
||||
return (
|
||||
<div className="main-container service-detail">
|
||||
<Loading
|
||||
shape={"flower"}
|
||||
tip={"Loading..."}
|
||||
className="loading"
|
||||
visible={loading}
|
||||
color={"#333"}
|
||||
>
|
||||
<h1 style={{
|
||||
position: 'relative',
|
||||
width: '100%'
|
||||
}}>
|
||||
{I18N.SERVICE_DETAILS}
|
||||
<Button
|
||||
type="primary"
|
||||
className="header-btn"
|
||||
onClick={() => this.props.history.goBack()}
|
||||
>{I18N.BACK}</Button>
|
||||
<Button
|
||||
type="normal"
|
||||
className="header-btn"
|
||||
onClick={() => this.openEditServiceDialog()}
|
||||
>{I18N.EDIT_SERVICE}</Button>
|
||||
</h1>
|
||||
|
||||
<Form style={{width: '60%'}} {...pageFormLayout}>
|
||||
<FormItem label={`${I18N.SERVICE_NAME}:`}>
|
||||
<p>{service.name}</p>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.PROTECT_THRESHOLD}:`}>
|
||||
<p>{service.protectThreshold}</p>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.HEALTH_CHECK_PATTERN}:`}>
|
||||
<p>{service.healthCheckMode}</p>
|
||||
</FormItem>
|
||||
<FormItem label={`${I18N.METADATA}:`}>
|
||||
<p>{metadataText}</p>
|
||||
</FormItem>
|
||||
</Form>
|
||||
{
|
||||
clusters.map(cluster => (
|
||||
<Card
|
||||
key={cluster.name}
|
||||
className="cluster-card"
|
||||
title={`${I18N.CLUSTER}:`}
|
||||
subTitle={cluster.name}
|
||||
contentHeight="auto"
|
||||
extra={(
|
||||
<Button
|
||||
type="normal"
|
||||
onClick={() => this.openClusterDialog(cluster)}
|
||||
>{I18N.EDIT_CLUSTER}</Button>
|
||||
)}
|
||||
>
|
||||
<InstanceTable
|
||||
clusterName={cluster.name}
|
||||
serviceName={serviceName}
|
||||
/>
|
||||
</Card>
|
||||
))
|
||||
}
|
||||
</Loading>
|
||||
<EditServiceDialog
|
||||
ref="editServiceDialog"
|
||||
openLoading={() => this.openLoading()}
|
||||
closeLoading={() => this.closeLoading()}
|
||||
getServiceDetail={() => this.getServiceDetail()}
|
||||
/>
|
||||
<EditClusterDialog
|
||||
ref="editClusterDialog"
|
||||
openLoading={() => this.openLoading()}
|
||||
closeLoading={() => this.closeLoading()}
|
||||
getServiceDetail={() => this.getServiceDetail()}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 主体代码请写在此行上面的class中, 组件导出语句及其他信息请写在此行下面*****************************/
|
||||
export default ServiceDetail;
|
@ -0,0 +1,39 @@
|
||||
.service-detail {
|
||||
.header-btn {
|
||||
float: right;
|
||||
margin-left: 20px;
|
||||
}
|
||||
.edit-btn {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.next-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.loading {
|
||||
position: relative;
|
||||
width: 100%
|
||||
}
|
||||
.pagination {
|
||||
float: right;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.cluster-card {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.service-detail-edit-dialog, .instance-edit-dialog, .cluster-edit-dialog {
|
||||
.next-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.next-col-fixed-12 {
|
||||
flex: 1;
|
||||
}
|
||||
.next-switch-off {
|
||||
background-color: #F2F3F7;
|
||||
border-color: #C4C6CF;
|
||||
}
|
||||
.in-text, .in-select {
|
||||
width: 120px;
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
const getI18N = (key, prefix = 'com.alibaba.nacos.page.serviceDetail.') => window.aliwareIntl.get(prefix + key)
|
||||
export const I18N = {}
|
||||
/**
|
||||
* 服务列表
|
||||
*/
|
||||
I18N.SERVICE_DETAILS = getI18N('service_details')
|
||||
/**
|
||||
* 编辑服务
|
||||
*/
|
||||
I18N.EDIT_SERVICE = getI18N('edit_service')
|
||||
/**
|
||||
* 返回
|
||||
*/
|
||||
I18N.BACK = getI18N('back')
|
||||
/**
|
||||
* 服务名
|
||||
*/
|
||||
I18N.SERVICE_NAME = getI18N('service_name')
|
||||
/**
|
||||
* 保护阀值
|
||||
*/
|
||||
I18N.PROTECT_THRESHOLD = getI18N('protect_threshold')
|
||||
/**
|
||||
* 健康检查模式
|
||||
*/
|
||||
I18N.HEALTH_CHECK_PATTERN = getI18N('health_check_pattern')
|
||||
/**
|
||||
* 健康检查模式 - 服务端
|
||||
*/
|
||||
I18N.HEALTH_CHECK_PATTERN_SERVICE = getI18N('health_check_pattern.service')
|
||||
/**
|
||||
* 健康检查模式 - 客户端
|
||||
*/
|
||||
I18N.HEALTH_CHECK_PATTERN_CLIENT = getI18N('health_check_pattern.client')
|
||||
/**
|
||||
* 健康检查模式 - 禁止
|
||||
*/
|
||||
I18N.HEALTH_CHECK_PATTERN_NONE = getI18N('health_check_pattern.none')
|
||||
/**
|
||||
* 元数据
|
||||
*/
|
||||
I18N.METADATA = getI18N('metadata')
|
||||
/**
|
||||
* 更新服务
|
||||
*/
|
||||
I18N.UPDATE_SERVICE = getI18N('update_service')
|
||||
/**
|
||||
* 集群
|
||||
*/
|
||||
I18N.CLUSTER = getI18N('cluster')
|
||||
/**
|
||||
* 端口
|
||||
*/
|
||||
I18N.PORT = getI18N('port')
|
||||
/**
|
||||
* 权重
|
||||
*/
|
||||
I18N.WEIGHT = getI18N('weight')
|
||||
/**
|
||||
* 健康状态
|
||||
*/
|
||||
I18N.HEALTHY = getI18N('healthy')
|
||||
/**
|
||||
* 操作
|
||||
*/
|
||||
I18N.OPERATION = getI18N('operation')
|
||||
/**
|
||||
* 编辑
|
||||
*/
|
||||
I18N.EDITOR = getI18N('editor')
|
||||
/**
|
||||
* 上线
|
||||
*/
|
||||
I18N.ONLINE = getI18N('online')
|
||||
/**
|
||||
* 下线
|
||||
*/
|
||||
I18N.OFFLINE = getI18N('offline')
|
||||
/**
|
||||
* 集群配置
|
||||
*/
|
||||
I18N.EDIT_CLUSTER = getI18N('edit_cluster')
|
||||
/**
|
||||
* 检查类型
|
||||
*/
|
||||
I18N.CHECK_TYPE = getI18N('check_type')
|
||||
/**
|
||||
* 检查端口
|
||||
*/
|
||||
I18N.CHECK_PORT = getI18N('check_port')
|
||||
/**
|
||||
* 使用IP端口检查
|
||||
*/
|
||||
I18N.USE_IP_PORT_CHECK = getI18N('use_ip_port_check')
|
||||
/**
|
||||
* 检查路径
|
||||
*/
|
||||
I18N.CHECK_PATH = getI18N('check_path')
|
||||
/**
|
||||
* 检查头
|
||||
*/
|
||||
I18N.CHECK_HEADERS = getI18N('check_headers')
|
||||
/**
|
||||
* 更新集群
|
||||
*/
|
||||
I18N.UPDATE_CLUSTER = getI18N('update_cluster')
|
||||
/**
|
||||
* 编辑实例
|
||||
*/
|
||||
I18N.UPDATE_INSTANCE = getI18N('update_instance')
|
||||
/**
|
||||
* 是否上线
|
||||
*/
|
||||
I18N.WHETHER_ONLINE = getI18N('whether_online')
|
||||
|
||||
export const DIALOG_FORM_LAYOUT = {
|
||||
labelCol: {fixedSpan: 12},
|
||||
wrapperCol: {span: 12}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
import ServiceDetail from './ServiceDetail'
|
||||
|
||||
export default ServiceDetail
|
@ -1,33 +1,13 @@
|
||||
import React from 'react';
|
||||
import RegionGroup from '../components/RegionGroup' ;
|
||||
import RegionGroup from '../../components/RegionGroup' ;
|
||||
import {Button, Field, Form, Grid, Input, Loading, Pagination, Table} from '@alifd/next';
|
||||
import {I18N, STATUS_COLOR_MAPPING} from './constant'
|
||||
import './ServiceManagement.less'
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const {Row, Col} = Grid;
|
||||
const {Column} = Table
|
||||
|
||||
const getI18N = (key, prefix = 'com.alibaba.nacos.page.serviceManagement.') => window.aliwareIntl.get(prefix + key)
|
||||
/**
|
||||
* 服务列表
|
||||
*/
|
||||
const I18N_SERVICE_LIST = getI18N('service_list')
|
||||
/**
|
||||
* 服务名称
|
||||
*/
|
||||
const I18N_SERVICE_NAME = getI18N('service_name')
|
||||
/**
|
||||
* 请输入服务名称
|
||||
*/
|
||||
const I18N_ENTER_SERVICE_NAME = getI18N('please_enter_the_service_name')
|
||||
/**
|
||||
* 查询
|
||||
*/
|
||||
const I18N_QUERY = window.aliwareIntl.get('com.alibaba.nacos.page.serviceManagement.query')
|
||||
/**
|
||||
* 查询
|
||||
*/
|
||||
const I18N_PUBNODEDATA = window.aliwareIntl.get('pubnodedata', '')
|
||||
|
||||
/*****************************此行为标记行, 请勿删和修改此行, 文件和组件依赖请写在此行上面, 主体代码请写在此行下面的class中*****************************/
|
||||
class ServiceManagement extends React.Component {
|
||||
constructor(props) {
|
||||
@ -43,9 +23,6 @@ class ServiceManagement extends React.Component {
|
||||
this.field = new Field(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
}
|
||||
|
||||
openLoading() {
|
||||
this.setState({loading: true})
|
||||
}
|
||||
@ -77,15 +54,17 @@ class ServiceManagement extends React.Component {
|
||||
setTimeout(() => this.queryServiceList());
|
||||
}
|
||||
|
||||
rowColor = ({status}) => ({className: `row-bg-${STATUS_COLOR_MAPPING[status]}`})
|
||||
|
||||
render() {
|
||||
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 style={{padding: 10}}>
|
||||
<div className="main-container service-management">
|
||||
<Loading
|
||||
shape="flower"
|
||||
style={{position: 'relative'}}
|
||||
@ -94,15 +73,15 @@ class ServiceManagement extends React.Component {
|
||||
color="#333"
|
||||
>
|
||||
<RegionGroup
|
||||
left={I18N_SERVICE_LIST}
|
||||
left={I18N.SERVICE_LIST}
|
||||
namespaceCallBack={this.getQueryLater.bind(this)}
|
||||
/>
|
||||
<Row className="demo-row" style={{marginBottom: 10, padding: 0}}>
|
||||
<Col span="24">
|
||||
<Form inline field={this.field}>
|
||||
<FormItem label={I18N_SERVICE_NAME}>
|
||||
<FormItem label={I18N.SERVICE_NAME}>
|
||||
<Input
|
||||
placeholder={I18N_ENTER_SERVICE_NAME}
|
||||
placeholder={I18N.ENTER_SERVICE_NAME}
|
||||
style={{width: 200}}
|
||||
value={keyword}
|
||||
onChange={keyword => this.setState({keyword})}
|
||||
@ -113,7 +92,7 @@ class ServiceManagement extends React.Component {
|
||||
type="primary"
|
||||
onClick={() => this.setState({currentPage: 1}, () => this.queryServiceList())}
|
||||
style={{marginRight: 10}}
|
||||
>{I18N_QUERY}</Button>
|
||||
>{I18N.QUERY}</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Col>
|
||||
@ -127,13 +106,17 @@ class ServiceManagement extends React.Component {
|
||||
locale={locale}
|
||||
language={window.aliwareIntl.currentLanguageCode}
|
||||
className={r => this.rowColor[r.status]}
|
||||
getRowProps={this.rowColor}
|
||||
>
|
||||
<Column title="服务名" dataIndex="name"/>
|
||||
<Column title="集群数目" dataIndex="clusterCount"/>
|
||||
<Column title="实例数目" dataIndex="ipCount"/>
|
||||
<Column title="健康程度" dataIndex="status"/>
|
||||
<Column title="操作" align="center" cell={(value, index, record) => (
|
||||
<Button type="normal" disabled>详情</Button>
|
||||
<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}`)}
|
||||
>详情</Button>
|
||||
)}/>
|
||||
</Table>
|
||||
</Col>
|
@ -0,0 +1,14 @@
|
||||
.service-management {
|
||||
.row-bg-green {
|
||||
background-color: #e4fdda;
|
||||
}
|
||||
.row-bg-light-green {
|
||||
background-color: #e3fff8;
|
||||
}
|
||||
.row-bg-orange {
|
||||
background-color: #fff3e0;
|
||||
}
|
||||
.row-bg-red {
|
||||
background-color: #ffece4;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
const getI18N = (key, prefix = 'com.alibaba.nacos.page.serviceManagement.') => window.aliwareIntl.get(prefix + key)
|
||||
export const I18N = {}
|
||||
/**
|
||||
* 服务列表
|
||||
*/
|
||||
I18N.SERVICE_LIST = getI18N('service_list')
|
||||
/**
|
||||
* 服务名称
|
||||
*/
|
||||
I18N.SERVICE_NAME = getI18N('service_name')
|
||||
/**
|
||||
* 请输入服务名称
|
||||
*/
|
||||
I18N.ENTER_SERVICE_NAME = getI18N('please_enter_the_service_name')
|
||||
/**
|
||||
* 查询
|
||||
*/
|
||||
I18N.QUERY = getI18N('query')
|
||||
/**
|
||||
* 查询
|
||||
*/
|
||||
I18N.PUBNODEDATA = getI18N('pubnodata', '')
|
||||
/**
|
||||
* 服务名
|
||||
*/
|
||||
I18N.COLUMN_SERVICE_NAME = getI18N('table.column.service_name')
|
||||
/**
|
||||
* 集群数目
|
||||
*/
|
||||
I18N.COLUMN_CLUSTER_COUNT = getI18N('table.column.cluster_count')
|
||||
/**
|
||||
* IP数目
|
||||
*/
|
||||
I18N.COLUMN_IP_COUNT = getI18N('table.column.ip_count')
|
||||
/**
|
||||
* 健康程度
|
||||
*/
|
||||
I18N.COLUMN_HEALTH_STATUS = getI18N('table.column.health_status')
|
||||
/**
|
||||
* 操作
|
||||
*/
|
||||
I18N.COLUMN_OPERATION = getI18N('table.column.operation')
|
||||
|
||||
export const STATUS_COLOR_MAPPING = {
|
||||
优: 'green',
|
||||
良: 'light-green',
|
||||
中: 'orange',
|
||||
差: 'red'
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
import ServiceManagement from './ServiceManagement'
|
||||
|
||||
export default ServiceManagement
|
@ -13,7 +13,8 @@ import ConfigRollback from './pages/ConfigRollback';
|
||||
import HistoryRollback from './pages/HistoryRollback';
|
||||
import ListeningToQuery from './pages/ListeningToQuery';
|
||||
import ConfigurationManagement from './pages/ConfigurationManagement';
|
||||
import ServiceManagement from './pages/ServiceManagement';
|
||||
import ServiceManagement from './pages/ServiceManagement/index';
|
||||
import ServiceDetail from './pages/ServiceDetail/ServiceDetail';
|
||||
|
||||
function RouterConfig({ history }) {
|
||||
window.hashHistory = history;
|
||||
@ -32,6 +33,7 @@ function RouterConfig({ history }) {
|
||||
<Route path="/ListeningToQuery" component={ListeningToQuery} />
|
||||
<Route path="/ConfigurationManagement" component={ConfigurationManagement} />
|
||||
<Route path="/ServiceManagement" component={ServiceManagement} />
|
||||
<Route path="/ServiceDetail" component={ServiceDetail} />
|
||||
</App>
|
||||
</Switch>
|
||||
</Router>
|
||||
|
@ -46,6 +46,11 @@
|
||||
<artifactId>nacos-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>nacos-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
|
@ -17,16 +17,20 @@ package com.alibaba.nacos.naming.controllers;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.nacos.api.naming.pojo.Cluster;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.Service;
|
||||
import com.alibaba.nacos.naming.core.Domain;
|
||||
import com.alibaba.nacos.naming.core.DomainsManager;
|
||||
import com.alibaba.nacos.naming.core.IpAddress;
|
||||
import com.alibaba.nacos.naming.core.VirtualClusterDomain;
|
||||
import com.alibaba.nacos.naming.exception.NacosException;
|
||||
import com.alibaba.nacos.naming.healthcheck.HealthCheckMode;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
import com.alibaba.nacos.naming.view.ServiceDetailView;
|
||||
import com.alibaba.nacos.naming.view.ServiceView;
|
||||
import com.alibaba.nacos.naming.web.BaseServlet;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -57,7 +61,7 @@ public class CatalogController {
|
||||
String keyword = BaseServlet.optional(request, "keyword", StringUtils.EMPTY);
|
||||
|
||||
List<Domain> doms = new ArrayList<>();
|
||||
int total = domainsManager.getPagedDom(page, pageSize, keyword, doms);
|
||||
int total = domainsManager.getPagedDom(page - 1, pageSize, keyword, doms);
|
||||
|
||||
if (CollectionUtils.isEmpty(doms)) {
|
||||
result.put("serviceList", Collections.emptyList());
|
||||
@ -81,20 +85,7 @@ public class CatalogController {
|
||||
}
|
||||
}
|
||||
|
||||
double validRatio = validCount * 1.0 / vDomain.allIPs().size();
|
||||
|
||||
// FIXME:
|
||||
validRatio = RandomUtils.nextDouble(0, 1.2);
|
||||
|
||||
if (validRatio > 0.9) {
|
||||
serviceView.setStatus("优");
|
||||
} else if (validRatio > 0.6) {
|
||||
serviceView.setStatus("良");
|
||||
} else if (validRatio > 0.3) {
|
||||
serviceView.setStatus("中");
|
||||
} else {
|
||||
serviceView.setStatus("差");
|
||||
}
|
||||
serviceView.setStatus(validCount + "/" + vDomain.allIPs().size());
|
||||
|
||||
domArray.add(serviceView);
|
||||
}
|
||||
@ -106,9 +97,7 @@ public class CatalogController {
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/serviceDetail")
|
||||
public VirtualClusterDomain serviceDetail(HttpServletRequest request) throws Exception {
|
||||
|
||||
JSONObject result = new JSONObject();
|
||||
public ServiceDetailView serviceDetail(HttpServletRequest request) throws Exception {
|
||||
|
||||
String serviceName = BaseServlet.required(request, "serviceName");
|
||||
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
|
||||
@ -116,6 +105,91 @@ public class CatalogController {
|
||||
throw new NacosException(NacosException.NOT_FOUND, "serivce " + serviceName + " is not found!");
|
||||
}
|
||||
|
||||
return null;
|
||||
ServiceDetailView detailView = new ServiceDetailView();
|
||||
|
||||
Service service = new Service(serviceName);
|
||||
service.setName(serviceName);
|
||||
service.setProtectThreshold(domain.getProtectThreshold());
|
||||
service.setHealthCheckMode(HealthCheckMode.none.name());
|
||||
if (domain.getEnableHealthCheck()) {
|
||||
service.setHealthCheckMode(HealthCheckMode.server.name());
|
||||
}
|
||||
if (domain.getEnableClientBeat()) {
|
||||
service.setHealthCheckMode(HealthCheckMode.client.name());
|
||||
}
|
||||
service.setMetadata(domain.getMetadata());
|
||||
detailView.setService(service);
|
||||
|
||||
List<Cluster> clusters = new ArrayList<>();
|
||||
|
||||
for (com.alibaba.nacos.naming.core.Cluster cluster : domain.getClusterMap().values()) {
|
||||
Cluster clusterView = new Cluster();
|
||||
clusterView.setName(cluster.getName());
|
||||
clusterView.setHealthChecker(cluster.getHealthChecker());
|
||||
clusterView.setMetadata(cluster.getMetadata());
|
||||
clusterView.setUseIPPort4Check(cluster.isUseIPPort4Check());
|
||||
clusterView.setDefaultPort(cluster.getDefIPPort());
|
||||
clusterView.setDefaultCheckPort(cluster.getDefCkport());
|
||||
clusterView.setServiceName(serviceName);
|
||||
clusters.add(clusterView);
|
||||
}
|
||||
|
||||
detailView.setClusters(clusters);
|
||||
|
||||
return detailView;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/instanceList")
|
||||
public JSONObject instanceList(HttpServletRequest request) throws Exception {
|
||||
|
||||
String serviceName = BaseServlet.required(request, "serviceName");
|
||||
String clusterName = BaseServlet.required(request, "clusterName");
|
||||
int page = Integer.parseInt(BaseServlet.required(request, "startPg"));
|
||||
int pageSize = Integer.parseInt(BaseServlet.required(request, "pgSize"));
|
||||
|
||||
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
|
||||
if (domain == null) {
|
||||
throw new NacosException(NacosException.NOT_FOUND, "serivce " + serviceName + " is not found!");
|
||||
}
|
||||
|
||||
if (!domain.getClusterMap().containsKey(clusterName)) {
|
||||
throw new NacosException(NacosException.NOT_FOUND, "cluster " + clusterName + " is not found!");
|
||||
}
|
||||
|
||||
List<Instance> instances = new ArrayList<>();
|
||||
|
||||
for (IpAddress ipAddress : domain.getClusterMap().get(clusterName).allIPs()) {
|
||||
Instance instance = new Instance();
|
||||
instance.setIp(ipAddress.getIp());
|
||||
instance.setMetadata(ipAddress.getMetadata());
|
||||
instance.setHealthy(ipAddress.isValid());
|
||||
instance.setPort(ipAddress.getPort());
|
||||
instance.setInstanceId(ipAddress.getInstanceId());
|
||||
instance.setWeight(ipAddress.getWeight());
|
||||
instance.setEnabled(ipAddress.isEnabled());
|
||||
|
||||
instances.add(instance);
|
||||
}
|
||||
|
||||
int start = (page - 1) * pageSize;
|
||||
int end = page * pageSize;
|
||||
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if (start > instances.size()) {
|
||||
start = instances.size();
|
||||
}
|
||||
|
||||
if (end > instances.size()) {
|
||||
end = instances.size();
|
||||
}
|
||||
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("list", instances.subList(start, end));
|
||||
result.put("count", instances.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,86 @@
|
||||
*/
|
||||
package com.alibaba.nacos.naming.controllers;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
|
||||
import com.alibaba.nacos.naming.core.Cluster;
|
||||
import com.alibaba.nacos.naming.core.DomainsManager;
|
||||
import com.alibaba.nacos.naming.core.VirtualClusterDomain;
|
||||
import com.alibaba.nacos.naming.exception.NacosException;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
import com.alibaba.nacos.naming.web.BaseServlet;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author dungu.zpf
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/cluster")
|
||||
public class ClusterController {
|
||||
|
||||
@Autowired
|
||||
protected DomainsManager domainsManager;
|
||||
|
||||
@RequestMapping(value = "/update", method = RequestMethod.POST)
|
||||
public String update(HttpServletRequest request) throws Exception {
|
||||
|
||||
String clusterName = BaseServlet.required(request, "clusterName");
|
||||
String serviceName = BaseServlet.required(request, "serviceName");
|
||||
String healthChecker = BaseServlet.required(request, "healthChecker");
|
||||
String metadata = BaseServlet.optional(request, "metadata", StringUtils.EMPTY);
|
||||
String checkPort = BaseServlet.required(request, "checkPort");
|
||||
String useInstancePort4Check = BaseServlet.required(request, "useInstancePort4Check");
|
||||
|
||||
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
|
||||
if (domain == null) {
|
||||
throw new NacosException(NacosException.INVALID_PARAM, "service not found:" + serviceName);
|
||||
}
|
||||
|
||||
Cluster cluster = domain.getClusterMap().get(clusterName);
|
||||
if (cluster == null) {
|
||||
throw new NacosException(NacosException.INVALID_PARAM, "cluster not found:"+ clusterName + ", " + serviceName);
|
||||
}
|
||||
|
||||
cluster.setDefCkport(NumberUtils.toInt(checkPort));
|
||||
cluster.setUseIPPort4Check(BooleanUtils.toBoolean(useInstancePort4Check));
|
||||
|
||||
JSONObject healthCheckObj = JSON.parseObject(healthChecker);
|
||||
AbstractHealthChecker abstractHealthChecker;
|
||||
|
||||
switch (healthCheckObj.getString("type")) {
|
||||
case AbstractHealthChecker.Tcp.TYPE:
|
||||
abstractHealthChecker = JSON.parseObject(healthChecker, AbstractHealthChecker.Tcp.class);
|
||||
break;
|
||||
case AbstractHealthChecker.Http.TYPE:
|
||||
abstractHealthChecker = JSON.parseObject(healthChecker, AbstractHealthChecker.Http.class);
|
||||
break;
|
||||
case AbstractHealthChecker.Mysql.TYPE:
|
||||
abstractHealthChecker = JSON.parseObject(healthChecker, AbstractHealthChecker.Mysql.class);
|
||||
break;
|
||||
default:
|
||||
throw new NacosException(NacosException.INVALID_PARAM, "unknown health check type:" + healthChecker);
|
||||
}
|
||||
|
||||
cluster.setHealthChecker(abstractHealthChecker);
|
||||
cluster.setMetadata(UtilsAndCommons.parseMetadata(metadata));
|
||||
|
||||
domain.getClusterMap().put(clusterName, cluster);
|
||||
|
||||
domain.setLastModifiedMillis(System.currentTimeMillis());
|
||||
domain.recalculateChecksum();
|
||||
domain.valid();
|
||||
|
||||
domainsManager.easyAddOrReplaceDom(domain);
|
||||
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ package com.alibaba.nacos.naming.controllers;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.nacos.naming.exception.NacosException;
|
||||
import com.alibaba.nacos.naming.core.IpAddress;
|
||||
import com.alibaba.nacos.naming.core.VirtualClusterDomain;
|
||||
import com.alibaba.nacos.naming.exception.NacosException;
|
||||
import com.alibaba.nacos.naming.healthcheck.HealthCheckMode;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
import com.alibaba.nacos.naming.web.ApiCommands;
|
||||
@ -115,9 +115,13 @@ public class InstanceController extends ApiCommands {
|
||||
return deRegService(request);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/instance", method = RequestMethod.POST)
|
||||
@RequestMapping(value = "/instance/update", method = RequestMethod.POST)
|
||||
public String update(HttpServletRequest request) throws Exception {
|
||||
return addIP4Dom(request);
|
||||
String serviceName = BaseServlet.required(request, "serviceName");
|
||||
Map<String, String[]> params = new HashMap<>(request.getParameterMap());
|
||||
MockHttpRequest mockHttpRequest = MockHttpRequest.buildRequest(params);
|
||||
mockHttpRequest.addParameter("dom", serviceName);
|
||||
return regService(mockHttpRequest);
|
||||
}
|
||||
|
||||
@RequestMapping(value = {"/instances", "/instance/list"}, method = RequestMethod.GET)
|
||||
|
@ -17,8 +17,12 @@ package com.alibaba.nacos.naming.controllers;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.nacos.naming.core.DomainsManager;
|
||||
import com.alibaba.nacos.naming.core.VirtualClusterDomain;
|
||||
import com.alibaba.nacos.naming.exception.NacosException;
|
||||
import com.alibaba.nacos.naming.healthcheck.HealthCheckMode;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
import com.alibaba.nacos.naming.web.BaseServlet;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -26,7 +30,9 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author dungu.zpf
|
||||
@ -65,4 +71,46 @@ public class ServiceController {
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/update", method = RequestMethod.POST)
|
||||
public String update(HttpServletRequest request) throws Exception {
|
||||
|
||||
String serviceName = BaseServlet.required(request, "serviceName");
|
||||
float protectThreshold = NumberUtils.toFloat(BaseServlet.required(request, "protectThreshold"));
|
||||
String healthCheckMode = BaseServlet.required(request, "healthCheckMode");
|
||||
String metadata = BaseServlet.optional(request, "metadata", StringUtils.EMPTY);
|
||||
|
||||
VirtualClusterDomain domain = (VirtualClusterDomain) domainsManager.getDomain(serviceName);
|
||||
if (domain == null) {
|
||||
throw new NacosException(NacosException.INVALID_PARAM, "service " + serviceName + " not found!");
|
||||
}
|
||||
|
||||
domain.setProtectThreshold(protectThreshold);
|
||||
|
||||
if (HealthCheckMode.server.name().equals(healthCheckMode)) {
|
||||
domain.setEnableHealthCheck(true);
|
||||
domain.setEnableClientBeat(false);
|
||||
}
|
||||
|
||||
if (HealthCheckMode.client.name().equals(healthCheckMode)) {
|
||||
domain.setEnableClientBeat(true);
|
||||
domain.setEnableHealthCheck(false);
|
||||
}
|
||||
|
||||
if (HealthCheckMode.none.name().equals(healthCheckMode)) {
|
||||
domain.setEnableClientBeat(false);
|
||||
domain.setEnableHealthCheck(false);
|
||||
}
|
||||
|
||||
Map<String, String> metadataMap = UtilsAndCommons.parseMetadata(metadata);
|
||||
domain.setMetadata(metadataMap);
|
||||
|
||||
domain.setLastModifiedMillis(System.currentTimeMillis());
|
||||
domain.recalculateChecksum();
|
||||
domain.valid();
|
||||
|
||||
domainsManager.easyAddOrReplaceDom(domain);
|
||||
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
package com.alibaba.nacos.naming.core;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.alibaba.nacos.naming.healthcheck.AbstractHealthCheckConfig;
|
||||
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
|
||||
import com.alibaba.nacos.naming.healthcheck.HealthCheckReactor;
|
||||
import com.alibaba.nacos.naming.healthcheck.HealthCheckStatus;
|
||||
import com.alibaba.nacos.naming.healthcheck.HealthCheckTask;
|
||||
@ -32,11 +32,10 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
/**
|
||||
* @author dungu.zpf
|
||||
*/
|
||||
public class Cluster implements Cloneable {
|
||||
public class Cluster extends com.alibaba.nacos.api.naming.pojo.Cluster implements Cloneable {
|
||||
|
||||
private static final String CLUSTER_NAME_SYNTAX = "[0-9a-zA-Z-]+";
|
||||
|
||||
private String name;
|
||||
/**
|
||||
* in fact this is CIDR(Classless Inter-Domain Routing). for naming it 'submask' it has historical reasons
|
||||
*/
|
||||
@ -56,14 +55,11 @@ public class Cluster implements Cloneable {
|
||||
private String legacySyncConfig;
|
||||
|
||||
@JSONField(name = "healthChecker")
|
||||
private AbstractHealthCheckConfig healthChecker = new AbstractHealthCheckConfig.Tcp();
|
||||
private AbstractHealthChecker healthChecker = new AbstractHealthChecker.Tcp();
|
||||
|
||||
@JSONField(serialize = false)
|
||||
private HealthCheckTask checkTask;
|
||||
|
||||
@JSONField(serialize = false)
|
||||
private Set<IpAddress> ips = new HashSet<IpAddress>();
|
||||
|
||||
@JSONField(serialize = false)
|
||||
private Set<IpAddress> raftIPs = new HashSet<IpAddress>();
|
||||
|
||||
@ -136,14 +132,6 @@ public class Cluster implements Cloneable {
|
||||
return checkTask;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Domain getDom() {
|
||||
return dom;
|
||||
}
|
||||
@ -160,14 +148,6 @@ public class Cluster implements Cloneable {
|
||||
this.legacySyncConfig = nodegroup;
|
||||
}
|
||||
|
||||
public AbstractHealthCheckConfig getHealthChecker() {
|
||||
return healthChecker;
|
||||
}
|
||||
|
||||
public void setHealthChecker(AbstractHealthCheckConfig healthChecker) {
|
||||
this.healthChecker = healthChecker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cluster clone() throws CloneNotSupportedException {
|
||||
super.clone();
|
||||
@ -175,23 +155,17 @@ public class Cluster implements Cloneable {
|
||||
|
||||
cluster.setHealthChecker(healthChecker.clone());
|
||||
cluster.setDom(getDom());
|
||||
cluster.ips = new HashSet<IpAddress>();
|
||||
cluster.raftIPs = new HashSet<IpAddress>();
|
||||
cluster.checkTask = null;
|
||||
cluster.metadata = new HashMap<>(metadata);
|
||||
return cluster;
|
||||
}
|
||||
|
||||
public void updateIPs(List<IpAddress> ips, boolean diamond) {
|
||||
public void updateIPs(List<IpAddress> ips) {
|
||||
HashMap<String, IpAddress> oldIPMap = new HashMap<>(raftIPs.size());
|
||||
if (diamond) {
|
||||
for (IpAddress ip : this.ips) {
|
||||
oldIPMap.put(ip.getDatumKey(), ip);
|
||||
}
|
||||
} else {
|
||||
for (IpAddress ip : this.raftIPs) {
|
||||
oldIPMap.put(ip.getDatumKey(), ip);
|
||||
}
|
||||
|
||||
for (IpAddress ip : this.raftIPs) {
|
||||
oldIPMap.put(ip.getDatumKey(), ip);
|
||||
}
|
||||
|
||||
List<IpAddress> updatedIPs = updatedIPs(ips, oldIPMap.values());
|
||||
@ -213,7 +187,7 @@ public class Cluster implements Cloneable {
|
||||
// ip validation status updated
|
||||
Loggers.EVT_LOG.info("{" + getDom().getName() + "} {SYNC} " +
|
||||
"{IP-" + (ip.isValid() ? "ENABLED" : "DISABLED") + "} " + ip.getIp()
|
||||
+ ":" + ip.getPort() + "@" + name);
|
||||
+ ":" + ip.getPort() + "@" + getName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,7 +201,7 @@ public class Cluster implements Cloneable {
|
||||
|
||||
List<IpAddress> newIPs = subtract(ips, oldIPMap.values());
|
||||
if (newIPs.size() > 0) {
|
||||
Loggers.EVT_LOG.info("{" + getDom().getName() + "} {SYNC} {IP-NEW} cluster: " + name
|
||||
Loggers.EVT_LOG.info("{" + getDom().getName() + "} {SYNC} {IP-NEW} cluster: " + getName()
|
||||
+ ", new ips(" + newIPs.size() + "): " + newIPs.toString());
|
||||
|
||||
for (IpAddress ip : newIPs) {
|
||||
@ -238,7 +212,7 @@ public class Cluster implements Cloneable {
|
||||
List<IpAddress> deadIPs = subtract(oldIPMap.values(), ips);
|
||||
|
||||
if (deadIPs.size() > 0) {
|
||||
Loggers.EVT_LOG.info("{" + getDom().getName() + "} {SYNC} {IP-DEAD} cluster: " + name
|
||||
Loggers.EVT_LOG.info("{" + getDom().getName() + "} {SYNC} {IP-DEAD} cluster: " + getName()
|
||||
+ ", dead ips(" + deadIPs.size() + "): " + deadIPs.toString());
|
||||
|
||||
for (IpAddress ip : deadIPs) {
|
||||
@ -246,11 +220,8 @@ public class Cluster implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
if (diamond) {
|
||||
this.ips = new HashSet<IpAddress>(ips);
|
||||
} else {
|
||||
this.raftIPs = new HashSet<IpAddress>(ips);
|
||||
}
|
||||
this.raftIPs = new HashSet<IpAddress>(ips);
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (IpAddress ipAddress : raftIPs) {
|
||||
stringBuilder.append(ipAddress.toIPAddr()).append(ipAddress.isValid());
|
||||
@ -337,7 +308,7 @@ public class Cluster implements Cloneable {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
return Objects.hash(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -346,7 +317,7 @@ public class Cluster implements Cloneable {
|
||||
return false;
|
||||
}
|
||||
|
||||
return name.equals(((Cluster) obj).getName());
|
||||
return getName().equals(((Cluster) obj).getName());
|
||||
}
|
||||
|
||||
public int getDefCkport() {
|
||||
@ -420,14 +391,6 @@ public class Cluster implements Cloneable {
|
||||
this.sitegroup = sitegroup;
|
||||
}
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public void setMetadata(Map<String, String> metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
public boolean responsible(IpAddress ip) {
|
||||
return Switch.isHealthCheckEnabled(dom.getName())
|
||||
&& !getHealthCheckTask().isCancelled()
|
||||
@ -436,8 +399,8 @@ public class Cluster implements Cloneable {
|
||||
}
|
||||
|
||||
public void valid() {
|
||||
if (!name.matches(CLUSTER_NAME_SYNTAX)) {
|
||||
throw new IllegalArgumentException("cluster name can only have these characters: 0-9a-zA-Z-, current: " + name);
|
||||
if (!getName().matches(CLUSTER_NAME_SYNTAX)) {
|
||||
throw new IllegalArgumentException("cluster name can only have these characters: 0-9a-zA-Z-, current: " + getName());
|
||||
}
|
||||
|
||||
String[] cidrGroups = submask.split("\\|");
|
||||
@ -446,7 +409,7 @@ public class Cluster implements Cloneable {
|
||||
|
||||
for (String cidr : cidrs) {
|
||||
if (!cidr.matches(UtilsAndCommons.CIDR_REGEX)) {
|
||||
throw new IllegalArgumentException("malformed submask: " + submask + " for cluster: " + name);
|
||||
throw new IllegalArgumentException("malformed submask: " + submask + " for cluster: " + getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,12 +176,12 @@ public class DomainsManager {
|
||||
JSONObject dom = JSON.parseObject(msg.getData());
|
||||
|
||||
JSONArray ipList = dom.getJSONArray("ips");
|
||||
Map<String, Pair> ipsMap = new HashMap<>(ipList.size());
|
||||
Map<String, String> ipsMap = new HashMap<>(ipList.size());
|
||||
for (int i=0; i<ipList.size(); i++) {
|
||||
|
||||
String ip = ipList.getString(i);
|
||||
String[] strings = ip.split("_");
|
||||
ipsMap.put(strings[0], new Pair(strings[1], strings[2]));
|
||||
ipsMap.put(strings[0], strings[1]);
|
||||
}
|
||||
|
||||
VirtualClusterDomain raftVirtualClusterDomain = (VirtualClusterDomain) raftDomMap.get(domName);
|
||||
@ -192,14 +192,10 @@ public class DomainsManager {
|
||||
|
||||
List<IpAddress> ipAddresses = raftVirtualClusterDomain.allIPs();
|
||||
for (IpAddress ipAddress : ipAddresses) {
|
||||
Pair pair = ipsMap.get(ipAddress.toIPAddr());
|
||||
if (pair == null) {
|
||||
continue;
|
||||
}
|
||||
Boolean valid = Boolean.parseBoolean(pair.getKey());
|
||||
|
||||
Boolean valid = Boolean.parseBoolean(ipsMap.get(ipAddress.toIPAddr()));
|
||||
if (valid != ipAddress.isValid()) {
|
||||
ipAddress.setValid(Boolean.parseBoolean(pair.getKey()));
|
||||
ipAddress.setInvalidType(pair.getValue());
|
||||
ipAddress.setValid(valid);
|
||||
Loggers.EVT_LOG.info("{" + domName + "} {SYNC} " +
|
||||
"{IP-" + (ipAddress.isValid() ? "ENABLED" : "DISABLED") + "} " + ipAddress.getIp()
|
||||
+ ":" + ipAddress.getPort() + "@" + ipAddress.getClusterName());
|
||||
|
@ -17,6 +17,7 @@ package com.alibaba.nacos.naming.core;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.naming.healthcheck.HealthCheckStatus;
|
||||
import com.alibaba.nacos.naming.misc.Loggers;
|
||||
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
|
||||
@ -33,55 +34,25 @@ import java.util.regex.Pattern;
|
||||
*
|
||||
* @author dungu.zpf
|
||||
*/
|
||||
public class IpAddress implements Comparable {
|
||||
public class IpAddress extends Instance implements Comparable {
|
||||
|
||||
private static final double MAX_WEIGHT_VALUE = 10000.0D;
|
||||
private static final double MIN_POSTIVE_WEIGHT_VALUE = 0.01D;
|
||||
private static final double MIN_WEIGHT_VALUE = 0.00D;
|
||||
|
||||
private String ip;
|
||||
private int port = 0;
|
||||
private double weight = 1.0;
|
||||
private String clusterName = UtilsAndCommons.DEFAULT_CLUSTER_NAME;
|
||||
|
||||
private volatile long lastBeat = System.currentTimeMillis();
|
||||
|
||||
@JSONField(serialize = false)
|
||||
private String invalidType = InvalidType.VALID;
|
||||
|
||||
public static class InvalidType {
|
||||
public final static String HTTP_404 = "404";
|
||||
public final static String WEIGHT_0 = "weight_0";
|
||||
public final static String NORMAL_INVALID = "invalid";
|
||||
public final static String VALID = "valid";
|
||||
}
|
||||
|
||||
public String getInvalidType() {
|
||||
return invalidType;
|
||||
}
|
||||
|
||||
public void setInvalidType(String invalidType) {
|
||||
this.invalidType = invalidType;
|
||||
}
|
||||
|
||||
@JSONField(serialize = false)
|
||||
private Cluster cluster;
|
||||
|
||||
private volatile boolean valid = true;
|
||||
|
||||
@JSONField(serialize = false)
|
||||
private volatile boolean mockValid = false;
|
||||
|
||||
@JSONField(serialize = false)
|
||||
private volatile boolean preValid = true;
|
||||
|
||||
private volatile boolean marked = false;
|
||||
|
||||
private String tenant;
|
||||
|
||||
private String app;
|
||||
|
||||
private Map<String, String> metadata = new ConcurrentHashMap<>();
|
||||
|
||||
public static final Pattern IP_PATTERN
|
||||
= Pattern.compile("(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}):?(\\d{1,5})?");
|
||||
|
||||
@ -107,20 +78,20 @@ public class IpAddress implements Comparable {
|
||||
}
|
||||
|
||||
public IpAddress(String ip, int port) {
|
||||
this.ip = ip.trim();
|
||||
this.port = port;
|
||||
this.setIp(ip);
|
||||
this.setPort(port);
|
||||
this.clusterName = UtilsAndCommons.DEFAULT_CLUSTER_NAME;
|
||||
}
|
||||
|
||||
public IpAddress(String ip, int port, String clusterName) {
|
||||
this.ip = ip.trim();
|
||||
this.port = port;
|
||||
this.setIp(ip.trim());
|
||||
this.setPort(port);
|
||||
this.clusterName = clusterName;
|
||||
}
|
||||
|
||||
public IpAddress(String ip, int port, String clusterName, String tenant, String app) {
|
||||
this.ip = ip.trim();
|
||||
this.port = port;
|
||||
this.setIp(ip.trim());
|
||||
this.setPort(port);
|
||||
this.clusterName = clusterName;
|
||||
this.tenant = tenant;
|
||||
this.app = app;
|
||||
@ -192,12 +163,12 @@ public class IpAddress implements Comparable {
|
||||
}
|
||||
|
||||
public String toIPAddr() {
|
||||
return ip + ":" + port;
|
||||
return getIp() + ":" + getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDatumKey() + SPLITER + weight + SPLITER + valid + SPLITER + marked + SPLITER + clusterName;
|
||||
return getDatumKey() + SPLITER + getWeight() + SPLITER + isHealthy() + SPLITER + marked + SPLITER + clusterName;
|
||||
}
|
||||
|
||||
public String toJSON() {
|
||||
@ -241,30 +212,30 @@ public class IpAddress implements Comparable {
|
||||
IpAddress other = (IpAddress) obj;
|
||||
|
||||
// 0 means wild
|
||||
return ip.equals(other.getIp()) && (port == other.port || port == 0);
|
||||
return getIp().equals(other.getIp()) && (getPort() == other.getPort() || getPort() == 0);
|
||||
}
|
||||
|
||||
@JSONField(serialize = false)
|
||||
public String getDatumKey() {
|
||||
if (port > 0) {
|
||||
return ip + ":" + port + ":" + DistroMapper.LOCALHOST_SITE;
|
||||
if (getPort() > 0) {
|
||||
return getIp() + ":" + getPort() + ":" + DistroMapper.LOCALHOST_SITE;
|
||||
} else {
|
||||
return ip + ":" + DistroMapper.LOCALHOST_SITE;
|
||||
return getIp() + ":" + DistroMapper.LOCALHOST_SITE;
|
||||
}
|
||||
}
|
||||
|
||||
@JSONField(serialize = false)
|
||||
public String getDefaultKey() {
|
||||
if (port > 0) {
|
||||
return ip + ":" + port + ":" + UtilsAndCommons.UNKNOWN_SITE;
|
||||
if (getPort() > 0) {
|
||||
return getIp() + ":" + getPort() + ":" + UtilsAndCommons.UNKNOWN_SITE;
|
||||
} else {
|
||||
return ip + ":" + UtilsAndCommons.UNKNOWN_SITE;
|
||||
return getIp() + ":" + UtilsAndCommons.UNKNOWN_SITE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ip.hashCode();
|
||||
return getIp().hashCode();
|
||||
}
|
||||
|
||||
public void setBeingChecked(boolean isBeingChecked) {
|
||||
@ -295,14 +266,6 @@ public class IpAddress implements Comparable {
|
||||
HealthCheckStatus.get(this).checkRT = checkRT;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getClusterName() {
|
||||
return clusterName;
|
||||
}
|
||||
@ -311,41 +274,12 @@ public class IpAddress implements Comparable {
|
||||
this.clusterName = clusterName;
|
||||
}
|
||||
|
||||
public void setCluster(Cluster cluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
public Cluster getCluster() {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public double getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public void setWeight(double weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public synchronized void setValid(boolean valid) {
|
||||
this.preValid = this.valid;
|
||||
this.valid = valid;
|
||||
setHealthy(valid);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
public boolean isPreValid() {
|
||||
return preValid;
|
||||
return isHealthy();
|
||||
}
|
||||
|
||||
public boolean isMarked() {
|
||||
@ -372,16 +306,8 @@ public class IpAddress implements Comparable {
|
||||
this.tenant = tenant;
|
||||
}
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public void setMetadata(Map<String, String> metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
public String generateInstanceId() {
|
||||
return this.ip + "#" + this.port + "#" + this.cluster.getName() + "#" + this.cluster.getDom().getName();
|
||||
return getIp() + "#" + getPort() + "#" + getCluster().getName() + "#" + getService().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -175,7 +175,7 @@ public class VirtualClusterDomain implements Domain, RaftListener {
|
||||
}
|
||||
}
|
||||
|
||||
updateIPs(ips, false);
|
||||
updateIPs(ips);
|
||||
|
||||
recalculateChecksum();
|
||||
}
|
||||
@ -185,7 +185,7 @@ public class VirtualClusterDomain implements Domain, RaftListener {
|
||||
// ignore
|
||||
}
|
||||
|
||||
public void updateIPs(List<IpAddress> ips, boolean diamond) {
|
||||
public void updateIPs(List<IpAddress> ips) {
|
||||
if (CollectionUtils.isEmpty(ips) && allIPs().size() > 1) {
|
||||
return;
|
||||
}
|
||||
@ -236,7 +236,7 @@ public class VirtualClusterDomain implements Domain, RaftListener {
|
||||
ip.setCluster(clusterMap.get(ip.getClusterName()));
|
||||
}
|
||||
|
||||
clusterMap.get(entry.getKey()).updateIPs(entryIPs, diamond);
|
||||
clusterMap.get(entry.getKey()).updateIPs(entryIPs);
|
||||
}
|
||||
setLastModifiedMillis(System.currentTimeMillis());
|
||||
PushService.domChanged(name);
|
||||
|
@ -1,327 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package com.alibaba.nacos.naming.healthcheck;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.alibaba.fastjson.parser.DefaultJSONParser;
|
||||
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
|
||||
import com.alibaba.fastjson.serializer.JSONSerializer;
|
||||
import com.alibaba.fastjson.serializer.ObjectSerializer;
|
||||
import com.alibaba.fastjson.serializer.SerializeWriter;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author nacos
|
||||
*/
|
||||
public abstract class AbstractHealthCheckConfig implements Cloneable {
|
||||
|
||||
protected String type = "unknown";
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get copy of health check config
|
||||
*
|
||||
* @return Copy of health check config
|
||||
* @throws CloneNotSupportedException
|
||||
*/
|
||||
@Override
|
||||
public abstract AbstractHealthCheckConfig clone() throws CloneNotSupportedException;
|
||||
|
||||
public static class Http extends AbstractHealthCheckConfig {
|
||||
public static final String TYPE = "HTTP";
|
||||
public static final String HTTP_HEADER_SPLIT_STRING = "\\|";
|
||||
|
||||
private String path = StringUtils.EMPTY;
|
||||
private String headers = StringUtils.EMPTY;
|
||||
|
||||
private int expectedResponseCode = 200;
|
||||
|
||||
public Http() {
|
||||
this.type = TYPE;
|
||||
}
|
||||
|
||||
public int getExpectedResponseCode() {
|
||||
return expectedResponseCode;
|
||||
}
|
||||
|
||||
public void setExpectedResponseCode(int expectedResponseCode) {
|
||||
this.expectedResponseCode = expectedResponseCode;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public void setHeaders(String headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
@JSONField(serialize = false)
|
||||
public Map<String, String> getCustomHeaders() {
|
||||
if (StringUtils.isBlank(headers)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, String> headers = new HashMap<String, String>(this.headers.split(HTTP_HEADER_SPLIT_STRING).length);
|
||||
for (String s : this.headers.split(HTTP_HEADER_SPLIT_STRING)) {
|
||||
String[] splits = s.split(":");
|
||||
if (splits.length != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
headers.put(StringUtils.trim(splits[0]), StringUtils.trim(splits[1]));
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(headers, path, expectedResponseCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Http)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Http other = (Http) obj;
|
||||
|
||||
if (!StringUtils.equals(type, other.getType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!StringUtils.equals(path, other.getPath())) {
|
||||
return false;
|
||||
}
|
||||
if (!StringUtils.equals(headers, other.getHeaders())) {
|
||||
return false;
|
||||
}
|
||||
return expectedResponseCode == other.getExpectedResponseCode();
|
||||
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("CN_IDIOM_NO_SUPER_CALL")
|
||||
@Override
|
||||
public AbstractHealthCheckConfig.Http clone() throws CloneNotSupportedException {
|
||||
AbstractHealthCheckConfig.Http config = new AbstractHealthCheckConfig.Http();
|
||||
|
||||
config.setPath(this.path);
|
||||
config.setHeaders(this.headers);
|
||||
config.setType(this.type);
|
||||
config.setExpectedResponseCode(this.expectedResponseCode);
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Tcp extends AbstractHealthCheckConfig {
|
||||
public static final String TYPE = "TCP";
|
||||
|
||||
public Tcp() {
|
||||
this.type = TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(Tcp.TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof Tcp;
|
||||
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("CN_IDIOM_NO_SUPER_CALL")
|
||||
@Override
|
||||
public AbstractHealthCheckConfig.Tcp clone() throws CloneNotSupportedException {
|
||||
AbstractHealthCheckConfig.Tcp config = new AbstractHealthCheckConfig.Tcp();
|
||||
|
||||
config.setType(this.type);
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Mysql extends AbstractHealthCheckConfig {
|
||||
public static final String TYPE = "MYSQL";
|
||||
|
||||
private String user;
|
||||
private String pwd;
|
||||
private String cmd;
|
||||
|
||||
public Mysql() {
|
||||
this.type = TYPE;
|
||||
}
|
||||
|
||||
public String getCmd() {
|
||||
return cmd;
|
||||
}
|
||||
|
||||
public String getPwd() {
|
||||
return pwd;
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public void setCmd(String cmd) {
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
public void setPwd(String pwd) {
|
||||
this.pwd = pwd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(user, pwd, cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Mysql)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Mysql other = (Mysql) obj;
|
||||
|
||||
if (!StringUtils.equals(user, other.getUser())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!StringUtils.equals(pwd, other.getPwd())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return StringUtils.equals(cmd, other.getCmd());
|
||||
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("CN_IDIOM_NO_SUPER_CALL")
|
||||
@Override
|
||||
public AbstractHealthCheckConfig.Mysql clone() throws CloneNotSupportedException {
|
||||
AbstractHealthCheckConfig.Mysql config = new AbstractHealthCheckConfig.Mysql();
|
||||
|
||||
config.setUser(this.user);
|
||||
config.setPwd(this.pwd);
|
||||
config.setCmd(this.cmd);
|
||||
config.setType(this.type);
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public static class JsonAdapter implements ObjectDeserializer, ObjectSerializer {
|
||||
private static JsonAdapter INSTANCE = new JsonAdapter();
|
||||
|
||||
private JsonAdapter() {
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
public static JsonAdapter getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
|
||||
JSONObject jsonObj = (JSONObject) parser.parse();
|
||||
String checkType = jsonObj.getString("type");
|
||||
|
||||
if (StringUtils.equals(checkType, AbstractHealthCheckConfig.Http.TYPE)) {
|
||||
return (T) JSON.parseObject(jsonObj.toJSONString(), AbstractHealthCheckConfig.Http.class);
|
||||
}
|
||||
|
||||
if (StringUtils.equals(checkType, AbstractHealthCheckConfig.Tcp.TYPE)) {
|
||||
return (T) JSON.parseObject(jsonObj.toJSONString(), AbstractHealthCheckConfig.Tcp.class);
|
||||
}
|
||||
|
||||
if (StringUtils.equals(checkType, AbstractHealthCheckConfig.Mysql.TYPE)) {
|
||||
return (T) JSON.parseObject(jsonObj.toJSONString(), AbstractHealthCheckConfig.Mysql.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFastMatchToken() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JSONSerializer jsonSerializer, Object o, Object o1, Type type, int i) throws IOException {
|
||||
SerializeWriter writer = jsonSerializer.getWriter();
|
||||
if (o == null) {
|
||||
writer.writeNull();
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractHealthCheckConfig config = (AbstractHealthCheckConfig) o;
|
||||
|
||||
writer.writeFieldValue(',', "type", config.getType());
|
||||
|
||||
if (StringUtils.equals(config.getType(), HealthCheckType.HTTP.name())) {
|
||||
AbstractHealthCheckConfig.Http httpCheckConfig = (Http) config;
|
||||
writer.writeFieldValue(',', "path", httpCheckConfig.getPath());
|
||||
writer.writeFieldValue(',', "headers", httpCheckConfig.getHeaders());
|
||||
}
|
||||
|
||||
if (StringUtils.equals(config.getType(), HealthCheckType.TCP.name())) {
|
||||
// nothing sepcial to handle
|
||||
}
|
||||
|
||||
if (StringUtils.equals(config.getType(), HealthCheckType.MYSQL.name())) {
|
||||
AbstractHealthCheckConfig.Mysql mysqlCheckConfig = (Mysql) config;
|
||||
writer.writeFieldValue(',', "user", mysqlCheckConfig.getUser());
|
||||
writer.writeFieldValue(',', "pwd", mysqlCheckConfig.getPwd());
|
||||
writer.writeFieldValue(',', "cmd", mysqlCheckConfig.getCmd());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
package com.alibaba.nacos.naming.healthcheck;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
|
||||
import com.alibaba.nacos.naming.boot.RunningConfig;
|
||||
import com.alibaba.nacos.naming.core.Cluster;
|
||||
import com.alibaba.nacos.naming.core.DistroMapper;
|
||||
@ -146,7 +147,7 @@ public abstract class AbstractHealthCheckProcessor {
|
||||
public static final TcpSuperSenseProcessor TCP_PROCESSOR = new TcpSuperSenseProcessor();
|
||||
public static final MysqlHealthCheckProcessor MYSQL_PROCESSOR = new MysqlHealthCheckProcessor();
|
||||
|
||||
public static AbstractHealthCheckProcessor getProcessor(AbstractHealthCheckConfig config) {
|
||||
public static AbstractHealthCheckProcessor getProcessor(AbstractHealthChecker config) {
|
||||
if (config == null || StringUtils.isEmpty(config.getType())) {
|
||||
throw new IllegalArgumentException("empty check type");
|
||||
}
|
||||
@ -207,7 +208,6 @@ public abstract class AbstractHealthCheckProcessor {
|
||||
if (cluster.responsible(ip)) {
|
||||
ip.setValid(true);
|
||||
ip.setMockValid(true);
|
||||
ip.setInvalidType(IpAddress.InvalidType.VALID);
|
||||
|
||||
VirtualClusterDomain vDom = (VirtualClusterDomain) cluster.getDom();
|
||||
vDom.setLastModifiedMillis(System.currentTimeMillis());
|
||||
@ -249,7 +249,6 @@ public abstract class AbstractHealthCheckProcessor {
|
||||
if (cluster.responsible(ip)) {
|
||||
ip.setValid(false);
|
||||
ip.setMockValid(false);
|
||||
setInvalidType(ip, msg);
|
||||
|
||||
VirtualClusterDomain vDom = (VirtualClusterDomain) cluster.getDom();
|
||||
vDom.setLastModifiedMillis(System.currentTimeMillis());
|
||||
@ -281,14 +280,6 @@ public abstract class AbstractHealthCheckProcessor {
|
||||
ip.setBeingChecked(false);
|
||||
}
|
||||
|
||||
private void setInvalidType(IpAddress ipAddress, String msg) {
|
||||
if (msg.equals(HTTP_CHECK_MSG_PREFIX + IpAddress.InvalidType.HTTP_404)) {
|
||||
ipAddress.setInvalidType(IpAddress.InvalidType.HTTP_404);
|
||||
} else {
|
||||
ipAddress.setInvalidType(IpAddress.InvalidType.NORMAL_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkFailNow(IpAddress ip, HealthCheckTask task, String msg) {
|
||||
Cluster cluster = task.getCluster();
|
||||
try {
|
||||
@ -297,8 +288,6 @@ public abstract class AbstractHealthCheckProcessor {
|
||||
ip.setValid(false);
|
||||
ip.setMockValid(false);
|
||||
|
||||
setInvalidType(ip, msg);
|
||||
|
||||
VirtualClusterDomain vDom = (VirtualClusterDomain) cluster.getDom();
|
||||
vDom.setLastModifiedMillis(System.currentTimeMillis());
|
||||
|
||||
|
@ -16,8 +16,6 @@
|
||||
package com.alibaba.nacos.naming.healthcheck;
|
||||
|
||||
|
||||
import com.alibaba.nacos.naming.core.Cluster;
|
||||
import com.alibaba.nacos.naming.core.Domain;
|
||||
import com.alibaba.nacos.naming.core.IpAddress;
|
||||
import com.alibaba.nacos.naming.misc.Loggers;
|
||||
|
||||
@ -58,16 +56,9 @@ public class HealthCheckStatus {
|
||||
|
||||
private static String buildKey(IpAddress ip) {
|
||||
try {
|
||||
Cluster cluster = ip.getCluster();
|
||||
Domain domain = cluster.getDom();
|
||||
|
||||
if (domain == null) {
|
||||
Loggers.SRV_LOG.warn("BUILD-KEY", "domain is null, ip: " + ip.toIPAddr());
|
||||
return ip.getDefaultKey();
|
||||
}
|
||||
|
||||
String clusterName = cluster.getName();
|
||||
String dom = domain.getName();
|
||||
String clusterName = ip.getCluster().getName();
|
||||
String dom = ip.getCluster().getServiceName();
|
||||
String datumKey = ip.getDatumKey();
|
||||
return dom + ":"
|
||||
+ clusterName + ":"
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.alibaba.nacos.naming.healthcheck;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
|
||||
import com.alibaba.nacos.naming.core.Cluster;
|
||||
import com.alibaba.nacos.naming.core.IpAddress;
|
||||
import com.alibaba.nacos.naming.core.VirtualClusterDomain;
|
||||
@ -107,7 +108,7 @@ public class HttpHealthCheckProcessor extends AbstractHealthCheckProcessor {
|
||||
continue;
|
||||
}
|
||||
|
||||
AbstractHealthCheckConfig.Http healthChecker = (AbstractHealthCheckConfig.Http) cluster.getHealthChecker();
|
||||
AbstractHealthChecker.Http healthChecker = (AbstractHealthChecker.Http) cluster.getHealthChecker();
|
||||
|
||||
int ckPort = cluster.isUseIPPort4Check() ? ip.getPort() : cluster.getDefCkport();
|
||||
URL host = new URL("http://" + ip.getIp() + ":" + ckPort);
|
||||
|
@ -0,0 +1,84 @@
|
||||
package com.alibaba.nacos.naming.healthcheck;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.parser.DefaultJSONParser;
|
||||
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
|
||||
import com.alibaba.fastjson.serializer.JSONSerializer;
|
||||
import com.alibaba.fastjson.serializer.ObjectSerializer;
|
||||
import com.alibaba.fastjson.serializer.SerializeWriter;
|
||||
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* @author dungu.zpf
|
||||
*/
|
||||
public class JsonAdapter implements ObjectDeserializer, ObjectSerializer {
|
||||
|
||||
private static JsonAdapter INSTANCE = new JsonAdapter();
|
||||
|
||||
private JsonAdapter() {
|
||||
}
|
||||
|
||||
public static JsonAdapter getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
|
||||
JSONObject jsonObj = (JSONObject) parser.parse();
|
||||
String checkType = jsonObj.getString("type");
|
||||
|
||||
if (StringUtils.equals(checkType, AbstractHealthChecker.Http.TYPE)) {
|
||||
return (T) JSON.parseObject(jsonObj.toJSONString(), AbstractHealthChecker.Http.class);
|
||||
}
|
||||
|
||||
if (StringUtils.equals(checkType, AbstractHealthChecker.Tcp.TYPE)) {
|
||||
return (T) JSON.parseObject(jsonObj.toJSONString(), AbstractHealthChecker.Tcp.class);
|
||||
}
|
||||
|
||||
if (StringUtils.equals(checkType, AbstractHealthChecker.Mysql.TYPE)) {
|
||||
return (T) JSON.parseObject(jsonObj.toJSONString(), AbstractHealthChecker.Mysql.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFastMatchToken() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JSONSerializer jsonSerializer, Object o, Object o1, Type type, int i) throws IOException {
|
||||
SerializeWriter writer = jsonSerializer.getWriter();
|
||||
if (o == null) {
|
||||
writer.writeNull();
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractHealthChecker config = (AbstractHealthChecker) o;
|
||||
|
||||
writer.writeFieldValue(',', "type", config.getType());
|
||||
|
||||
if (StringUtils.equals(config.getType(), HealthCheckType.HTTP.name())) {
|
||||
AbstractHealthChecker.Http httpCheckConfig = (AbstractHealthChecker.Http) config;
|
||||
writer.writeFieldValue(',', "path", httpCheckConfig.getPath());
|
||||
writer.writeFieldValue(',', "headers", httpCheckConfig.getHeaders());
|
||||
}
|
||||
|
||||
if (StringUtils.equals(config.getType(), HealthCheckType.TCP.name())) {
|
||||
// nothing sepcial to handle
|
||||
}
|
||||
|
||||
if (StringUtils.equals(config.getType(), HealthCheckType.MYSQL.name())) {
|
||||
AbstractHealthChecker.Mysql mysqlCheckConfig = (AbstractHealthChecker.Mysql) config;
|
||||
writer.writeFieldValue(',', "user", mysqlCheckConfig.getUser());
|
||||
writer.writeFieldValue(',', "pwd", mysqlCheckConfig.getPwd());
|
||||
writer.writeFieldValue(',', "cmd", mysqlCheckConfig.getCmd());
|
||||
}
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.alibaba.nacos.naming.healthcheck;
|
||||
|
||||
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
|
||||
import com.alibaba.nacos.naming.core.Cluster;
|
||||
import com.alibaba.nacos.naming.core.IpAddress;
|
||||
import com.alibaba.nacos.naming.core.VirtualClusterDomain;
|
||||
@ -132,7 +133,7 @@ public class MysqlHealthCheckProcessor extends AbstractHealthCheckProcessor {
|
||||
Cluster cluster = task.getCluster();
|
||||
String key = cluster.getDom().getName() + ":" + cluster.getName() + ":" + ip.getIp() + ":" + ip.getPort();
|
||||
Connection connection = CONNECTION_POOL.get(key);
|
||||
AbstractHealthCheckConfig.Mysql config = (AbstractHealthCheckConfig.Mysql) cluster.getHealthChecker();
|
||||
AbstractHealthChecker.Mysql config = (AbstractHealthChecker.Mysql) cluster.getHealthChecker();
|
||||
|
||||
if (connection == null || connection.isClosed()) {
|
||||
MysqlDataSource dataSource = new MysqlDataSource();
|
||||
|
@ -16,14 +16,19 @@
|
||||
package com.alibaba.nacos.naming.misc;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import com.alibaba.fastjson.serializer.SerializeConfig;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
|
||||
import com.alibaba.nacos.naming.core.Domain;
|
||||
import com.alibaba.nacos.naming.healthcheck.AbstractHealthCheckConfig;
|
||||
import com.alibaba.nacos.naming.exception.NacosException;
|
||||
import com.alibaba.nacos.naming.healthcheck.JsonAdapter;
|
||||
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;
|
||||
@ -115,9 +120,9 @@ public class UtilsAndCommons {
|
||||
static {
|
||||
// custom serializer and deserializer for fast-json
|
||||
SerializeConfig.getGlobalInstance()
|
||||
.put(AbstractHealthCheckConfig.class, AbstractHealthCheckConfig.JsonAdapter.getInstance());
|
||||
.put(AbstractHealthChecker.class, JsonAdapter.getInstance());
|
||||
ParserConfig.getGlobalInstance()
|
||||
.putDeserializer(AbstractHealthCheckConfig.class, AbstractHealthCheckConfig.JsonAdapter.getInstance());
|
||||
.putDeserializer(AbstractHealthChecker.class, JsonAdapter.getInstance());
|
||||
|
||||
// write null values, otherwise will cause compatibility issues
|
||||
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteNullStringAsEmpty.getMask();
|
||||
@ -203,4 +208,29 @@ public class UtilsAndCommons {
|
||||
return UtilsAndCommons.DOMAINS_DATA_ID + "." + dom.getName();
|
||||
}
|
||||
|
||||
public static Map<String, String> parseMetadata(String metadata) throws NacosException {
|
||||
|
||||
Map<String, String> metadataMap = new HashMap<>(16);
|
||||
|
||||
if (StringUtils.isBlank(metadata)) {
|
||||
return metadataMap;
|
||||
}
|
||||
|
||||
try {
|
||||
metadataMap = JSON.parseObject(metadata, new TypeReference<Map<String, String>>(){});
|
||||
} catch (Exception e) {
|
||||
String[] datas = metadata.split(",");
|
||||
if (datas.length > 0) {
|
||||
for (String data : datas) {
|
||||
String[] kv = data.split("=");
|
||||
if (kv.length != 2) {
|
||||
throw new NacosException(NacosException.INVALID_PARAM, "metadata format incorrect:" + metadata);
|
||||
}
|
||||
metadataMap.put(kv[0], kv[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return metadataMap;
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ public class PeerSet {
|
||||
RaftPeer peer = peers.get(first);
|
||||
peer.state = RaftPeer.State.LEADER;
|
||||
|
||||
if (!peer.equals(leader)) {
|
||||
if (!Objects.equals(leader, peer)) {
|
||||
leader = peer;
|
||||
Loggers.RAFT.info(leader.ip + " has become the LEADER");
|
||||
}
|
||||
@ -139,14 +139,14 @@ public class PeerSet {
|
||||
}
|
||||
|
||||
public RaftPeer makeLeader(RaftPeer candidate) {
|
||||
if (!leader.equals(candidate)) {
|
||||
if (!Objects.equals(leader, candidate)) {
|
||||
leader = candidate;
|
||||
Loggers.RAFT.info(leader.ip + " has become the LEADER" + ",local :" + JSON.toJSONString(local()) + ", leader: " + JSON.toJSONString(leader));
|
||||
}
|
||||
|
||||
for (final RaftPeer peer : peers.values()) {
|
||||
Map<String, String> params = new HashMap<String, String>(1);
|
||||
if (!peer.equals(candidate) && peer.state == RaftPeer.State.LEADER) {
|
||||
if (!Objects.equals(peer, candidate) && peer.state == RaftPeer.State.LEADER) {
|
||||
try {
|
||||
String url = RaftCore.buildURL(peer.ip, RaftCore.API_GET_PEER);
|
||||
HttpClient.asyncHttpPost(url, null, params, new AsyncCompletionHandler<Integer>() {
|
||||
|
@ -1,10 +1,40 @@
|
||||
package com.alibaba.nacos.naming.view;
|
||||
|
||||
import com.alibaba.nacos.naming.core.VirtualClusterDomain;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.nacos.api.naming.pojo.Cluster;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author dungu.zpf
|
||||
*/
|
||||
public class ServiceDetailView {
|
||||
|
||||
private Service service;
|
||||
|
||||
private List<Cluster> clusters;
|
||||
|
||||
public Service getService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
public void setService(Service service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public List<Cluster> getClusters() {
|
||||
return clusters;
|
||||
}
|
||||
|
||||
public void setClusters(List<Cluster> clusters) {
|
||||
this.clusters = clusters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
|
||||
import com.alibaba.nacos.api.naming.pojo.Service;
|
||||
import com.alibaba.nacos.common.util.IoUtils;
|
||||
import com.alibaba.nacos.common.util.Md5Utils;
|
||||
import com.alibaba.nacos.common.util.SystemUtil;
|
||||
@ -41,6 +43,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import org.apache.catalina.util.ParameterMap;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.codehaus.jackson.util.VersionUtil;
|
||||
@ -179,7 +182,7 @@ public class ApiCommands {
|
||||
JSONArray ipArray = new JSONArray();
|
||||
|
||||
for (IpAddress ip : ips) {
|
||||
ipArray.add(ip.toIPAddr() + "_" + ip.isValid() + "_" + ip.getInvalidType());
|
||||
ipArray.add(ip.toIPAddr() + "_" + ip.isValid());
|
||||
}
|
||||
|
||||
result.put("ips", ipArray);
|
||||
@ -237,7 +240,6 @@ public class ApiCommands {
|
||||
}
|
||||
ipPac.put("checkRT", ip.getCheckRT());
|
||||
ipPac.put("cluster", ip.getClusterName());
|
||||
ipPac.put("invalidType", ip.getInvalidType());
|
||||
|
||||
ipArray.add(ipPac);
|
||||
}
|
||||
@ -410,25 +412,25 @@ public class ApiCommands {
|
||||
}));
|
||||
}
|
||||
|
||||
if (AbstractHealthCheckConfig.Tcp.TYPE.equals(cktype)) {
|
||||
AbstractHealthCheckConfig.Tcp config = new AbstractHealthCheckConfig.Tcp();
|
||||
if (AbstractHealthChecker.Tcp.TYPE.equals(cktype)) {
|
||||
AbstractHealthChecker.Tcp config = new AbstractHealthChecker.Tcp();
|
||||
cluster.setHealthChecker(config);
|
||||
} else if (AbstractHealthCheckConfig.Http.TYPE.equals(cktype)) {
|
||||
} else if (AbstractHealthChecker.Http.TYPE.equals(cktype)) {
|
||||
|
||||
String path = BaseServlet.optional(request, "path", StringUtils.EMPTY);
|
||||
String headers = BaseServlet.optional(request, "headers", StringUtils.EMPTY);
|
||||
String expectedResponseCode = BaseServlet.optional(request, "expectedResponseCode", "200");
|
||||
|
||||
AbstractHealthCheckConfig.Http config = new AbstractHealthCheckConfig.Http();
|
||||
AbstractHealthChecker.Http config = new AbstractHealthChecker.Http();
|
||||
config.setType(cktype);
|
||||
config.setPath(path);
|
||||
config.setHeaders(headers);
|
||||
config.setExpectedResponseCode(Integer.parseInt(expectedResponseCode));
|
||||
cluster.setHealthChecker(config);
|
||||
|
||||
} else if (AbstractHealthCheckConfig.Mysql.TYPE.equals(cktype)) {
|
||||
} else if (AbstractHealthChecker.Mysql.TYPE.equals(cktype)) {
|
||||
|
||||
AbstractHealthCheckConfig.Mysql config = new AbstractHealthCheckConfig.Mysql();
|
||||
AbstractHealthChecker.Mysql config = new AbstractHealthChecker.Mysql();
|
||||
String user = BaseServlet.optional(request, "user", StringUtils.EMPTY);
|
||||
String pwd = BaseServlet.optional(request, "pwd", StringUtils.EMPTY);
|
||||
String cmd = BaseServlet.optional(request, "cmd", StringUtils.EMPTY);
|
||||
@ -472,16 +474,18 @@ public class ApiCommands {
|
||||
String ip = BaseServlet.required(request, "ip");
|
||||
String port = BaseServlet.required(request, "port");
|
||||
String weight = BaseServlet.optional(request, "weight", "1");
|
||||
String cluster = BaseServlet.optional(request, "cluster", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
|
||||
String cluster = BaseServlet.optional(request, "cluster", StringUtils.EMPTY);
|
||||
if (StringUtils.isEmpty(cluster)) {
|
||||
cluster = BaseServlet.required(request, "clusterName");
|
||||
cluster = BaseServlet.optional(request, "clusterName", UtilsAndCommons.DEFAULT_CLUSTER_NAME);
|
||||
}
|
||||
boolean enabled = BooleanUtils.toBoolean(BaseServlet.optional(request, "enable", "true"));
|
||||
|
||||
IpAddress ipAddress = new IpAddress();
|
||||
ipAddress.setPort(Integer.parseInt(port));
|
||||
ipAddress.setIp(ip);
|
||||
ipAddress.setWeight(Double.parseDouble(weight));
|
||||
ipAddress.setClusterName(cluster);
|
||||
ipAddress.setEnabled(enabled);
|
||||
|
||||
return ipAddress;
|
||||
}
|
||||
@ -518,16 +522,18 @@ public class ApiCommands {
|
||||
String tenant = BaseServlet.optional(request, "tid", StringUtils.EMPTY);
|
||||
String app = BaseServlet.optional(request, "app", "DEFAULT");
|
||||
String env = BaseServlet.optional(request, "env", StringUtils.EMPTY);
|
||||
String instanceMetadataJson = BaseServlet.optional(request, "metadata", StringUtils.EMPTY);
|
||||
String metadata = BaseServlet.optional(request, "metadata", StringUtils.EMPTY);
|
||||
|
||||
VirtualClusterDomain virtualClusterDomain = (VirtualClusterDomain) domainsManager.getDomain(dom);
|
||||
|
||||
IpAddress ipAddress = getIPAddress(request);
|
||||
Service service = new Service(dom);
|
||||
ipAddress.setApp(app);
|
||||
ipAddress.setService(service);
|
||||
ipAddress.setInstanceId(ipAddress.generateInstanceId());
|
||||
ipAddress.setLastBeat(System.currentTimeMillis());
|
||||
if (StringUtils.isNotEmpty(instanceMetadataJson)) {
|
||||
ipAddress.setMetadata(JSON.parseObject(instanceMetadataJson, new TypeReference<Map<String, String>>() {
|
||||
}));
|
||||
if (StringUtils.isNotEmpty(metadata)) {
|
||||
ipAddress.setMetadata(UtilsAndCommons.parseMetadata(metadata));
|
||||
}
|
||||
|
||||
Loggers.TENANT.debug("reg-service: " + dom + "|" + ipAddress.toJSON() + "|" + env + "|" + tenant + "|" + app);
|
||||
@ -622,16 +628,16 @@ public class ApiCommands {
|
||||
}
|
||||
|
||||
if (cktype.equals(AbstractHealthCheckProcessor.HTTP_PROCESSOR.getType())) {
|
||||
AbstractHealthCheckConfig.Http config = new AbstractHealthCheckConfig.Http();
|
||||
AbstractHealthChecker.Http config = new AbstractHealthChecker.Http();
|
||||
config.setType(cktype);
|
||||
config.setPath(BaseServlet.required(request, "path"));
|
||||
cluster.setHealthChecker(config);
|
||||
} else if (cktype.equals(AbstractHealthCheckProcessor.TCP_PROCESSOR.getType())) {
|
||||
AbstractHealthCheckConfig.Tcp config = new AbstractHealthCheckConfig.Tcp();
|
||||
AbstractHealthChecker.Tcp config = new AbstractHealthChecker.Tcp();
|
||||
config.setType(cktype);
|
||||
cluster.setHealthChecker(config);
|
||||
} else if (cktype.equals(AbstractHealthCheckProcessor.MYSQL_PROCESSOR.getType())) {
|
||||
AbstractHealthCheckConfig.Mysql config = new AbstractHealthCheckConfig.Mysql();
|
||||
AbstractHealthChecker.Mysql config = new AbstractHealthChecker.Mysql();
|
||||
config.setCmd(BaseServlet.required(request, "cmd"));
|
||||
config.setPwd(BaseServlet.required(request, "pwd"));
|
||||
config.setUser(BaseServlet.required(request, "user"));
|
||||
@ -1044,7 +1050,7 @@ public class ApiCommands {
|
||||
ipObj.put("valid", ip.isValid());
|
||||
ipObj.put("weight", ip.getWeight());
|
||||
ipObj.put("doubleWeight", ip.getWeight());
|
||||
ipObj.put("instanceId", ip.generateInstanceId());
|
||||
ipObj.put("instanceId", ip.getInstanceId());
|
||||
ipObj.put("metadata", ip.getMetadata());
|
||||
ipArray.add(ipObj);
|
||||
}
|
||||
@ -1176,10 +1182,9 @@ public class ApiCommands {
|
||||
ipObj.put("port", ip.getPort());
|
||||
ipObj.put("valid", entry.getKey());
|
||||
ipObj.put("marked", ip.isMarked());
|
||||
ipObj.put("instanceId", ip.generateInstanceId());
|
||||
ipObj.put("instanceId", ip.getInstanceId());
|
||||
ipObj.put("metadata", ip.getMetadata());
|
||||
double weight = ip.getWeight();
|
||||
|
||||
ipObj.put("enabled", ip.isEnabled());
|
||||
ipObj.put("weight", ip.getWeight());
|
||||
|
||||
hosts.add(ipObj);
|
||||
@ -1824,14 +1829,14 @@ public class ApiCommands {
|
||||
private Cluster getClusterFromJson(String json) {
|
||||
JSONObject object = JSON.parseObject(json);
|
||||
String type = object.getJSONObject("healthChecker").getString("type");
|
||||
AbstractHealthCheckConfig abstractHealthCheckConfig;
|
||||
AbstractHealthChecker abstractHealthCheckConfig;
|
||||
|
||||
if (type.equals(HealthCheckType.HTTP.name())) {
|
||||
abstractHealthCheckConfig = JSON.parseObject(object.getString("healthChecker"), AbstractHealthCheckConfig.Http.class);
|
||||
abstractHealthCheckConfig = JSON.parseObject(object.getString("healthChecker"), AbstractHealthChecker.Http.class);
|
||||
} else if (type.equals(HealthCheckType.TCP.name())) {
|
||||
abstractHealthCheckConfig = JSON.parseObject(object.getString("healthChecker"), AbstractHealthCheckConfig.Tcp.class);
|
||||
abstractHealthCheckConfig = JSON.parseObject(object.getString("healthChecker"), AbstractHealthChecker.Tcp.class);
|
||||
} else if (type.equals(HealthCheckType.MYSQL.name())) {
|
||||
abstractHealthCheckConfig = JSON.parseObject(object.getString("healthChecker"), AbstractHealthCheckConfig.Mysql.class);
|
||||
abstractHealthCheckConfig = JSON.parseObject(object.getString("healthChecker"), AbstractHealthChecker.Mysql.class);
|
||||
} else {
|
||||
throw new IllegalArgumentException("can not prase cluster from json: " + json);
|
||||
}
|
||||
@ -1889,18 +1894,18 @@ public class ApiCommands {
|
||||
}
|
||||
|
||||
if (StringUtils.equals(cktype, HealthCheckType.HTTP.name())) {
|
||||
AbstractHealthCheckConfig.Http config = new AbstractHealthCheckConfig.Http();
|
||||
AbstractHealthChecker.Http config = new AbstractHealthChecker.Http();
|
||||
config.setType(cktype);
|
||||
config.setPath(path);
|
||||
config.setHeaders(headers);
|
||||
config.setExpectedResponseCode(Integer.parseInt(expectedResponseCode));
|
||||
cluster.setHealthChecker(config);
|
||||
} else if (StringUtils.equals(cktype, HealthCheckType.TCP.name())) {
|
||||
AbstractHealthCheckConfig.Tcp config = new AbstractHealthCheckConfig.Tcp();
|
||||
AbstractHealthChecker.Tcp config = new AbstractHealthChecker.Tcp();
|
||||
config.setType(cktype);
|
||||
cluster.setHealthChecker(config);
|
||||
} else if (StringUtils.equals(cktype, HealthCheckType.MYSQL.name())) {
|
||||
AbstractHealthCheckConfig.Mysql config = new AbstractHealthCheckConfig.Mysql();
|
||||
AbstractHealthChecker.Mysql config = new AbstractHealthChecker.Mysql();
|
||||
String cmd = BaseServlet.required(request, "cmd");
|
||||
String pwd = BaseServlet.required(request, "pwd");
|
||||
String user = BaseServlet.required(request, "user");
|
||||
|
@ -1,4 +1,4 @@
|
||||
server.port=8080
|
||||
server.port=8848
|
||||
server.servlet.context-path=/nacos
|
||||
|
||||
|
||||
|
@ -82,7 +82,7 @@ public class InstanceControllerTest extends BaseTest {
|
||||
ipAddress.setPort(9999);
|
||||
List<IpAddress> ipList = new ArrayList<IpAddress>();
|
||||
ipList.add(ipAddress);
|
||||
domain.updateIPs(ipList, false);
|
||||
domain.updateIPs(ipList);
|
||||
|
||||
Mockito.when(domainsManager.getDomain("nacos.test.1")).thenReturn(domain);
|
||||
|
||||
@ -129,7 +129,7 @@ public class InstanceControllerTest extends BaseTest {
|
||||
ipAddress.setWeight(2.0);
|
||||
List<IpAddress> ipList = new ArrayList<IpAddress>();
|
||||
ipList.add(ipAddress);
|
||||
domain.updateIPs(ipList, false);
|
||||
domain.updateIPs(ipList);
|
||||
|
||||
Mockito.when(domainsManager.getDomain("nacos.test.1")).thenReturn(domain);
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.alibaba.nacos.naming.core;
|
||||
|
||||
import com.alibaba.nacos.naming.healthcheck.AbstractHealthCheckConfig;
|
||||
import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -50,7 +50,7 @@ public class ClusterTest {
|
||||
Cluster newCluster = new Cluster();
|
||||
newCluster.setDefCkport(8888);
|
||||
newCluster.setDefIPPort(9999);
|
||||
AbstractHealthCheckConfig.Http healthCheckConfig = new AbstractHealthCheckConfig.Http();
|
||||
AbstractHealthChecker.Http healthCheckConfig = new AbstractHealthChecker.Http();
|
||||
healthCheckConfig.setPath("/nacos-path-1");
|
||||
healthCheckConfig.setExpectedResponseCode(500);
|
||||
healthCheckConfig.setHeaders("Client-Version:nacos-test-1");
|
||||
@ -65,8 +65,8 @@ public class ClusterTest {
|
||||
|
||||
Assert.assertEquals(8888, cluster.getDefCkport());
|
||||
Assert.assertEquals(9999, cluster.getDefIPPort());
|
||||
Assert.assertTrue(cluster.getHealthChecker() instanceof AbstractHealthCheckConfig.Http);
|
||||
AbstractHealthCheckConfig.Http httpHealthCheck = (AbstractHealthCheckConfig.Http)(cluster.getHealthChecker());
|
||||
Assert.assertTrue(cluster.getHealthChecker() instanceof AbstractHealthChecker.Http);
|
||||
AbstractHealthChecker.Http httpHealthCheck = (AbstractHealthChecker.Http)(cluster.getHealthChecker());
|
||||
Assert.assertEquals("/nacos-path-1", httpHealthCheck.getPath());
|
||||
Assert.assertEquals(500, httpHealthCheck.getExpectedResponseCode());
|
||||
Assert.assertEquals("Client-Version:nacos-test-1", httpHealthCheck.getHeaders());
|
||||
@ -87,7 +87,7 @@ public class ClusterTest {
|
||||
list.add(ipAddress1);
|
||||
list.add(ipAddress2);
|
||||
|
||||
cluster.updateIPs(list, false);
|
||||
cluster.updateIPs(list);
|
||||
|
||||
List<IpAddress> ips = cluster.allIPs();
|
||||
Assert.assertNotNull(ips);
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.alibaba.nacos.test.naming;
|
||||
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.naming.NamingFactory;
|
||||
import com.alibaba.nacos.api.naming.NamingService;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
@ -29,7 +30,9 @@ import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.alibaba.nacos.test.naming.NamingBase.*;
|
||||
@ -56,6 +59,48 @@ public class SelectInstances_ITCase {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getAllInstances() throws Exception {
|
||||
|
||||
// final String serviceName = "dungu.test.100";
|
||||
// naming.registerInstance(serviceName, "127.0.0.1", TEST_PORT);
|
||||
//
|
||||
//
|
||||
//
|
||||
// Thread thread = new Thread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// try {
|
||||
// TimeUnit.SECONDS.sleep(10);
|
||||
// naming.deregisterInstance(serviceName, "127.0.0.1", TEST_PORT);
|
||||
// System.out.println("deregister ok!");
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// thread.start();
|
||||
//
|
||||
//
|
||||
// while (true) {
|
||||
//
|
||||
// System.out.println(new Date());
|
||||
// System.out.println(naming.getAllInstances("dungu.test.100"));
|
||||
//
|
||||
// TimeUnit.SECONDS.sleep(1);
|
||||
// }
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deregister() throws NacosException {
|
||||
// String serviceName = "dungu.test.100";
|
||||
// naming.deregisterInstance(serviceName, "127.0.0.1", TEST_PORT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有健康的Instance
|
||||
* @throws Exception
|
||||
|
Loading…
Reference in New Issue
Block a user