Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -439,15 +439,15 @@ public class ServerOptions extends OptionHolder {
"arthas.ip",
"arthas bound ip",
disallowEmpty(),
"0.0.0.0"
"127.0.0.1"
);

public static final ConfigOption<String> ARTHAS_DISABLED_COMMANDS =
new ConfigOption<>(
"arthas.disabledCommands",
"arthas disabled commands",
disallowEmpty(),
"jad"
"jad,ognl,vmtool"
);

public static final ConfigOption<Boolean> ALLOW_TRACE =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ batch.max_write_ratio=80
batch.max_write_threads=0

# configuration of arthas
arthas.telnet_port=8562
arthas.http_port=8561
arthas.telnetPort=8562
arthas.httpPort=8561
arthas.ip=127.0.0.1
arthas.disabled_commands=jad
arthas.disabledCommands=jad,ognl,vmtool

# authentication configs
#auth.authenticator=org.apache.hugegraph.auth.StandardAuthenticator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,10 @@ public class ArthasConfig {
@Value("${arthas.httpPort:8565}")
private String httpPort;

@Value("${arthas.ip:0.0.0.0}")
@Value("${arthas.ip:127.0.0.1}")
private String arthasip;

@Value("${arthas.disabledCommands:jad}")
@Value("${arthas.disabledCommands:jad,ognl,vmtool}")
private String disCmd;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.hugegraph.pd.common.PDException;
import org.apache.hugegraph.pd.grpc.Metapb;
import org.apache.hugegraph.rocksdb.access.RocksDBSession;
Expand All @@ -37,7 +39,9 @@
import org.apache.hugegraph.store.node.grpc.HgStoreNodeService;
import org.apache.hugegraph.util.Bytes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -64,7 +68,7 @@ public class PartitionAPI {
AppConfig appConfig;

@GetMapping(value = "/partitions", produces = "application/json")
public Map<String, Object> getPartitions(
public ResponseEntity<Map<String, Object>> getPartitions(
@RequestParam(required = false, defaultValue = "") String flags) {

boolean accurate = false;
Expand Down Expand Up @@ -109,7 +113,7 @@ public Map<String, Object> getPartitions(
rafts.add(raft);
}

return okMap("partitions", rafts);
return ResponseEntity.status(HttpStatus.OK).body(okMap("partitions", rafts));
}

@GetMapping(value = "/partition/{id}", produces = "application/json")
Expand Down Expand Up @@ -146,8 +150,8 @@ public Raft getPartition(@PathVariable(value = "id") int id) {
* Print all keys in the partition
*/
@GetMapping(value = "/partition/dump/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, Object> dumpPartition(@PathVariable(value = "id") int id) throws
PDException {
public ResponseEntity<Map<String, Object>> dumpPartition(
@PathVariable(value = "id") int id) throws PDException {
HgStoreEngine storeEngine = nodeService.getStoreEngine();
BusinessHandler handler = storeEngine.getBusinessHandler();
InnerKeyCreator innerKeyCreator = new InnerKeyCreator(handler);
Expand All @@ -168,27 +172,45 @@ public Map<String, Object> dumpPartition(@PathVariable(value = "id") int id) thr
}
cfIterator.close();
});
return okMap("ok", null);
return ResponseEntity.status(HttpStatus.OK).body(okMap("ok", null));
}

/**
* Print all keys in the partition
*/
@GetMapping(value = "/partition/clean/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, Object> cleanPartition(@PathVariable(value = "id") int id) throws
PDException {
public ResponseEntity<Map<String, Object>> cleanPartition(
@PathVariable(value = "id") int id) throws PDException {
HgStoreEngine storeEngine = nodeService.getStoreEngine();
BusinessHandler handler = storeEngine.getBusinessHandler();

storeEngine.getPartitionEngine(id).getPartitions().forEach((graph, partition) -> {
handler.cleanPartition(graph, id);
});
return okMap("ok", null);
return ResponseEntity.status(HttpStatus.OK).body(okMap("ok", null));
}

@GetMapping(value = "/arthasstart", produces = "application/json")
public Map<String, Object> arthasstart(
@RequestParam(required = false, defaultValue = "") String flags) {
public ResponseEntity<Map<String, Object>> arthasstart(
@RequestParam(required = false, defaultValue = "") String flags,
HttpServletRequest request) {
if (request == null) {
log.error("Security Alert: HttpServletRequest is NULL when accessing /arthasstart. " +
"Access denied.");
Map<String, Object> err = new HashMap<>();
err.put("status", "ERROR");
err.put("message", "Internal Error: Cannot determine client IP.");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(err);
}
String remoteAddr = getClientIp(request);
boolean isLocalRequest =
"127.0.0.1".equals(remoteAddr) || "[0:0:0:0:0:0:0:1]".equals(remoteAddr);
if (!isLocalRequest) {
List<String> ret = new ArrayList<>();
ret.add("Arthas start is ONLY allowed from localhost.");
return ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(forbiddenMap("arthasstart", ret));
}
HashMap<String, String> configMap = new HashMap<>();
configMap.put("arthas.telnetPort", appConfig.getArthasConfig().getTelnetPort());
configMap.put("arthas.httpPort", appConfig.getArthasConfig().getHttpPort());
Expand All @@ -198,11 +220,11 @@ public Map<String, Object> arthasstart(
// DashResponse retPose = new DashResponse();
List<String> ret = new ArrayList<>();
ret.add("Arthas started successfully");
return okMap("arthasstart", ret);
return ResponseEntity.status(HttpStatus.OK).body(okMap("arthasstart", ret));
}

@PostMapping("/compat")
public Map<String, Object> compact(@RequestParam(value = "id") int id) {
public ResponseEntity<Map<String, Object>> compact(@RequestParam(value = "id") int id) {
boolean submitted =
nodeService.getStoreEngine().getBusinessHandler().blockingCompact("", id);
Map<String, Object> map = new HashMap<>();
Expand All @@ -215,7 +237,7 @@ public Map<String, Object> compact(@RequestParam(value = "id") int id) {
map.put("msg",
"compaction task fail to submit, and there could be another task in progress");
}
return map;
return ResponseEntity.status(HttpStatus.OK).body(map);
}

public Map<String, Object> okMap(String k, Object v) {
Expand All @@ -225,6 +247,34 @@ public Map<String, Object> okMap(String k, Object v) {
return map;
}

public Map<String, Object> forbiddenMap(String k, Object v) {
HashMap<String, Object> map = new HashMap<>();
map.put("status", 403);
map.put(k, v);
return map;
}

private String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}

if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
return ip;
}

@Data
public class Raft {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,10 @@ logging:
config: classpath:log4j2-dev.xml
level:
root: info

arthas:
telnetPort: 8566
httpPort: 8565
# Only allow starting arthas locally
ip: 127.0.0.1
disabledCommands: jad,ognl,vmtool
Loading