new_educoder_dev merge dev

This commit is contained in:
jiangzhongxiang 2019-06-05 10:30:34 +08:00
commit dd403ecc32
109 changed files with 12292 additions and 3374 deletions

1
.gitignore vendored
View File

@ -8,5 +8,4 @@ target/
.settings/
*.log
bin/
src/test/
src/main/java/test/

68
pom.xml
View File

@ -128,6 +128,11 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
@ -145,9 +150,20 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.6.RELEASE</version>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
@ -165,6 +181,12 @@
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-crypto-hash</artifactId>
<version>1.4.1</version>
</dependency>
<!-- logback -->
<dependency>
@ -212,7 +234,49 @@
<artifactId>quartz-jobs</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore-nio</artifactId>
<version>4.4.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.9</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.0</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,22 @@
package com.educoder.bridge.alarm.constant;
public interface AlarmCsts {
/**
* 告警规则启用
*/
String ALARM_RULE_ENABLE = "1";
/**
* 告警规则停用
*/
String ALARM_RULE_DISABLE = "0";
/**
* 消防警察启用
*/
String FIRE_POLICE_ENABLE = "1";
/**
* 消防警察停用
*/
String FIRE_POLICE_DISABLE = "0";
}

View File

@ -0,0 +1,57 @@
package com.educoder.bridge.alarm.controller;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.educoder.bridge.alarm.model.Alarm;
import com.educoder.bridge.common.model.ApiResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* 告警相关的接口
*
* @author jiangzhongxiang
*/
@Api(value = "告警", hidden = true)
@RestController
@RequestMapping("/alarms")
public class AlarmController {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* 获取告警列表
*/
@RequestMapping(path = "/list", method = RequestMethod.POST)
@ApiOperation(value = "获取告警列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<List<Alarm>> getAlarms() throws Exception {
logger.info("获取告警列表");
ApiResult<List<Alarm>> result = new ApiResult<>();
return result;
}
/**
* 修改告警
*/
@RequestMapping(path = "/{id}", method = RequestMethod.PUT)
@ApiOperation(value = "修改告警", httpMethod = "PUT", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<Alarm> updateAlarms(@PathVariable("id") String id, @RequestBody Alarm Alarm) throws Exception {
logger.info("修改告警{}", id);
ApiResult<Alarm> result = new ApiResult<>();
return result;
}
}

View File

@ -0,0 +1,81 @@
package com.educoder.bridge.alarm.controller;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.educoder.bridge.alarm.model.AlarmRule;
import com.educoder.bridge.alarm.service.AlarmService;
import com.educoder.bridge.common.model.ApiResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* 告警规则相关的接口
*
* @author jiangzhongxiang
*/
@Api(value = "告警规则", hidden = true)
@RestController
@RequestMapping("/alarmrules")
public class AlarmRuleController {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private AlarmService alarmService;
/**
* 获取告警规则列表
*/
@RequestMapping(path = "/list", method = RequestMethod.POST)
@ApiOperation(value = "获取告警规则列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<List<AlarmRule>> getAlarmRules(@RequestBody(required = false) Map<String, Object> param)
throws Exception {
logger.info("获取告警规则列表");
ApiResult<List<AlarmRule>> result = new ApiResult<>();
List<AlarmRule> list = alarmService.getAlarmRules(param);
result.setData(list);
return result;
}
/**
* 创建告警规则
*/
@RequestMapping(path = "", method = RequestMethod.POST)
@ApiOperation(value = "创建告警规则", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<AlarmRule> createAlarmRules(@RequestBody AlarmRule alarmRule) throws Exception {
logger.info("创建告警规则[{}]阈值[{}]", alarmRule.getName(), alarmRule.getThreshold());
ApiResult<AlarmRule> result = new ApiResult<>();
alarmRule = alarmService.createAlarmRule(alarmRule);
result.setData(alarmRule);
return result;
}
/**
* 修改告警规则
*/
@RequestMapping(path = "/{id}", method = RequestMethod.PUT)
@ApiOperation(value = "修改告警规则", httpMethod = "PUT", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<AlarmRule> updateAlarmRules(@PathVariable("id") String id, @RequestBody AlarmRule alarmRule)
throws Exception {
logger.info("修改告警规则{}", id);
ApiResult<AlarmRule> result = new ApiResult<>();
alarmRule.setId(Long.parseLong(id));
alarmRule = alarmService.updateAlarmRule(alarmRule);
result.setData(alarmRule);
return result;
}
}

View File

@ -0,0 +1,82 @@
package com.educoder.bridge.alarm.controller;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.educoder.bridge.alarm.model.FirePolice;
import com.educoder.bridge.alarm.service.FirePoliceService;
import com.educoder.bridge.common.model.ApiResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* 告警人员相关的接口
*
* @author jiangzhongxiang
*/
@Api(value = "告警人员", hidden = true)
@RestController
@RequestMapping("/firepolices")
public class FirePoliceController {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private FirePoliceService firePoliceService;
/**
* 获取告警人员列表
*/
@RequestMapping(path = "/list", method = RequestMethod.POST)
@ApiOperation(value = "获取告警人员列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<List<FirePolice>> getFirePolices(@RequestBody(required = false) Map<String, Object> param)
throws Exception {
logger.info("获取告警人员列表");
ApiResult<List<FirePolice>> result = new ApiResult<>();
List<FirePolice> list = firePoliceService.getFirePolices(param);
result.setData(list);
return result;
}
/**
* 创建告警人员
*/
@RequestMapping(path = "", method = RequestMethod.POST)
@ApiOperation(value = "创建告警人员", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<FirePolice> createFirePolices(@RequestBody FirePolice firePolice) throws Exception {
logger.info("创建告警人员");
ApiResult<FirePolice> result = new ApiResult<>();
firePolice = firePoliceService.createFirePolice(firePolice);
result.setData(firePolice);
return result;
}
/**
* 修改告警人员
*/
@RequestMapping(path = "/{id}", method = RequestMethod.PUT)
@ApiOperation(value = "修改告警人员", httpMethod = "PUT", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<FirePolice> updateFirePolices(@PathVariable("id") String id, @RequestBody FirePolice firePolice)
throws Exception {
logger.info("修改告警人员{}", id);
ApiResult<FirePolice> result = new ApiResult<>();
firePolice.setId(Long.parseLong(id));
firePolice = firePoliceService.updateFirePolice(firePolice);
result.setData(firePolice);
return result;
}
}

View File

@ -0,0 +1,22 @@
package com.educoder.bridge.alarm.dao;
import java.util.List;
import java.util.Map;
import com.educoder.bridge.alarm.model.AlarmRule;
public interface AlarmRuleMapper {
int deleteByPrimaryKey(Long id);
int insert(AlarmRule record);
int insertSelective(AlarmRule record);
AlarmRule selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(AlarmRule record);
int updateByPrimaryKey(AlarmRule record);
List<AlarmRule> selectAlarmRule(Map<String, Object> param);
}

View File

@ -0,0 +1,22 @@
package com.educoder.bridge.alarm.dao;
import java.util.List;
import java.util.Map;
import com.educoder.bridge.alarm.model.FirePolice;
public interface FirePoliceMapper {
int deleteByPrimaryKey(Long id);
int insert(FirePolice record);
int insertSelective(FirePolice record);
FirePolice selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(FirePolice record);
int updateByPrimaryKey(FirePolice record);
List<FirePolice> selectFirePolice(Map<String, Object> param);
}

View File

@ -0,0 +1,94 @@
package com.educoder.bridge.alarm.model;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "告警", description = "告警")
public class Alarm {
@ApiModelProperty(value = "告警id")
private String id;
@ApiModelProperty(value = "告警名称")
private String name;
@ApiModelProperty(value = "告警阈值")
private String threshold;
@ApiModelProperty(value = "告警方式")
private AlarmWay alarmWay;
@ApiModelProperty(value = "告警值")
private String val;
@ApiModelProperty(value = "规则创建时间")
private LocalDateTime createTime;
@ApiModelProperty(value = "规则更新时间")
private LocalDateTime updateTime;
@ApiModelProperty(value = "告警状态0,创建; 1,发送成功; 2,处理成功")
private String status;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getThreshold() {
return threshold;
}
public void setThreshold(String threshold) {
this.threshold = threshold;
}
public AlarmWay getAlarmWay() {
return alarmWay;
}
public void setAlarmWay(AlarmWay alarmWay) {
this.alarmWay = alarmWay;
}
public String getVal() {
return val;
}
public void setVal(String val) {
this.val = val;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@ -0,0 +1,83 @@
package com.educoder.bridge.alarm.model;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "告警规则", description = "告警规则")
public class AlarmRule {
@ApiModelProperty(value = "告警规则id")
private Long id;
@ApiModelProperty(value = "告警规则名称")
private String name;
@ApiModelProperty(value = "告警阈值")
private String threshold;
@ApiModelProperty(value = "告警方式")
private AlarmWay alarmWay;
@ApiModelProperty(value = "规则创建时间")
private LocalDateTime createTime;
@ApiModelProperty(value = "规则更新时间")
private LocalDateTime updateTime;
@ApiModelProperty(value = "告警状态0,停用; 1,启用.")
private String status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getThreshold() {
return threshold;
}
public void setThreshold(String threshold) {
this.threshold = threshold;
}
public AlarmWay getAlarmWay() {
return alarmWay;
}
public void setAlarmWay(AlarmWay alarmWay) {
this.alarmWay = alarmWay;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@ -0,0 +1,7 @@
package com.educoder.bridge.alarm.model;
public enum AlarmWay {
EMAIL, MOBILE;
}

View File

@ -0,0 +1,83 @@
package com.educoder.bridge.alarm.model;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "消防警察", description = "消防警察")
public class FirePolice {
@ApiModelProperty(value = "告警规则id")
private Long id;
@ApiModelProperty(value = "名称")
private String name;
@ApiModelProperty(value = "邮箱")
private String email;
@ApiModelProperty(value = "手机")
private String mobile;
@ApiModelProperty(value = "规则创建时间")
private LocalDateTime createTime;
@ApiModelProperty(value = "规则更新时间")
private LocalDateTime updateTime;
@ApiModelProperty(value = "告警状态0,停用; 1,启用.")
private String status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@ -0,0 +1,38 @@
package com.educoder.bridge.alarm.service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.educoder.bridge.alarm.constant.AlarmCsts;
import com.educoder.bridge.alarm.dao.AlarmRuleMapper;
import com.educoder.bridge.alarm.model.AlarmRule;
@Service
public class AlarmService {
@Autowired
private AlarmRuleMapper alarmRuleMapper;
public List<AlarmRule> getAlarmRules(Map<String,Object > param) {
return alarmRuleMapper.selectAlarmRule(param);
}
public AlarmRule createAlarmRule(AlarmRule alarmRule) {
alarmRule.setCreateTime(LocalDateTime.now());
alarmRule.setUpdateTime(LocalDateTime.now());
alarmRule.setStatus(AlarmCsts.ALARM_RULE_ENABLE);
alarmRuleMapper.insert(alarmRule);
return alarmRuleMapper.selectByPrimaryKey(alarmRule.getId());
}
public AlarmRule updateAlarmRule(AlarmRule alarmRule) {
alarmRule.setUpdateTime(LocalDateTime.now());
alarmRuleMapper.updateByPrimaryKeySelective(alarmRule);
return alarmRuleMapper.selectByPrimaryKey(alarmRule.getId());
}
}

View File

@ -0,0 +1,38 @@
package com.educoder.bridge.alarm.service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.educoder.bridge.alarm.constant.AlarmCsts;
import com.educoder.bridge.alarm.dao.FirePoliceMapper;
import com.educoder.bridge.alarm.model.FirePolice;
@Service
public class FirePoliceService {
@Autowired
private FirePoliceMapper FirePoliceMapper;
public List<FirePolice> getFirePolices(Map<String, Object> param) {
return FirePoliceMapper.selectFirePolice(param);
}
public FirePolice createFirePolice(FirePolice firePolice) {
firePolice.setCreateTime(LocalDateTime.now());
firePolice.setUpdateTime(LocalDateTime.now());
firePolice.setStatus(AlarmCsts.FIRE_POLICE_ENABLE);
FirePoliceMapper.insert(firePolice);
return FirePoliceMapper.selectByPrimaryKey(firePolice.getId());
}
public FirePolice updateFirePolice(FirePolice firePolice) {
firePolice.setUpdateTime(LocalDateTime.now());
FirePoliceMapper.updateByPrimaryKeySelective(firePolice);
return FirePoliceMapper.selectByPrimaryKey(firePolice.getId());
}
}

View File

@ -0,0 +1,7 @@
package com.educoder.bridge.common.constant;
public interface ApiResultCodeCsts {
int SUCCESS = 0;
int FAIL = -1;
}

View File

@ -0,0 +1,30 @@
package com.educoder.bridge.common.constant;
public interface BuildResultCsts {
/**
* 完整结果正则
*
*/
// \{ 匹配 { , [\s]* 匹配0-多个空白字符, "compileResult"[\s]*:匹配"compileResult":
// [\s\S]*匹配0-多个任意字符, [\s\S]*"out"[\s]*:匹配"out": , [^}]*匹配除}之外的所有字符
String FULL_RESULT_REG = "\\{[\\s]*\"compileResult\"[\\s]*:[\\s\\S]*\"out\"[\\s]*:[^}]*}";
/**
* 文本消息前缀
*/
String TEXT_RESULT_PRE = "educoder:";
/**
* 文本消息前缀长度
*/
int TEXT_RESULT_PRE_LEN = TEXT_RESULT_PRE.length();
String DOWNLOAD_STATUS = "downloadStatus";
String DOWNLOAD_STATUS_SUCCESS = "1";
String DOWNLOAD_STATUS_FAIL = "0";
String CREATE_POD_STATUS = "createPodStatus";
String CREATE_POD_STATUS_SUCCESS = "1";
String CREATE_POD_STATUS_FAIL = "0";
}

View File

@ -1,28 +0,0 @@
package com.educoder.bridge.common.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ModelAttribute;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @author lqk
* @version 0.1
*/
public class BaseController {
protected HttpServletRequest request;
protected HttpServletResponse response;
protected HttpSession session;
protected final static Logger logger = LoggerFactory.getLogger(BaseController.class);
@ModelAttribute
public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
this.session = request.getSession();
}
}

View File

@ -0,0 +1,37 @@
package com.educoder.bridge.common.model;
import com.educoder.bridge.common.constant.ApiResultCodeCsts;
public class ApiResult<T> {
private int code = ApiResultCodeCsts.SUCCESS;
private String msg;
private T data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}

View File

@ -0,0 +1,53 @@
package com.educoder.bridge.common.model;
import java.util.List;
import com.github.pagehelper.Page;
public class BridgePage<T> {
private List<T> data;
private Integer pageNum;
private Integer pageSize;
private Long total;
public BridgePage(Page<T> page) {
this.data = page.getResult();
this.pageNum = page.getPageNum();
this.pageSize = page.getPageSize();
this.total = page.getTotal();
}
public List<T> getData() {
return data;
}
public void setData(List<T> data) {
this.data = data;
}
public Integer getPageNum() {
return pageNum;
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
}

View File

@ -11,151 +11,154 @@ import org.springframework.context.annotation.PropertySource;
@PropertySource("classpath:config_${spring.profiles.active}.properties")
public class AppConfig {
@Value("${educoderURL}")
private String educoderURL;
@Value("${educoderURL}")
private String educoderURL;
@Value("${workspace}")
private String workspace;
@Value("${simpileEducoderURL}")
private String simpileEducoderURL;
@Value("${maxRunningPodNum}")
private String maxRunningPodNum;
@Value("${workspace}")
private String workspace;
@Value("${defaultTimeLimit}")
private String defaultTimeLimit;
@Value("${maxRunningPodNum}")
private String maxRunningPodNum;
@Value("${k8sServer}")
private String k8sServer;
@Value("${k8sUser}")
private String k8sUser;
@Value("${k8sPasswd}")
private String k8sPasswd;
@Value("${defaultTimeLimit}")
private String defaultTimeLimit;
@Value("${dockerMaster}")
private String dockerMaster;
@Value("${dockerDeputies}")
private String dockerDeputies;
@Value("${registry}")
private String registry;
@Value("${k8sServer}")
private String k8sServer;
@Value("${k8sUser}")
private String k8sUser;
@Value("${k8sPasswd}")
private String k8sPasswd;
@Value("${cpuAllocatable}")
private String cpuAllocatable;
@Value("${memAllocatable}")
private String memAllocatable;
@Value("${dockerMaster}")
private String dockerMaster;
@Value("${dockerDeputies}")
private String dockerDeputies;
@Value("${registry}")
private String registry;
@Value("${gitIP}")
private String gitIP;
@Value("${cpuAllocatable}")
private String cpuAllocatable;
@Value("${memAllocatable}")
private String memAllocatable;
@Value("${gitIP}")
private String gitIP;
@Value("${gitBackUpIP}")
private String gitBackUpIP;
@Value("${outputSize}")
private String outputSize;
@Value("${secretKey}")
private String secretKey;
@Value("${secretKey}")
private String secretKey;
@Value("${websocket.addr}")
private String serverUrl;
@Value("${websocket.addr}")
private String serverUrl;
@Value("${gpuImage}")
private String gpuImage;
@Value("${gpuImage}")
private String gpuImage;
@Value("${gitUsername}")
private String gitUsername;
@Value("${vncPort}")
private Integer vncPort;
@Value("${gitPassword}")
private String gitPassword;
public String getServerUrl() {
return serverUrl;
}
public String getServerUrl() {
return serverUrl;
public void setServerUrl(String serverUrl) {
this.serverUrl = serverUrl;
}
public String getEducoderURL() {
return educoderURL;
}
public String getSimpileEducoderURL() {
return simpileEducoderURL;
}
public String getWorkspace() {
return workspace;
}
public String getMaxRunningPodNum() {
return maxRunningPodNum;
}
public String getDefaultTimeLimit() {
return defaultTimeLimit;
}
public String getK8sServer() {
return k8sServer;
}
public String getK8sUser() {
return k8sUser;
}
public String getK8sPasswd() {
return k8sPasswd;
}
public String getCpuAllocatable() {
return cpuAllocatable;
}
public String getMemAllocatable() {
return memAllocatable;
}
public String getGitBackUpIP() {
return gitBackUpIP;
}
public void setServerUrl(String serverUrl) {
this.serverUrl = serverUrl;
}
public String getGitIP() {
return gitIP;
}
public String getEducoderURL() {
return educoderURL;
}
public String getDockerMaster() {
return dockerMaster;
}
public String getWorkspace() {
return workspace;
}
public String getDockerDeputies() {
return dockerDeputies;
}
public String getMaxRunningPodNum() {
return maxRunningPodNum;
}
public String getRegistry() {
return registry;
}
public String getDefaultTimeLimit() {
return defaultTimeLimit;
}
public String getOutputSize() {
return outputSize;
}
public String getK8sServer() {
return k8sServer;
}
public String getSecretKey() {
return secretKey;
}
public String getK8sUser() {
return k8sUser;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getK8sPasswd() {
return k8sPasswd;
}
public String getGpuImage() {
return gpuImage;
}
public String getCpuAllocatable() {
return cpuAllocatable;
}
public void setGpuImage(String gpuImage) {
this.gpuImage = gpuImage;
}
public String getMemAllocatable() {
return memAllocatable;
}
public Integer getVncPort() {
return vncPort;
}
public String getGitIP() {
return gitIP;
}
public String getDockerMaster() {
return dockerMaster;
}
public String getDockerDeputies() {
return dockerDeputies;
}
public String getRegistry() {
return registry;
}
public String getOutputSize() {
return outputSize;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getGpuImage() {
return gpuImage;
}
public void setGpuImage(String gpuImage) {
this.gpuImage = gpuImage;
}
public String getGitUsername() {
return gitUsername;
}
public void setGitUsername(String gitUsername) {
this.gitUsername = gitUsername;
}
public String getGitPassword() {
return gitPassword;
}
public void setGitPassword(String gitPassword) {
this.gitPassword = gitPassword;
}
public void setVncPort(Integer vncPort) {
this.vncPort = vncPort;
}
}

View File

@ -0,0 +1,147 @@
package com.educoder.bridge.common.settings;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
@Configuration
public class DateConfig {
/** 默认日期时间格式 */
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
/** 默认日期格式 */
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
/** 默认时间格式 */
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
/**
* LocalDate转换器用于转换RequestParam和PathVariable参数
*/
@Bean
public Converter<String, LocalDate> localDateConverter() {
return new Converter<String, LocalDate>() {
@Override
public LocalDate convert(String source) {
return LocalDate.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));
}
};
}
/**
* LocalDateTime转换器用于转换RequestParam和PathVariable参数
*/
@Bean
public Converter<String, LocalDateTime> localDateTimeConverter() {
return new Converter<String, LocalDateTime>() {
@Override
public LocalDateTime convert(String source) {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT));
}
};
}
/**
* LocalTime转换器用于转换RequestParam和PathVariable参数
*/
@Bean
public Converter<String, LocalTime> localTimeConverter() {
return new Converter<String, LocalTime>() {
@Override
public LocalTime convert(String source) {
return LocalTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT));
}
};
}
/**
* Date转换器用于转换RequestParam和PathVariable参数
*/
@Bean
public Converter<String, Date> dateConverter() {
return new Converter<String, Date>() {
@Override
public Date convert(String source) {
SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
try {
return format.parse(source);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
};
}
/**
* Json序列化和反序列化转换器用于转换Post请求体中的json以及将我们的对象序列化为返回响应的json
*/
@Bean("objectMapper")
public ObjectMapper objectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
//LocalDateTime系列序列化和反序列化模块继承自jsr310我们在这里修改了日期格式
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
javaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
javaTimeModule.addSerializer(LocalTime.class,new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
javaTimeModule.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
javaTimeModule.addDeserializer(LocalTime.class,new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//Date序列化和反序列化
javaTimeModule.addSerializer(Date.class, new JsonSerializer<Date>() {
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
SimpleDateFormat formatter = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
String formattedDate = formatter.format(date);
jsonGenerator.writeString(formattedDate);
}
});
javaTimeModule.addDeserializer(Date.class, new JsonDeserializer<Date>() {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
String date = jsonParser.getText();
try {
return format.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
});
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
}

View File

@ -10,23 +10,36 @@
*/
package com.educoder.bridge.common.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* <一句话功能简述>
* <功能详细描述>
* @author liliy
* @version [版本号2017年6月13日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
public class BeanFactory {
static ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
public static Object getObejct(String className){
Object object = ctx.getBean(className);
/**
* <一句话功能简述> <功能详细描述>
*
* @author liliy
* @version [版本号2017年6月13日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
@Component
public class BeanFactory implements ApplicationContextAware {
private static ApplicationContext ctx = null;
public static Object getObejct(String name) {
Object object = ctx.getBean(name);
return object;
}
public static <T> T getObejct(Class<T> requiredType) {
return ctx.getBean(requiredType);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanFactory.ctx = applicationContext;
}
}

View File

@ -1,70 +1,69 @@
package com.educoder.bridge.common.utils;
import com.educoder.bridge.common.settings.AppConfig;
import com.spotify.docker.client.DefaultDockerClient;
import com.spotify.docker.client.DockerClient;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import com.educoder.bridge.common.settings.AppConfig;
import com.spotify.docker.client.DefaultDockerClient;
import com.spotify.docker.client.DockerClient;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
/**
* Created by zzx on 17/11/30.
*/
public class ClientUtil {
private static KubernetesClient client;
private static DockerClient docker;
private static List<DockerClient> dockerDeputies = new ArrayList<>();
private static volatile KubernetesClient client;
private static volatile DockerClient docker;
private static final List<DockerClient> dockerDeputies = new ArrayList<>();
public synchronized static KubernetesClient getClient() {
if (client != null) {
return client;
}
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
Config config = new ConfigBuilder()
.withMasterUrl(appConfig.getK8sServer())
.withNamespace("default")
.withTrustCerts(true)
.withUsername(appConfig.getK8sUser())
.withPassword(appConfig.getK8sPasswd())
.build();
try {
client = new DefaultKubernetesClient(config);
} catch (Exception e) {
e.printStackTrace();
}
return client;
}
public static KubernetesClient getClient() {
if (client == null) {
synchronized (ClientUtil.class) {
if (client == null) {
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
Config config = new ConfigBuilder().withMasterUrl(appConfig.getK8sServer()).withNamespace("default")
.withTrustCerts(true).withUsername(appConfig.getK8sUser())
.withPassword(appConfig.getK8sPasswd()).build();
client = new DefaultKubernetesClient(config);
}
}
}
return client;
}
public synchronized static DockerClient getDocker() {
if (docker != null) {
return docker;
}
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
try {
docker = DefaultDockerClient.builder().uri(URI.create(appConfig.getDockerMaster())).build();
} catch (Exception e) {
e.printStackTrace();
}
return docker;
}
public static DockerClient getDocker() {
if (docker == null) {
synchronized (ClientUtil.class) {
if (docker == null) {
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
docker = DefaultDockerClient.builder().uri(URI.create(appConfig.getDockerMaster())).build();
}
}
}
public synchronized static List<DockerClient> getDockerDeputies() {
if (dockerDeputies != null && dockerDeputies.size() > 0) {
return dockerDeputies;
}
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
String deputies = appConfig.getDockerDeputies();
String[] ips = deputies.split(";");
// 为每一个节点返回一个docker客户端
for (int i = 0; i < ips.length; i++) {
dockerDeputies.add(DefaultDockerClient.builder().uri(URI.create(ips[i])).build());
}
return docker;
}
return dockerDeputies;
}
public static List<DockerClient> getDockerDeputies() {
if (dockerDeputies.size() == 0) {
synchronized (ClientUtil.class) {
if (dockerDeputies.size() == 0) {
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("AppConfig");
String deputies = appConfig.getDockerDeputies();
String[] ips = deputies.split(";");
// 为每一个节点返回一个docker客户端
for (int i = 0; i < ips.length; i++) {
dockerDeputies.add(DefaultDockerClient.builder().uri(URI.create(ips[i])).build());
}
}
}
}
return dockerDeputies;
}
}

View File

@ -1,12 +1,5 @@
package com.educoder.bridge.common.utils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
@ -14,6 +7,14 @@ import java.time.LocalDateTime;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.constant.BuildResultCsts;
/**
* 业务相关的字符串帮助类
*
@ -22,306 +23,335 @@ import java.util.regex.Pattern;
**/
public class GameHelper {
private static final Logger logger = LoggerFactory.getLogger(GameHelper.class);
private static final Logger logger = LoggerFactory.getLogger(GameHelper.class);
/**
* 通过gitURL获取版本库名字
* @param gitURL 版本库地址
* @return 版本库名字
*/
public static String getRepoName(String gitURL) {
String repoName = gitURL.substring(gitURL.lastIndexOf("/") + 1, gitURL.lastIndexOf("."));
return repoName;
}
/**
* 通过gitURL获取版本库名字
*
* @param gitURL
* 版本库地址
* @return 版本库名字
*/
public static String getRepoName(String gitURL) {
String repoName = gitURL.substring(gitURL.lastIndexOf("/") + 1, gitURL.lastIndexOf("."));
return repoName;
}
/**
* 通过gitUrl获取用户的identifier
* @param gitURL
* @return 用户identifier
*/
public static String getIdentifier(String gitURL) {
String tmp = gitURL.substring(0, gitURL.lastIndexOf("/"));
return tmp.substring(tmp.lastIndexOf("/") + 1);
}
/**
* 通过gitUrl获取用户的identifier
*
* @param gitURL
* @return 用户identifier
*/
public static String getIdentifier(String gitURL) {
String tmp = gitURL.substring(0, gitURL.lastIndexOf("/"));
return tmp.substring(tmp.lastIndexOf("/") + 1);
}
/**
* tpmRepoName存在于tpi工作目录且tpiRepoName不存在若tpmRepoName与tpiRepoName异名,则需将tpmRepoName改名
*
* @param tpiWorkSpace 工作目录
* @param tpiRepoName tpi版本库名字
* @param tpmRepoName tpm版本库名字
* @return
*/
public static boolean ensurelocalRepoName(String tpiWorkSpace, String tpiRepoName, String tpmRepoName) {
try {
if (!tpiRepoName.equals(tpmRepoName)) {
Files.move(Paths.get(tpiWorkSpace, tpmRepoName), Paths.get(tpiWorkSpace, tpiRepoName));
}
return true;
} catch (Exception e) {
logger.error("tpmRepoName: {}重命名为tpiRepoName: {}失败,路径为: {}", tpmRepoName, tpiRepoName, tpiWorkSpace);
return false;
}
}
/**
* tpmRepoName存在于tpi工作目录且tpiRepoName不存在若tpmRepoName与tpiRepoName异名,则需将tpmRepoName改名
*
* @param tpiWorkSpace
* 工作目录
* @param tpiRepoName
* tpi版本库名字
* @param tpmRepoName
* tpm版本库名字
* @return
*/
public static boolean ensurelocalRepoName(String tpiWorkSpace, String tpiRepoName, String tpmRepoName) {
try {
if (!tpiRepoName.equals(tpmRepoName)) {
Files.move(Paths.get(tpiWorkSpace, tpmRepoName), Paths.get(tpiWorkSpace, tpiRepoName));
}
return true;
} catch (Exception e) {
logger.error("tpmRepoName: {}重命名为tpiRepoName: {}失败,路径为: {}", tpmRepoName, tpiRepoName, tpiWorkSpace);
return false;
}
}
/**
* 提取脚本执行结果中平台封装的结果格式
* @param src
* @return
*/
public static String getRealResult(String src) {
// \{ 匹配 { , [\s]* 匹配0-多个空白字符, "compileResult"[\s]*:匹配"compileResult":
// [\s\S]*匹配0-多个任意字符, [\s\S]*"out"[\s]*:匹配"out": , [^}]*匹配除}之外的所有字符
String regex = "\\{[\\s]*\"compileResult\"[\\s]*:[\\s\\S]*\"out\"[\\s]*:[^}]*}";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(src);
if (m.find()) {
return m.group(0);
} else {
return null;
}
}
/**
* 提取脚本执行结果中平台封装的结果格式
*
* @param src
* @return
*/
public static String getRealResult(String src) {
Pattern p = Pattern.compile(BuildResultCsts.FULL_RESULT_REG);
Matcher m = p.matcher(src);
if (m.find()) {
return m.group(0);
} else {
return null;
}
}
/**
* 判段是否是合法的json字符串
* @param src
* @return
*/
public static boolean isValidJSON(String src) {
try {
JSONObject.parseObject(src);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 判段是否是合法的json字符串
*
* @param src
* @return
*/
public static boolean isValidJSON(String src) {
try {
JSONObject.parseObject(src);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 判断是否为图片文件
*
* @param pic
* @return
*/
public static boolean isPic(String pic) {
String regex = ".+(.JPEG|.jpeg|.JPG|.jpg|.GIF|.gif|.BMP|.bmp|.PNG|.png)$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(pic);
/**
* 判断是否为图片文件
*
* @param pic
* @return
*/
public static boolean isPic(String pic) {
String regex = ".+(.JPEG|.jpeg|.JPG|.jpg|.GIF|.gif|.BMP|.bmp|.PNG|.png)$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(pic);
return m.find();
}
return m.find();
}
/**
* 判断是否为html
*
* @param html
* @return
*/
public static boolean isHtml(String html) {
String regex = ".+(.html|.htm)$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(html);
return m.find();
}
/**
* 判断是否为html
*
* @param html
* @return
*/
public static boolean isHtml(String html) {
String regex = ".+(.html|.htm)$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(html);
return m.find();
}
/**
* 判断是否为apk
*
* @param apk
* @return
*/
public static boolean isApk(String apk) {
String regex = ".+(.apk)$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(apk);
return m.find();
}
/**
* 判断是否为apk
*
* @param apk
* @return
*/
public static boolean isApk(String apk) {
String regex = ".+(.apk)$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(apk);
return m.find();
}
/**
* 判断是否为exe
*
* @param exe
* @return
*/
public static boolean isExe(String exe) {
String regex = ".+(.exe)$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(exe);
return m.find();
}
/**
* 判断是否为exe
*
* @param exe
* @return
*/
public static boolean isExe(String exe) {
String regex = ".+(.exe)$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(exe);
return m.find();
}
/**
* 判断是否为txt
*
* @param txt
* @return
*/
public static boolean isTxt(String txt) {
String regex = ".+(.txt)$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(txt);
return m.find();
}
/**
* 判断是否为txt
*
* @param txt
* @return
*/
public static boolean isTxt(String txt) {
String regex = ".+(.txt)$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(txt);
return m.find();
}
/**
* 获取生成的apk的文件名字
*
* @param dir
* @return
*/
public static String getApkName(String dir) {
String apkName = "";
File file = new File(dir);
if (file.exists() && file.isDirectory()) {
File[] files = file.listFiles();
for (File fileTmp : files) {
String fileName = fileTmp.getName();
if (GameHelper.isApk(fileName)) {
return fileName;
}
}
}
return apkName;
}
/**
* 获取生成的apk的文件名字
*
* @param dir
* @return
*/
public static String getApkName(String dir) {
String apkName = "";
File file = new File(dir);
if (file.exists() && file.isDirectory()) {
File[] files = file.listFiles();
for (File fileTmp : files) {
String fileName = fileTmp.getName();
if (GameHelper.isApk(fileName)) {
return fileName;
}
}
}
return apkName;
}
/**
* 清除无关的文件
*
* @param dir
*/
public static void clearFiles(String dir) {
GameHelper.deleteFiles(dir, "pic");
GameHelper.deleteFiles(dir, "apk");
GameHelper.deleteFiles(dir, "html");
GameHelper.deleteFiles(dir, "exe");
GameHelper.deleteFiles(dir, "txt");
}
/**
* 清除无关的文件
* @param dir
*/
public static void clearFiles(String dir) {
GameHelper.deleteFiles(dir, "pic");
GameHelper.deleteFiles(dir, "apk");
GameHelper.deleteFiles(dir, "html");
GameHelper.deleteFiles(dir, "exe");
GameHelper.deleteFiles(dir, "txt");
}
/**
* 删除文件夹下某种类型的文件
*
* @param dir
* @param fileType
*/
public static void deleteFiles(String dir, String fileType) {
File file = new File(dir);
if (file.exists() && file.isDirectory()) {
File[] files = file.listFiles();
for (File fileTmp : files) {
String fileName = fileTmp.getName();
try {
if ("pic".equals(fileType) && GameHelper.isPic(fileName)) {
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
}
if ("apk".equals(fileType) && GameHelper.isApk(fileName)) {
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
}
if ("html".equals(fileType) && GameHelper.isHtml(fileName)) {
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
}
if ("exe".equals(fileType) && GameHelper.isExe(fileName)) {
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
}
if ("txt".equals(fileType) && GameHelper.isTxt(fileName)) {
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
}
} catch (Exception e) {
logger.error("删除实训生成文件失败: {}", e);
}
}
}
}
/**
* 删除文件夹下某种类型的文件
*
* @param dir
* @param fileType
*/
public static void deleteFiles(String dir, String fileType) {
File file = new File(dir);
if (file.exists() && file.isDirectory()) {
File[] files = file.listFiles();
for (File fileTmp : files) {
String fileName = fileTmp.getName();
try {
if ("pic".equals(fileType) && GameHelper.isPic(fileName)) {
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
}
if ("apk".equals(fileType) && GameHelper.isApk(fileName)) {
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
}
if ("html".equals(fileType) && GameHelper.isHtml(fileName)) {
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
}
if ("exe".equals(fileType) && GameHelper.isExe(fileName)) {
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
}
if ("txt".equals(fileType) && GameHelper.isTxt(fileName)) {
FileUtils.forceDelete(new File(fileTmp.getAbsolutePath()));
logger.debug("删除文件:{}", fileTmp.getAbsolutePath());
}
} catch (Exception e) {
logger.error("删除实训生成文件失败: {}", e.getStackTrace());
}
}
}
}
/**
* 取得评测执行超时情况下的平台封装结果限定时间内执行脚本尚未获得结果脚本还在运行
*/
public static String getTooManyTimesResult(int caseSize, int maxTimes) {
String hint = "输出消息次数超限,最多输出%d次";
hint = String.format(hint, maxTimes);
return getResult(hint, caseSize, null, null);
}
public static String getResult(String hint, int caseSize, String downloadStatus, String createPodStatus) {
hint = Base64Util.encode(hint);
/**
* 取得评测执行超时情况下的平台封装结果限定时间内执行脚本尚未获得结果脚本还在运行
*/
public static String getTimeOutResult(int caseSize, int timeLimit) {
String hint = "代码评测超时!本关限定时间为:" + timeLimit + "s请检查代码是否存在死循环或其他耗时操作";
JSONObject result = new JSONObject();
result.put("compileResult", hint);
JSONArray out = new JSONArray(caseSize);
for (int i = 0; i < caseSize; i++) {
out.add(hint);
}
result.put("out", out);
result.put(BuildResultCsts.DOWNLOAD_STATUS, downloadStatus);
result.put(BuildResultCsts.CREATE_POD_STATUS, createPodStatus);
return result.toJSONString();
}
JSONObject result = new JSONObject();
result.put("compileResult", Base64Util.encode("compile successfully"));
JSONArray out = new JSONArray(caseSize);
for (int i = 0; i < caseSize; i++) {
out.add(Base64Util.encode(hint));
}
result.put("out", out);
public static String getTextMsgResult(String textMsg) {
return BuildResultCsts.TEXT_RESULT_PRE + textMsg;
}
return result.toJSONString();
}
/**
* 取得评测执行超时情况下的平台封装结果限定时间内执行脚本尚未获得结果脚本还在运行
*/
public static String getTimeOutResult(int caseSize, int timeLimit) {
String hint = "代码评测超时!本关限定时间为:" + timeLimit + "s请检查代码是否存在死循环或其他耗时操作";
/**
* 当脚本错误时返回平台封装的结果
*/
public static String getShellErrorResult(int caseSize, String oriOut) {
JSONObject result = new JSONObject();
result.put("compileResult", Base64Util.encode("评测脚本错误,请检查评测脚本设置。评测脚本返回的结果格式示例如下:\n" +
"{\"compileResult\":\"Y29tcGlsZSBzdWNjZXNzZnVsbHk=\",\"out\":[\"MzI=\",\"MTIy\"]}其中Y29tcGlsZSBzdWNjZXNzZnVsbHk=MzI=MTIy分别为base64编码之后的编译和执行结果。\n" +
"请保证您的评测脚本返回的是一个符合上述格式的有效json字符串\n您的输出\n" + oriOut));
JSONArray out = new JSONArray(caseSize);
for (int i = 0; i < caseSize; i++) {
out.add(Base64Util.encode(""));
}
result.put("out", out);
JSONObject result = new JSONObject();
result.put("compileResult", Base64Util.encode("compile successfully"));
JSONArray out = new JSONArray(caseSize);
for (int i = 0; i < caseSize; i++) {
out.add(Base64Util.encode(hint));
}
result.put("out", out);
return result.toJSONString();
}
return result.toJSONString();
}
/**
* 评测时候出现未知错误报平台繁忙
*/
public static String getUnknowErrorResult(int caseSize) {
JSONObject result = new JSONObject();
result.put("compileResult", Base64Util.encode("系统繁忙,请稍后重试"));
JSONArray out = new JSONArray(caseSize);
for (int i = 0; i < caseSize; i++) {
out.add(Base64Util.encode(""));
}
result.put("out", out);
/**
* 当脚本错误时返回平台封装的结果
*/
public static String getShellErrorResult(int caseSize, String oriOut) {
JSONObject result = new JSONObject();
result.put("compileResult", Base64Util.encode("评测脚本错误,请检查评测脚本设置。评测脚本返回的结果格式示例如下:\n"
+ "{\"compileResult\":\"Y29tcGlsZSBzdWNjZXNzZnVsbHk=\",\"out\":[\"MzI=\",\"MTIy\"]}其中Y29tcGlsZSBzdWNjZXNzZnVsbHk=MzI=MTIy分别为base64编码之后的编译和执行结果。\n"
+ "请保证您的评测脚本返回的是一个符合上述格式的有效json字符串\n您的输出\n" + oriOut));
return result.toJSONString();
}
JSONArray out = new JSONArray(caseSize);
for (int i = 0; i < caseSize; i++) {
out.add(Base64Util.encode(""));
}
result.put("out", out);
/**
* 调试模式下封装调试结果
*/
public static String getDebugOutPut(String result, String oriOut) {
return "当前模式下为您展示脚本原始输出,供调试使用,您脚本的原始输出为:\n"
+ oriOut +
"\n在实训发布后平台将屏蔽调试输出仅提取结果相关部分用于测评。\n" +
"结果格式应如:{\"compileResult\":\"Y29tcGlsZSBzdWNjZXNzZnVsbHk=\",\"out\":[\"MzI=\",\"MTIy\"]}其中Y29tcGlsZSBzdWNjZXNzZnVsbHk=MzI=MTIy分别为base64编码之后的编译和执行结果。" +
"\n以下是本次评测结果\n" + result;
return result.toJSONString();
}
}
/**
* 评测时候出现未知错误报平台繁忙
*/
public static String getUnknowErrorResult(int caseSize) {
JSONObject result = new JSONObject();
result.put("compileResult", Base64Util.encode("系统繁忙,请稍后重试"));
JSONArray arr = new JSONArray(caseSize);
for (int i = 0; i < caseSize; i++) {
arr.add(Base64Util.encode(""));
}
result.put("out", arr);
/**
* 设置TPI 本次build某一阶段消耗时间值
* @param key timeCost:${tpiID}:${buildID}
*/
public static void setTimeCostInJedis(String key, String period, String cost) {
JSONObject timeCost = JSONObject.parseObject(JedisUtil.get(key));
return result.toJSONString();
}
// 如果没有是不是可以理解为速度太快导致同步不及时
// 那么设开始时间为现在的时间
if (timeCost == null){
timeCost = new JSONObject();
String evaluateStartTime = LocalDateTime.now().toString();
timeCost.put("evaluateStartTime", evaluateStartTime);
}
/**
* 调试模式下封装调试结果
*/
public static String getDebugOutPut(String result, String oriOut) {
return "当前模式下为您展示脚本原始输出,供调试使用,您脚本的原始输出为:\n" + oriOut + "\n在实训发布后平台将屏蔽调试输出仅提取结果相关部分用于测评。\n"
+ "结果格式应如:{\"compileResult\":\"Y29tcGlsZSBzdWNjZXNzZnVsbHk=\",\"out\":[\"MzI=\",\"MTIy\"]}其中Y29tcGlsZSBzdWNjZXNzZnVsbHk=MzI=MTIy分别为base64编码之后的编译和执行结果。"
+ "\n以下是本次评测结果\n" + result;
timeCost.put(period, cost);
JedisUtil.set(key, timeCost.toJSONString());
}
}
/**
* 设置TPI 本次build某一阶段消耗时间值
*
* @param key
* timeCost:${tpiID}:${buildID}
*/
public static JSONObject setTimeCostInJedis(String key, String period, String cost) {
JSONObject timeCost = JSONObject.parseObject(JedisUtil.get(key));
// 如果没有是不是可以理解为速度太快导致同步不及时
// 那么设开始时间为现在的时间
if (timeCost == null) {
timeCost = new JSONObject();
String evaluateStartTime = LocalDateTime.now().toString();
timeCost.put("evaluateStartTime", evaluateStartTime);
}
timeCost.put(period, cost);
JedisUtil.set(key, timeCost.toJSONString());
return timeCost;
}
/**
* 获取加权限的gitURL:
* 加上超级用户的用户名密码
* 形如https://edugit:xinedugit@bdgit.educoder.net/educoder/mnf6b7z3.git
*/
public static String appendGitUrlWithUser(String gitUsername, String gitPassword, String gitUrl) {
return new StringBuffer(gitUrl).insert(gitUrl.indexOf("//") + 2, gitUsername + ":" + gitPassword + "@").toString();
}
}

View File

@ -1,16 +1,18 @@
package com.educoder.bridge.common.utils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by guange on 30/10/2016.
*/
@ -47,7 +49,9 @@ public class HttpHelper {
Map<String, List<String>> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
if (log.isDebugEnabled()) {
log.debug((key + "--->" + map.get(key)));
}
}
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
@ -65,6 +69,7 @@ public class HttpHelper {
in.close();
}
} catch (Exception e2) {
// ignore quietly
e2.printStackTrace();
}
}
@ -84,13 +89,11 @@ public class HttpHelper {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
long currentTimeMillis = System.currentTimeMillis();
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("Accept", "*/*");
conn.setRequestProperty("Connection", "Keep-Alive");
@ -100,7 +103,6 @@ public class HttpHelper {
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
StringBuffer stringBuffer = new StringBuffer();
for (Object key : param.keySet()) {
stringBuffer.append(key + "=" + param.get(key));
@ -108,26 +110,22 @@ public class HttpHelper {
}
String data = stringBuffer.toString();
data = data.substring(0, data.length() - 1);
log.debug("POST: " + url + " DATA: " + data);
OutputStream outputStream = conn.getOutputStream();
outputStream.write(data.getBytes());
outputStream.flush();
outputStream.close();
log.info("结果返回时间0{}" , System.currentTimeMillis() - currentTimeMillis);
log.info("结果返回时间0{}", System.currentTimeMillis() - currentTimeMillis);
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
finally {
// System.out.println("发送 POST 请求出现异常!" + e);
// e.printStackTrace();
log.error("发送 POST 请求出现异常!", e);
} finally {
try {
if (out != null) {
out.close();
@ -136,14 +134,14 @@ public class HttpHelper {
in.close();
}
} catch (IOException e) {
// ignore quietly
e.printStackTrace();
}
}
log.info("结果返回时间1{},返回结果{}" , System.currentTimeMillis() - currentTimeMillis, result);
log.info("结果返回时间1{},返回结果{}", System.currentTimeMillis() - currentTimeMillis, result);
return result;
}
/**
* 向指定 URL 发送POST方法的请求
*
@ -157,13 +155,11 @@ public class HttpHelper {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
long currentTimeMillis = System.currentTimeMillis();
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("Accept", "*/*");
conn.setRequestProperty("Connection", "Keep-Alive");
@ -174,7 +170,6 @@ public class HttpHelper {
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
StringBuffer stringBuffer = new StringBuffer();
for (Object key : param.keySet()) {
stringBuffer.append(key + "=" + param.get(key));
@ -182,26 +177,22 @@ public class HttpHelper {
}
String data = stringBuffer.toString();
data = data.substring(0, data.length() - 1);
log.debug("POST: " + url + " DATA: " + data);
OutputStream outputStream = conn.getOutputStream();
outputStream.write(data.getBytes());
outputStream.flush();
outputStream.close();
log.info("结果返回时间0{}" , System.currentTimeMillis() - currentTimeMillis);
log.info("结果返回时间0{}", System.currentTimeMillis() - currentTimeMillis);
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
finally {
// System.out.println("发送 POST 请求出现异常!" + e);
// e.printStackTrace();
log.error("发送 POST 请求出现异常!", e);
} finally {
try {
if (out != null) {
out.close();
@ -210,10 +201,11 @@ public class HttpHelper {
in.close();
}
} catch (IOException e) {
// ignore quietly
e.printStackTrace();
}
}
log.info("结果返回时间1{},返回结果{}" , System.currentTimeMillis() - currentTimeMillis, result);
log.info("结果返回时间1{},返回结果{}", System.currentTimeMillis() - currentTimeMillis, result);
return result;
}
@ -254,8 +246,9 @@ public class HttpHelper {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
// System.out.println("发送 POST 请求出现异常!" + e);
// e.printStackTrace();
log.error("发送 POST 请求出现异常!", e);
}
// 使用finally块来关闭输出流输入流
finally {
@ -267,10 +260,10 @@ public class HttpHelper {
in.close();
}
} catch (IOException ex) {
// ignore quietly
ex.printStackTrace();
}
}
return result;
}
}
}

View File

@ -1,25 +1,27 @@
package com.educoder.bridge.common.utils;
import redis.clients.jedis.Jedis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
import redis.clients.jedis.Jedis;
/**
* Created by zzx on 17/10/24.
*/
public class JedisUtil {
private static final Logger log = LoggerFactory.getLogger(JedisUtil.class);
/**
* 获取zset中元素个数
*/
public static int zlen(String key) {
Jedis jedis = null;
Jedis jedis = null;
int len = 0;
try {
jedis = RedisPool.getJedis();
len = jedis.zcard(key).intValue();
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
@ -30,7 +32,7 @@ public class JedisUtil {
* 获取元素在zset中的排名
*/
public static double zrank(String key, String value) {
Jedis jedis = null;
Jedis jedis = null;
double rank = Double.MIN_VALUE;
try {
jedis = RedisPool.getJedis();
@ -40,7 +42,7 @@ public class JedisUtil {
rank = jedis.zrank(key, value);
} catch (Exception e) {
rank = Double.MAX_VALUE;
e.printStackTrace();
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
@ -51,7 +53,7 @@ public class JedisUtil {
* 将zset中队首元素弹出若zset中没有元素则返回null
*/
public static String zpop(String key) {
Jedis jedis = null;
Jedis jedis = null;
String element = null;
try {
jedis = RedisPool.getJedis();
@ -60,7 +62,7 @@ public class JedisUtil {
jedis.zrem(key, element);
}
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
@ -82,7 +84,7 @@ public class JedisUtil {
jedis.zadd(key, lastScore + 1, value);
}
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
@ -99,7 +101,7 @@ public class JedisUtil {
jedis = RedisPool.getJedis();
jedis.zincrby(key, 1, value);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
@ -119,7 +121,7 @@ public class JedisUtil {
jedis.zrem(key, value);
}
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
@ -135,7 +137,7 @@ public class JedisUtil {
jedis = RedisPool.getJedis();
has = jedis.zscore(key, value) != null;
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
@ -151,7 +153,7 @@ public class JedisUtil {
jedis = RedisPool.getJedis();
jedis.hset(key, field, value);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
@ -167,7 +169,7 @@ public class JedisUtil {
jedis = RedisPool.getJedis();
value = jedis.hget(key, field);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
@ -183,57 +185,57 @@ public class JedisUtil {
jedis = RedisPool.getJedis();
jedis.hdel(key, field);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
}
/**
* String: set
*/
public static void set(String key, String value) {
Jedis jedis = null;
try {
jedis = RedisPool.getJedis();
jedis.set(key, value);
} catch (Exception e) {
e.printStackTrace();
} finally {
RedisPool.returnResource(jedis);
}
}
* String: set
*/
public static void set(String key, String value) {
Jedis jedis = null;
try {
jedis = RedisPool.getJedis();
jedis.set(key, value);
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
}
/**
* String: get
*/
public static String get(String key) {
Jedis jedis = null;
String value = null;
try {
jedis = RedisPool.getJedis();
value = jedis.get(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
RedisPool.returnResource(jedis);
}
return value;
}
/**
* String: get
*/
public static String get(String key) {
Jedis jedis = null;
String value = null;
try {
jedis = RedisPool.getJedis();
value = jedis.get(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
return value;
}
/**
* String: delete
*/
public static void del(String key) {
Jedis jedis = null;
try {
jedis = RedisPool.getJedis();
jedis.del(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
RedisPool.returnResource(jedis);
}
}
/**
* String: delete
*/
public static void del(String key) {
Jedis jedis = null;
try {
jedis = RedisPool.getJedis();
jedis.del(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
RedisPool.returnResource(jedis);
}
}
}

View File

@ -0,0 +1,176 @@
package com.educoder.bridge.common.utils;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.Future;
import org.apache.http.ConnectionClosedException;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.nio.client.BridgeHttpAsyncClientBuilder;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by guange on 30/10/2016.
*/
public class NioHttpClientUtils {
private static final Logger log = LoggerFactory.getLogger(NioHttpClientUtils.class);
/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数请求参数应该是 name1=value1&name2=value2 的形式
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, Map param) {
long currentTimeMillis = System.currentTimeMillis();
String result = "";
try {
HttpPost request = new HttpPost(url);
StringBuilder sb = new StringBuilder();
for (Object key : param.keySet()) {
sb.append(key + "=" + param.get(key));
sb.append("&");
}
String data = sb.toString();
data = data.substring(0, data.length() - 1);
log.debug("POST: " + url + " DATA: " + data);
ContentType contentType = ContentType.create("application/x-www-form-urlencoded", Consts.UTF_8);
StringEntity entity = new StringEntity(data, contentType);
request.setEntity(entity);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000) // 建立连接的超时时间,即三次握手的超时时间
.setSocketTimeout(10000) // 请求数据传输的超时时间
.setConnectionRequestTimeout(1000) // 从连接池获取连接的超时时间
.build();
CloseableHttpAsyncClient httpclient = BridgeHttpAsyncClientBuilder.create()
.setDefaultRequestConfig(requestConfig).setBodyLength(entity.getContentLength()).build();
httpclient.start();
Future<HttpResponse> future = httpclient.execute(request, new FutureCallback<HttpResponse>() {
@Override
public void failed(Exception ex) {
if (ex instanceof ConnectionClosedException) {
} else {
log.error("请求发送失败");
}
close(httpclient);
}
@Override
public void completed(HttpResponse resp) {
close(httpclient);
}
@Override
public void cancelled() {
close(httpclient);
}
});
// HttpResponse res = future.get();
// result = EntityUtils.toString(res.getEntity());
while (httpclient.isRunning()) {
}
} catch (Exception e) {
log.error("发送 POST 请求出现异常!", e);
}
log.info("结果返回时间0{}", System.currentTimeMillis() - currentTimeMillis);
return result;
}
private static void close(CloseableHttpAsyncClient httpclient) {
try {
httpclient.close();
} catch (IOException e) {
// ignore quietly
}
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数请求参数应该是 name1=value1&name2=value2 的形式
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, Map param, int readTimeOut) {
long currentTimeMillis = System.currentTimeMillis();
String result = "";
try {
HttpPost request = new HttpPost(url);
StringBuilder sb = new StringBuilder();
for (Object key : param.keySet()) {
sb.append(key + "=" + param.get(key));
sb.append("&");
}
String data = sb.toString();
data = data.substring(0, data.length() - 1);
log.debug("POST: " + url + " DATA: " + data);
ContentType contentType = ContentType.create("application/x-www-form-urlencoded", Consts.UTF_8);
StringEntity entity = new StringEntity(data, contentType);
request.setEntity(entity);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000) // 建立连接的超时时间,即三次握手的超时时间
.setSocketTimeout(10000) // 请求数据传输的超时时间
.setConnectionRequestTimeout(1000) // 从连接池获取连接的超时时间
.build();
CloseableHttpAsyncClient httpclient = BridgeHttpAsyncClientBuilder.create()
.setDefaultRequestConfig(requestConfig).setBodyLength(entity.getContentLength()).build();
httpclient.start();
Future<HttpResponse> future = httpclient.execute(request, new FutureCallback<HttpResponse>() {
@Override
public void failed(Exception ex) {
if (ex instanceof ConnectionClosedException) {
} else {
log.error("请求发送失败");
}
close(httpclient);
}
@Override
public void completed(HttpResponse resp) {
close(httpclient);
}
@Override
public void cancelled() {
close(httpclient);
}
});
// future.get();
while (httpclient.isRunning()) {
}
} catch (Exception e) {
log.error("发送 POST 请求出现异常!", e);
}
log.info("结果返回时间0{}", System.currentTimeMillis() - currentTimeMillis);
return result;
}
}

View File

@ -7,17 +7,17 @@ import java.net.ServerSocket;
* Created by zzx on 17/10/30.
*/
public class PortUtil {
public static int getPort() {
int port;
while(true) {
port = (int) (20000 * Math.random() + 40000);
try {
new ServerSocket(port).close();
break;
} catch (IOException e) {
continue;
}
}
return port;
}
public static int getPort() {
int port;
while (true) {
port = (int) (20000 * Math.random() + 40000);
try {
new ServerSocket(port).close();// TODO 端口可能冲突
break;
} catch (IOException e) {
continue;
}
}
return port;
}
}

View File

@ -0,0 +1,21 @@
package com.educoder.bridge.common.utils;
/**
*
* @author mm
*
*/
public final class ProcessStatusUtil {
/**
* 执行shell命令并获取输出
*/
public static boolean isTimeout(int exitStatus) {
return exitStatus == 124 || exitStatus == (128 + 9);
}
public static boolean isError(int exitStatus) {
return exitStatus == -1;
}
}

View File

@ -1,70 +1,74 @@
package com.educoder.bridge.common.utils;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.exceptions.JedisException;
import java.util.Properties;
public final class RedisPool {
private static final Logger log = LoggerFactory.getLogger(JedisUtil.class);
//可用连接实例的最大数目默认为8
//如果赋值为-1则表示不限制如果pool已经分配了maxActive个jedis实例则此时pool的状态为exhausted(耗尽)
private static Integer MAX_TOTAL = 1024;
//控制一个pool最多有多少个状态为idle(空闲)的jedis实例默认值是8
private static Integer MAX_IDLE = 200;
//等待可用连接的最大时间单位是毫秒默认值为-1表示永不超时
//如果超过等待时间则直接抛出JedisConnectionException
private static Integer MAX_WAIT_MILLIS = 10000;
private static Integer TIMEOUT = 10000;
//在borrow()一个jedis实例时是否提前进行validate(验证)操作
//如果为true则得到的jedis实例均是可用的
private static Boolean TEST_ON_BORROW = true;
private static JedisPool jedisPool = null;
// 可用连接实例的最大数目默认为8
// 如果赋值为-1则表示不限制如果pool已经分配了maxActive个jedis实例则此时pool的状态为exhausted(耗尽)
private static Integer MAX_TOTAL = 1024;
// 控制一个pool最多有多少个状态为idle(空闲)的jedis实例默认值是8
private static Integer MAX_IDLE = 200;
// 等待可用连接的最大时间单位是毫秒默认值为-1表示永不超时
// 如果超过等待时间则直接抛出JedisConnectionException
private static Integer MAX_WAIT_MILLIS = 10000;
private static Integer TIMEOUT = 10000;
// 在borrow()一个jedis实例时是否提前进行validate(验证)操作
// 如果为true则得到的jedis实例均是可用的
private static Boolean TEST_ON_BORROW = true;
private static JedisPool jedisPool = null;
// 静态块初始化Redis连接池
static {
try {
Properties prop = new Properties();
String active = System.getProperty("spring.profiles.active");
prop.load(RedisPool.class.getClassLoader().getResourceAsStream("config_" + active + ".properties"));
// 静态块初始化Redis连接池
static {
try {
Properties prop = new Properties();
String active = System.getProperty("spring.profiles.active");
prop.load(RedisPool.class.getClassLoader().getResourceAsStream("config_" + active + ".properties"));
String ADDR = prop.getProperty("redisAddress");
int PORT = Integer.parseInt(prop.getProperty("redisPort"));
String AUTH = prop.getProperty("redisAuth");
String ADDR = prop.getProperty("redisAddress");
int PORT = Integer.parseInt(prop.getProperty("redisPort"));
String AUTH = prop.getProperty("redisAuth");
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_TOTAL);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT_MILLIS);
config.setTestOnBorrow(TEST_ON_BORROW);
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_TOTAL);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT_MILLIS);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = AUTH.equals("") ? new JedisPool(config, ADDR, PORT, TIMEOUT) :
new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
} catch (Exception e) {
e.printStackTrace();
}
jedisPool = AUTH.equals("") ? new JedisPool(config, ADDR, PORT, TIMEOUT)
: new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
/**
* 获取Jedis实例
*
* @return
*/
public synchronized static Jedis getJedis() {
return jedisPool.getResource();
}
/**
* 获取Jedis实例
*
* @return
*/
public synchronized static Jedis getJedis() {
return jedisPool.getResource();
}
public static void returnResource(final Jedis jedis) {
if (jedis != null) {
// jedis.close()取代jedisPool.returnResource(jedis)方法将3.0版本开始
try {
jedis.close();
} catch (JedisException e) {
}
}
}
public static void returnResource(final Jedis jedis) {
if (jedis != null) {
// jedis.close()取代jedisPool.returnResource(jedis)方法将3.0版本开始
try {
jedis.close();
} catch (JedisException e) {
log.error(e.getMessage(), e);
}
}
}
}

View File

@ -1,124 +1,133 @@
package com.educoder.bridge.common.utils;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
/**
* Created by guange on 26/02/2017.
*/
public class ShellUtil {
private static final Logger logger = LoggerFactory.getLogger(ShellUtil.class);
private static final Logger logger = LoggerFactory.getLogger(ShellUtil.class);
private static ExecutorService executor;
private static volatile ExecutorService executor;
/**
* 执行shell命令并获取输出
*/
public static String execute(String command) {
return executeAndGetExitStatus(command).getString("out");
}
/**
* 执行shell命令并获取输出
*/
public static String execute(String command) {
return executeAndGetExitStatus(command).getString("out");
}
/**
* 执行shell命令并获得输出及退出码失败重试 共尝试retryTimes次
*/
public static JSONObject executeAndGetExitStatus(String command, int retryTimes) {
JSONObject result = new JSONObject();
/**
* 执行shell命令并获得输出及退出码失败重试 共尝试retryTimes次
*/
public static JSONObject executeAndGetExitStatus(String command, int retryTimes) {
JSONObject result = new JSONObject();
for (int i = 0; i < retryTimes; i++) {
result = executeAndGetExitStatus(command);
if (result.getInteger("exitStatus") != 0) {
continue;
} else {
break;
}
}
for (int i = 0; i < retryTimes; i++) {
result = executeAndGetExitStatus(command);
if (result.getInteger("exitStatus") != 0) {
continue;
} else {
break;
}
}
return result;
}
return result;
}
/**
* 执行命令并获得输出以及退出码
*/
public static JSONObject executeAndGetExitStatus(String command) {
JSONObject result = new JSONObject();
/**
* 执行命令并获得输出以及退出码
*/
public static JSONObject executeAndGetExitStatus(String command) {
JSONObject result = new JSONObject();
StringBuffer out = new StringBuffer();
Integer exitStatus = -1;
StringBuffer out = new StringBuffer();
Integer exitStatus = -1;
ProcessBuilder pb = new ProcessBuilder(new String[]{"/bin/sh", "-c", command});
pb.redirectErrorStream(true);
try {
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append(System.getProperty("line.separator"));
}
exitStatus = process.waitFor();
ProcessBuilder pb = new ProcessBuilder(new String[] { "/bin/sh", "-c", command });
pb.redirectErrorStream(true);
try {
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
out.append(System.getProperty("line.separator"));
}
exitStatus = process.waitFor();
} catch (Exception e) {
e.printStackTrace();
logger.info("executeAndGetExitStatus: {}", command);
logger.error("executeAndGetExitStatus: ",e);
}
} catch (Exception e) {
logger.info("executeAndGetExitStatus: {}", command);
logger.error("executeAndGetExitStatus: ", e);
}
result.put("out", out.toString().trim());
result.put("exitStatus", exitStatus);
result.put("out", out.toString().trim());
result.put("exitStatus", exitStatus);
return result;
}
return result;
}
/**
* 执行shell命令设定时间限制为${timeLimit} s
*/
public static JSONObject executeInLimitTime(String command, long timeLimit) throws TimeoutException {
JSONObject result = new JSONObject();
/**
* 执行shell命令设定时间限制为${timeLimit} s
*/
public static JSONObject executeInLimitTime(String command, long timeLimit) throws TimeoutException {
JSONObject result = new JSONObject();
if (executor == null) {
executor = Executors.newCachedThreadPool();
}
if (executor == null) {
synchronized (ShellUtil.class) {
if (executor == null) {
executor = Executors.newCachedThreadPool();
}
}
}
try {
Future<JSONObject> future = executor.submit(() -> executeAndGetExitStatus(command));
result = future.get(timeLimit, TimeUnit.SECONDS);
} catch (TimeoutException ex) {
logger.debug("执行shell命令超时command: {}", command);
try {
Future<JSONObject> future = executor.submit(() -> executeAndGetExitStatus(command));
result = future.get(timeLimit, TimeUnit.SECONDS);
} catch (TimeoutException ex) {
logger.debug("执行shell命令超时command: {}", command);
// 删除任务
killProcess(command);
// 删除任务
killProcess(command);
throw new TimeoutException("执行命令超时");
} catch (Exception e) {
logger.debug("执行shell命令失败未知错误command: {}", command);
e.printStackTrace();
}
throw new TimeoutException("执行命令超时");
} catch (Exception e) {
logger.debug("执行shell命令失败未知错误command: {}", command);
logger.error("执行shell命令失败未知错误", e);
}
return result;
}
return result;
}
/**
* 杀掉一个shell进程
*
* @param commandToKill 源命令
*/
public static void killProcess(String commandToKill) {
// 原型kill -9 `ps -ef | grep "haha.sh" |grep -v grep | awk -F' ' '{print $2}'`
logger.debug("ExecuteShellCommand: killProcess: " + commandToKill);
/**
* 杀掉一个shell进程
*
* @param commandToKill
* 源命令
*/
public static void killProcess(String commandToKill) {
// 原型kill -9 `ps -ef | grep "haha.sh" |grep -v grep | awk -F' ' '{print $2}'`
logger.debug("ExecuteShellCommand: killProcess: " + commandToKill);
String command = "kill -9 `ps -ef | grep \"" + commandToKill + "\" | grep -v grep | awk -F' ' '{print $2}'`";
String command = "kill -9 `ps -ef | grep \"" + commandToKill + "\" | grep -v grep | awk -F' ' '{print $2}'`";
try {
Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", command});
} catch (IOException e) {
e.printStackTrace();
}
}
try {
Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", command });
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,31 @@
package com.educoder.bridge.common.utils;
import java.util.concurrent.ThreadPoolExecutor;
import com.alibaba.fastjson.JSONObject;
public class ThreadPoolUtil {
/**
* 获取线程池信息
* @return
*/
public static JSONObject getPoolInfo(ThreadPoolExecutor executor) {
JSONObject result = new JSONObject();
result.put("taskCount", executor.getTaskCount());
result.put("activeTaskCount", executor.getActiveCount());
result.put("completedCount", executor.getCompletedTaskCount());
result.put("coreSize", executor.getCorePoolSize());
result.put("maxSize", executor.getMaximumPoolSize());
result.put("poolSize", executor.getPoolSize());
StringBuilder sb = new StringBuilder();
for (Runnable r : executor.getQueue()) {
sb.append(r.toString() + " ");
}
result.put("queue", sb.toString());
return result;
}
}

View File

@ -0,0 +1,79 @@
package com.educoder.bridge.common.utils;
import java.io.File;
import io.fabric8.kubernetes.api.model.Pod;
/**
*
* @author mm
*
*/
public abstract class TpUtils {
private TpUtils() {
}
public static String buildTpiWorkspace(String basePath, String tpiID) {
return basePath + File.separator + "myshixun_" + tpiID;
}
/**
* 转化评测pod类型
*
* @param podType
* @return
*/
public static String cvtEvaPodType(Integer podType) {
return podType != 2 ? "evaluate" : "evassh";
}
/**
* 转化ssh pod类型
*
* @param podType
* @return
*/
public static String cvtSshPodType(Integer podType) {
return podType != 2 ? "webssh" : "evassh";
}
/**
* pod 共享返回true否则返回false
*
* @param podName
* @return
*/
public static boolean isSharedPod(String podName) {
return podName.startsWith("evaluate");
}
/**
* pod 共享返回true否则返回false
*
* @param podType
* @return
*/
public static boolean isSharedPod(Integer podType) {
String type = cvtEvaPodType(podType);
return "evaluate".equals(type);
}
/**
* 共享pod名称构成evaluate_tpID_xxx
*
* @param podName
* @return
*/
public static String getSharePodTpID(String podName) {
int beginIndex = "evaluate_".length();
int endIndex = podName.lastIndexOf("_");
String str = podName.substring(beginIndex - 1, endIndex);
return str;
}
public static boolean isSharePod(Pod pod) {
String type = pod.getMetadata().getLabels().get("type");
return "evaluate".equals(type);
}
/**
* 获取redis中共享pod的任务集合的名称
*
* @param podName
* evaluate-课程ID-xxx
* @return task-evaluate-课程ID
*/
public static String getShareSetName(String podName) {
int index = podName.lastIndexOf("-");
return "task-" + podName.substring(0, index);
}
}

View File

@ -1,93 +1,96 @@
package com.educoder.bridge.docker.controller;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.controller.BaseController;
import com.educoder.bridge.common.utils.ClientUtil;
import com.educoder.bridge.docker.service.DockerService;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.exceptions.DockerException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.utils.ClientUtil;
import com.educoder.bridge.docker.service.DockerService;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.exceptions.DockerException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@Api(value = "镜像管理", hidden = true)
@RestController
@RequestMapping("/docker")
public class DockerController extends BaseController {
@Autowired
private DockerService dockerService;
public class DockerController {
private static final Logger logger = LoggerFactory.getLogger(DockerController.class);
@Autowired
private DockerService dockerService;
@RequestMapping(path = "/images")
@ApiOperation(value = "获取全部实训镜像", httpMethod = "GET")
public JSONObject getImages() throws DockerException, InterruptedException {
logger.info("收到获取镜像请求");
@RequestMapping(path = "/images")
@ApiOperation(value = "获取全部实训镜像", httpMethod = "GET")
public JSONObject getImages() throws DockerException, InterruptedException {
logger.info("收到获取镜像请求");
JSONObject result = new JSONObject();
// 获取主节点全部镜像
DockerClient docker = ClientUtil.getDocker();
List<String> imageList = dockerService.getImageList(docker);
result.put("images", imageList);
JSONObject result = new JSONObject();
// 获取主节点全部镜像
DockerClient docker = ClientUtil.getDocker();
List<String> imageList = dockerService.getImageList(docker);
result.put("images", imageList);
// 获取未同步的镜像
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
List<String> imageDiff = dockerService.imageDiff(imageList, dockerDeputies);
result.put("imagesNotSync", imageDiff);
// 获取未同步的镜像
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
List<String> imageDiff = dockerService.imageDiff(imageList, dockerDeputies);
result.put("imagesNotSync", imageDiff);
result.put("code", 0);
return result;
}
result.put("code", 0);
return result;
}
@RequestMapping(path = "/syncImage")
@ApiOperation(value = "同步镜像", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public JSONObject syncImage(
@ApiParam(name = "imageName", required = true, value = "镜像名") @RequestParam String imageName)
throws DockerException, InterruptedException {
logger.info("同步镜像imageName: {}", imageName);
@RequestMapping(path = "/syncImage")
@ApiOperation(value = "同步镜像", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public JSONObject syncImage(
@ApiParam(name = "imageName", required = true, value = "镜像名") @RequestParam String imageName)
throws DockerException, InterruptedException {
logger.info("同步镜像imageName: {}", imageName);
JSONObject result = new JSONObject();
JSONObject result = new JSONObject();
DockerClient dockerMaster = ClientUtil.getDocker();
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
DockerClient dockerMaster = ClientUtil.getDocker();
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
dockerService.syncImage(dockerMaster, dockerDeputies, imageName);
dockerService.syncImage(dockerMaster, dockerDeputies, imageName);
result.put("code", 0);
return result;
result.put("code", 0);
return result;
}
}
@RequestMapping(path = "/updateImage")
@ApiOperation(value = "镜像有更新", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public JSONObject updateImage(
@ApiParam(name = "imageName", required = true, value = "镜像名") @RequestParam String imageName,
@ApiParam(name = "imageID", required = true, value = "旧的镜像ID") @RequestParam String imageID,
@ApiParam(name = "flag", required = true, value = "更新行为选择0更新 1回退") @RequestParam Integer flag)
throws DockerException, InterruptedException {
logger.info("更新镜像imageName: {}, imageID: {}, flag: {}", imageName, imageID, flag);
@RequestMapping(path = "/updateImage")
@ApiOperation(value = "镜像有更新", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public JSONObject updateImage(
@ApiParam(name = "imageName", required = true, value = "镜像名") @RequestParam String imageName,
@ApiParam(name = "imageID", required = true, value = "旧的镜像ID") @RequestParam String imageID,
@ApiParam(name = "flag", required = true, value = "更新行为选择0更新 1回退") @RequestParam Integer flag)
throws DockerException, InterruptedException {
logger.info("更新镜像imageName: {}, imageID: {}, flag: {}", imageName, imageID, flag);
JSONObject result = new JSONObject();
JSONObject result = new JSONObject();
DockerClient dockerMaster = ClientUtil.getDocker();
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
DockerClient dockerMaster = ClientUtil.getDocker();
List<DockerClient> dockerDeputies = ClientUtil.getDockerDeputies();
if (flag == 0) {
// 选择更新
dockerService.syncImage(dockerMaster, dockerDeputies, imageName);
} else {
// 选择回退
dockerService.resetImage(dockerMaster, imageID, imageName);
}
if (flag == 0) {
// 选择更新
dockerService.syncImage(dockerMaster, dockerDeputies, imageName);
} else {
// 选择回退
dockerService.resetImage(dockerMaster, imageID, imageName);
}
result.put("code", 0);
return result;
}
result.put("code", 0);
return result;
}
}

View File

@ -3,54 +3,55 @@
*/
package com.educoder.bridge.docker.controller;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.controller.BaseController;
import com.educoder.bridge.game.service.K8sService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.game.service.K8sService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* Created by liqiankun on 2017/11/16 0016
* Description
* Created by liqiankun on 2017/11/16 0016 Description
*/
@Api(value = "资源监控", hidden = true)
@RestController
@RequestMapping("/monitor")
public class MonitorController extends BaseController {
@Autowired
private K8sService k8sService;
public class MonitorController {
/**
* 简单地获取集群中的Pod总量及各个节点上的Pod分布
*
* @return
* @throws Exception
*/
@RequestMapping(path = "/getPodsInfo")
@ApiOperation(value = "获取集群中某个节点的信息", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public JSONObject podsInfo() throws Exception {
int podSum = k8sService.getPodSum();
List<String> nodeIP = k8sService.getNodesIP();
//生成Json格式的返回结果
StringBuffer jsonResult = new StringBuffer("[");
for (String ip : nodeIP) {
int num = k8sService.getPodNum(ip);
jsonResult.append("{\"ip\":" + "\"" + ip + "\"," + "\"num\":" + "\"" + num + "\"},");
}
int length = jsonResult.length() - 1;
jsonResult.deleteCharAt(length);
jsonResult.append("]");
@Autowired
private K8sService k8sService;
JSONObject response = new JSONObject();
response.put("sum", podSum);
response.put("distr", jsonResult);
response.put("code", 0);
return response;
}
/**
* 简单地获取集群中的Pod总量及各个节点上的Pod分布
*
* @return
* @throws Exception
*/
@RequestMapping(path = "/getPodsInfo")
@ApiOperation(value = "获取集群中某个节点的信息", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public JSONObject podsInfo() throws Exception {
int podSum = k8sService.getPodSum();
List<String> nodeIP = k8sService.getNodesIP();
// 生成Json格式的返回结果
StringBuffer jsonResult = new StringBuffer("[");
for (String ip : nodeIP) {
int num = k8sService.getPodNum(ip);
jsonResult.append("{\"ip\":" + "\"" + ip + "\"," + "\"num\":" + "\"" + num + "\"},");
}
int length = jsonResult.length() - 1;
jsonResult.deleteCharAt(length);
jsonResult.append("]");
JSONObject response = new JSONObject();
response.put("sum", podSum);
response.put("distr", jsonResult);
response.put("code", 0);
return response;
}
}

View File

@ -1,162 +1,168 @@
package com.educoder.bridge.docker.service;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.settings.AppConfig;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.Image;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.docker.controller.DockerController;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.Image;
@Service("DockerService")
public class DockerService {
private static final Logger logger = LoggerFactory.getLogger(DockerController.class);
@Autowired
private AppConfig appConfig;
@Autowired
private AppConfig appConfig;
/**
* 返回小洞洞做的实训镜像名称列表
*
* @param docker
* @return
* @throws DockerException
* @throws InterruptedException
*/
public List<String> getImageList(DockerClient docker) throws DockerException, InterruptedException {
List<String> imageList = new ArrayList<>();
List<Image> images = docker.listImages(DockerClient.ListImagesParam.byName("*:v1.0"));
for (Image image : images) {
for (String imageName : image.repoTags()) {
JSONObject jsonObject = new JSONObject(true);
jsonObject.put("imageID", image.id().substring(7, 19));
jsonObject.put("imageName", imageName);
imageList.add(jsonObject.toJSONString());
}
}
return imageList;
}
/**
* 返回小洞洞做的实训镜像名称列表
*
* @param docker
* @return
* @throws DockerException
* @throws InterruptedException
*/
public List<String> getImageList(DockerClient docker) throws DockerException, InterruptedException {
List<String> imageList = new ArrayList<>();
List<Image> images = docker.listImages(DockerClient.ListImagesParam.byName("*:v1.0"));
for (Image image : images) {
for (String imageName : image.repoTags()) {
JSONObject jsonObject = new JSONObject(true);
jsonObject.put("imageID", image.id().substring(7, 19));
jsonObject.put("imageName", imageName);
imageList.add(jsonObject.toJSONString());
}
}
return imageList;
}
/**
* 主节点镜像同步至子节点
*
* @param dockerMaster
* @param dockerDeputies
* @throws DockerException
* @throws InterruptedException
*/
public void checkNodeImages(DockerClient dockerMaster, List<DockerClient> dockerDeputies)
throws DockerException, InterruptedException {
// 主节点上的所有镜像列表
List<String> images = getImageList(dockerMaster);
/**
* 主节点镜像同步至子节点
*
* @param dockerMaster
* @param dockerDeputies
* @throws DockerException
* @throws InterruptedException
*/
public void checkNodeImages(DockerClient dockerMaster, List<DockerClient> dockerDeputies)
throws DockerException, InterruptedException {
// 主节点上的所有镜像列表
List<String> images = getImageList(dockerMaster);
for (DockerClient dockerDeputy : dockerDeputies) {
List<String> allImages = new ArrayList<>(images);
List<String> deputyImages = getImageList(dockerDeputy);
// 取差集获取多出来的镜像
allImages.removeAll(deputyImages);
for (DockerClient dockerDeputy : dockerDeputies) {
List<String> allImages = new ArrayList<>(images);
List<String> deputyImages = getImageList(dockerDeputy);
// 取差集获取多出来的镜像
allImages.removeAll(deputyImages);
for (String image : allImages) {
JSONObject imageInfo = JSONObject.parseObject(image);
String imageName = imageInfo.getString("imageName");
try {
// 主节点推子节点拉
dockerPush(dockerMaster, imageName);
dockerPull(dockerDeputy, imageName);
for (String image : allImages) {
JSONObject imageInfo = JSONObject.parseObject(image);
String imageName = imageInfo.getString("imageName");
try {
// 主节点推子节点拉
dockerPush(dockerMaster, imageName);
dockerPull(dockerDeputy, imageName);
} catch (Exception e) {
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
}
}
}
}
}
/**
* 从主节点同步一个镜像到子节点
*
* @param dockerMaster
* @param dockerDeputies
* @param imageName
* @throws DockerException
* @throws InterruptedException
*/
public void syncImage(DockerClient dockerMaster, List<DockerClient> dockerDeputies, String imageName)
throws DockerException, InterruptedException {
for (DockerClient dockerDeputy : dockerDeputies) {
dockerPush(dockerMaster, imageName);
dockerPull(dockerDeputy, imageName);
}
}
/**
* 从主节点同步一个镜像到子节点
*
* @param dockerMaster
* @param dockerDeputies
* @param imageName
* @throws DockerException
* @throws InterruptedException
*/
public void syncImage(DockerClient dockerMaster, List<DockerClient> dockerDeputies, String imageName)
throws DockerException, InterruptedException {
for (DockerClient dockerDeputy : dockerDeputies) {
dockerPush(dockerMaster, imageName);
dockerPull(dockerDeputy, imageName);
}
}
/**
* 回退镜像
*
* @param dockerMaster
* @param imageID
* @param imageName
* @throws DockerException
* @throws InterruptedException
*/
public void resetImage(DockerClient dockerMaster, String imageID, String imageName)
throws DockerException, InterruptedException {
dockerMaster.tag(imageID, imageName);
}
/**
* 回退镜像
*
* @param dockerMaster
* @param imageID
* @param imageName
* @throws DockerException
* @throws InterruptedException
*/
public void resetImage(DockerClient dockerMaster, String imageID, String imageName) throws DockerException, InterruptedException {
dockerMaster.tag(imageID, imageName);
}
/**
* 拉镜像
*
* @param docker
* @param imageName
* @throws DockerException
* @throws InterruptedException
*/
public void dockerPull(DockerClient docker, String imageName) throws DockerException, InterruptedException {
String imageNew = appConfig.getRegistry() + "/" + imageName;
docker.pull(imageNew);
docker.tag(imageNew, imageName);
docker.removeImage(imageNew);
}
/**
* 镜像
*
* @param docker
* @param imageName
* @throws DockerException
* @throws InterruptedException
*/
public void dockerPull(DockerClient docker, String imageName) throws DockerException, InterruptedException {
String imageNew = appConfig.getRegistry() + "/" + imageName;
docker.pull(imageNew);
docker.tag(imageNew, imageName);
docker.removeImage(imageNew);
}
/**
* 镜像
*
* @param docker
* @param imageName
* @throws DockerException
* @throws InterruptedException
*/
public void dockerPush(DockerClient docker, String imageName) throws DockerException, InterruptedException {
String imageNew = appConfig.getRegistry() + "/" + imageName;
docker.tag(imageName, imageNew);
docker.push(imageNew);
docker.removeImage(imageNew);
}
/**
* 推镜像
*
* @param docker
* @param imageName
* @throws DockerException
* @throws InterruptedException
*/
public void dockerPush(DockerClient docker, String imageName) throws DockerException, InterruptedException {
String imageNew = appConfig.getRegistry() + "/" + imageName;
docker.tag(imageName, imageNew);
docker.push(imageNew);
docker.removeImage(imageNew);
}
/**
* 找出主节点镜像中那些没有同步到每个子节点的镜像
*
* @param images
* @param dockerDeputies
* @return
* @throws DockerException
* @throws InterruptedException
*/
public List<String> imageDiff(List<String> images, List<DockerClient> dockerDeputies)
throws DockerException, InterruptedException {
List<String> diffImages = new ArrayList<>();
for (DockerClient dockerDeputy : dockerDeputies) {
List<String> masterImages = new ArrayList<>(images);
List<String> deputyImages = getImageList(dockerDeputy);
/**
* 找出主节点镜像中那些没有同步到每个子节点的镜像
*
* @param images
* @param dockerDeputies
* @return
* @throws DockerException
* @throws InterruptedException
*/
public List<String> imageDiff(List<String> images, List<DockerClient> dockerDeputies)
throws DockerException, InterruptedException {
List<String> diffImages = new ArrayList<>();
for (DockerClient dockerDeputy : dockerDeputies) {
List<String> masterImages = new ArrayList<>(images);
List<String> deputyImages = getImageList(dockerDeputy);
masterImages.removeAll(deputyImages);
masterImages.removeAll(diffImages);
diffImages.addAll(masterImages);
masterImages.removeAll(deputyImages);
masterImages.removeAll(diffImages);
diffImages.addAll(masterImages);
}
}
return diffImages;
}
return diffImages;
}
}

View File

@ -4,6 +4,8 @@ import java.io.File;
import java.time.LocalDateTime;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@ -13,20 +15,17 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.controller.BaseController;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.common.utils.Base64Util;
import com.educoder.bridge.common.utils.BeanFactory;
import com.educoder.bridge.common.utils.GameHelper;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.common.utils.PortUtil;
import com.educoder.bridge.common.utils.ShellUtil;
import com.educoder.bridge.common.utils.TimeHelper;
import com.educoder.bridge.game.exception.GameException;
import com.educoder.bridge.game.service.GameService;
import com.educoder.bridge.game.service.K8sService;
import com.educoder.bridge.game.thread.BuildThread;
import com.educoder.bridge.game.thread.BuildThreadPersistence;
import com.educoder.bridge.k8s.model.BridgePod;
import com.educoder.bridge.k8s.service.BridgePodService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -40,15 +39,19 @@ import io.swagger.annotations.ApiParam;
@Api(value = "game控制器", hidden = true)
@RestController
@RequestMapping("/game")
public class GameController extends BaseController {
public class GameController {
private static final Logger logger = LoggerFactory.getLogger(GameController.class);
@Autowired
private AppConfig appConfig;
@Autowired
private GameService gameService;
@Autowired
private K8sService k8sService;
@Autowired
private BridgePodService bridgePodService;
@Autowired
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
/**
@ -70,7 +73,6 @@ public class GameController extends BaseController {
// 对当前TPI从TPM clone 版本库
tpmGitURL = Base64Util.decode(tpmGitURL);
tpmGitURL = GameHelper.appendGitUrlWithUser(appConfig.getGitUsername(), appConfig.getGitPassword(), tpmGitURL);
gameService.gitClone(tpiWorkSpace, tpmGitURL, "remote_origin", tpiRepoName);
response.put("code", 0);
@ -100,26 +102,27 @@ public class GameController extends BaseController {
@ApiParam(name = "podType", required = true, value = "pod类型(0.evaluate1.webssh2.evassh)") @RequestParam Integer podType,
@ApiParam(name = "file", required = false, value = "需要传文件的实训,给出文件存放路径(一个目录)及文件类型") String file,
@ApiParam(name = "containers", required = true, value = "需要使用的容器,base64编码") @RequestParam String containers,
@ApiParam(name = "content_modified", required = true, value = "文件是否修改的标志") @RequestParam Integer content_modified)
@ApiParam(name = "content_modified", required = true, value = "文件是否修改的标志") @RequestParam Integer content_modified,
@ApiParam(name = "sec_key", required = false, value = "每一次评测的唯一标识") String sec_key)
throws Exception {
logger.info(
"评测tpiID: {}, tpiGitURL: {}, buildID: {}, isPublished: {}, instanceChallenge: {}, "
+ "testCases: {}, tpmScript: {}, timeLimit: {}, resubmit: {}, "
+ "times: {}, needPortMapping: {}, podType: {}, file: {}, containers: {}, content_modified: {}",
tpiID, tpiGitURL, buildID, isPublished, instanceChallenge, testCases, tpmScript, timeLimit, resubmit, times,
needPortMapping, podType, file, containers, content_modified);
+ "times: {}, needPortMapping: {}, podType: {}, file: {}, containers: {}, content_modified: {}, sec_key: {}",
tpiID, tpiGitURL, buildID, isPublished, instanceChallenge, testCases, tpmScript, timeLimit, resubmit,
times, needPortMapping, podType, file, containers, content_modified, sec_key);
// 记录开始时间
String evaluateStartTime = LocalDateTime.now().toString();
LocalDateTime requestTime = LocalDateTime.now();
String evaluateStartTime = requestTime.toString();
JSONObject cost = new JSONObject();
cost.put("evaluateStartTime", evaluateStartTime);
JedisUtil.set("timeCost:" + tpiID + ":" + buildID, cost.toJSONString());
JedisUtil.set("timeCost:" + tpiID + ":" + buildID, cost.toJSONString());
JSONObject response = new JSONObject();
// 参数处理
tpiGitURL = Base64Util.decode(tpiGitURL);
tpiGitURL = GameHelper.appendGitUrlWithUser(appConfig.getGitUsername(), appConfig.getGitPassword(), tpiGitURL);
needPortMapping = needPortMapping == null ? 0 : needPortMapping;
timeLimit = timeLimit == null ? Integer.parseInt(appConfig.getDefaultTimeLimit()) : timeLimit;
testCases = Base64Util.decode(testCases);
@ -135,7 +138,7 @@ public class GameController extends BaseController {
buildParams.put("tpiID", tpiID);
buildParams.put("tpiGitURL", tpiGitURL);
buildParams.put("buildID", buildID);
buildParams.put("isPublished", isPublished);
buildParams.put("isPublished", isPublished);
buildParams.put("instanceChallenge", instanceChallenge);
buildParams.put("testCases", testCases);
buildParams.put("timeLimit", timeLimit);
@ -145,6 +148,7 @@ public class GameController extends BaseController {
buildParams.put("containers", containers);
buildParams.put("contentModified", content_modified);
buildParams.put("executeTime", executeTime);
buildParams.put("sec_key", sec_key);
// 若实训生成文件 todo:这个处理方式好2b扩展性极差
if (!StringUtils.isEmpty(file)) {
@ -157,6 +161,9 @@ public class GameController extends BaseController {
// podName
String podName = podType != 2 ? "evaluate-" + tpiID : "evassh-" + tpiID;
BridgePod bridgePod = bridgePodService.createBridgePod(podName, tpiID, requestTime, sec_key);
buildParams.put("bridgePodId", bridgePod.getId());
// 若需要端口映射服务则分配端口将podName-port键值对存储于redis
String port = "-1";
@ -172,8 +179,10 @@ public class GameController extends BaseController {
String task = buildParams.toJSONString();
// 最大running pod数量
int maxRunningPodNum = Integer.parseInt(appConfig.getMaxRunningPodNum());
// 此次请求只为轮询时间只返回轮询的时间结果
if (times != 1) {
logger.debug("轮询times: {}", times);
double buildRank;
try {
@ -208,12 +217,14 @@ public class GameController extends BaseController {
}
}
// 获取Running状态的pod数
int runningPodNum = k8sService.getRunningPodNum();
// 判断是否可以立即执行(若pod已经存在或是pod不存在但是此时可以创建pod)
boolean executeImmediately = k8sService.isPodRunning("tpiID", tpiID)
|| (runningPodNum < maxRunningPodNum && k8sService.ableToEvaluate());
boolean executeImmediately = k8sService.isPodRunning("tpiID", tpiID);
if(!executeImmediately) {
// 获取Running状态的pod数
int runningPodNum = k8sService.getRunningPodNum();
boolean able = true; // k8sService.ableToEvaluate();
executeImmediately = (runningPodNum < maxRunningPodNum && able);
}
if (executeImmediately) {
// 直接执行任务
BuildThread buildThread = gameService.getBuildThread(buildParams);
@ -244,159 +255,6 @@ public class GameController extends BaseController {
return response;
}
/**
* 评测 对每一次评测请求调用持续化pods进行处理不需要排队
*/
@RequestMapping(path = "/persistence/gameEvaluate")
@ApiOperation(value = "持续评测", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public JSONObject persistenceGameEvaluate(
@ApiParam(name = "tpiID", required = true, value = "实训实例的ID") @RequestParam String tpiID,
@ApiParam(name = "tpiGitURL", required = true, value = "学员对应当前实训的版本库地址需要base64编码") @RequestParam String tpiGitURL,
@ApiParam(name = "buildID", required = true, value = "本次评测ID") @RequestParam String buildID,
@ApiParam(name = "instanceChallenge", required = true, value = "当前处在第几关") @RequestParam String instanceChallenge,
@ApiParam(name = "testCases", required = true, value = "测试用例") @RequestParam String testCases,
@ApiParam(name = "tpmScript", required = true, value = "tpm评测脚本需要base64编码") @RequestParam String tpmScript,
@ApiParam(name = "timeLimit", required = false, value = "时间限制") Integer timeLimit,
@ApiParam(name = "resubmit", required = true, value = "是否是重复评测") @RequestParam String resubmit,
@ApiParam(name = "times", required = true, value = "是否是时间轮询请求") @RequestParam Integer times,
@ApiParam(name = "needPortMapping", required = false, value = "容器中需要被映射的端口") Integer needPortMapping,
@ApiParam(name = "podType", required = true, value = "pod类型(0.evaluate1.webssh2.evassh)") @RequestParam Integer podType,
@ApiParam(name = "file", required = false, value = "需要传文件的实训,给出文件存放路径(一个目录)及文件类型") String file,
@ApiParam(name = "containers", required = true, value = "需要使用的容器,base64编码") @RequestParam String containers,
@ApiParam(name = "content_modified", required = true, value = "文件是否修改的标志") @RequestParam Integer content_modified,
@ApiParam(name = "persistenceName", required = true, value = "持续pods名称") @RequestParam String persistenceName)
throws Exception {
logger.info(
"评测tpiID: {}, tpiGitURL: {}, buildID: {}, instanceChallenge: {}, "
+ "testCases: {}, tpmScript: {}, timeLimit: {}, resubmit: {}, "
+ "times: {}, needPortMapping: {}, podType: {}, file: {}, containers: {}, content_modified: {}",
tpiID, tpiGitURL, buildID, instanceChallenge, testCases, tpmScript, timeLimit, resubmit, times,
needPortMapping, podType, file, containers, content_modified);
// 记录开始时间
String evaluateStartTime = LocalDateTime.now().toString();
JSONObject cost = new JSONObject();
cost.put("evaluateStartTime", evaluateStartTime);
JedisUtil.set("timeCost:" + tpiID + ":" + buildID, cost.toJSONString());
JSONObject response = new JSONObject();
// 参数处理
tpiGitURL = Base64Util.decode(tpiGitURL);
needPortMapping = needPortMapping == null ? 0 : needPortMapping;
timeLimit = timeLimit == null ? Integer.parseInt(appConfig.getDefaultTimeLimit()) : timeLimit - 10;
testCases = Base64Util.decode(testCases);
containers = Base64Util.decode(containers);
// 每次评测均生成新TPI评测脚本
tpmScript = Base64Util.decode(tpmScript);
String tpiWorkspace = appConfig.getWorkspace() + File.separator + "myshixun_" + tpiID;
String tpiRepoName = GameHelper.getRepoName(tpiGitURL);
gameService.generateTpiEvaluateShellScript(tpmScript, tpiWorkspace, tpiRepoName);
JSONObject buildParams = new JSONObject(true);
buildParams.put("tpiID", tpiID);
buildParams.put("tpiGitURL", tpiGitURL);
buildParams.put("buildID", buildID);
buildParams.put("instanceChallenge", instanceChallenge);
buildParams.put("testCases", testCases);
buildParams.put("timeLimit", timeLimit);
buildParams.put("resubmit", resubmit);
buildParams.put("needPortMapping", needPortMapping);
buildParams.put("podType", podType);
buildParams.put("containers", containers);
buildParams.put("contentModified", content_modified);
buildParams.put("persistenceName", persistenceName);
// 若实训生成文件 todo:这个处理方式好2b扩展性极差
if (!StringUtils.isEmpty(file)) {
file = Base64Util.decode(file);
buildParams.put("file", file);
// 清空目标文件夹以防止影响此次评测结果
GameHelper.clearFiles(tpiWorkspace + File.separator + tpiRepoName + File.separator
+ JSONObject.parseObject(file).getString("path"));
}
// podName
String podName = podType != 2 ? "evaluate-" + tpiID : "evassh-" + tpiID;
// 若需要端口映射服务则分配端口将podName-port键值对存储于redis
String port = "-1";
if (needPortMapping != -1) {
port = JedisUtil.hget("port", podName);
if (port == null) {
port = PortUtil.getPort() + "";
JedisUtil.hset("port", podName, port);
}
}
// 构建任务字符串便于redis存储
String task = buildParams.toJSONString();
// 最大running pod数量
int maxRunningPodNum = Integer.parseInt(appConfig.getMaxRunningPodNum());
// 此次请求只为轮询时间只返回轮询的时间结果
if (times != 1) {
double buildRank;
try {
buildRank = JedisUtil.zrank("task", task);
} catch (Exception e) {
response.put("ableToCreate", 0);
response.put("waitNum", maxRunningPodNum + JedisUtil.zlen("task"));
response.put("code", 0);
response.put("msg", "等待评测");
return response;
}
if (buildRank != Double.MIN_VALUE) {
logger.debug("任务:{} : 还在等待队列中!", task);
response.put("ableToCreate", 0);
response.put("waitNum", buildRank == Double.MAX_VALUE ? maxRunningPodNum + JedisUtil.zlen("task")
: buildRank + maxRunningPodNum);
response.put("code", 0);
response.put("msg", "等待评测");
return response;
} else {
// 轮询时间请求发现目标任务不在队列就直接认为其正在运行
logger.debug("任务:{} : 正在执行中!", task);
response.put("ableToCreate", 1);
response.put("waitNum", 0);
response.put("code", 0);
response.put("port", Integer.parseInt(port));
response.put("msg", "正在评测");
return response;
}
}
// 持续化pods直接处理任务
BuildThreadPersistence buildThreadPersistence = (BuildThreadPersistence) BeanFactory
.getObejct("BuildThreadPersistence");
buildThreadPersistence.setBuildParams(buildParams, Thread.currentThread());
threadPoolTaskExecutor.execute(buildThreadPersistence);
try {
// 主线程等待1秒
Thread.sleep(1000);
//如果是自己醒来设置同步返回失败
buildThreadPersistence.setSyncSuccess(false);
} catch (InterruptedException e) {
logger.info("当前容器同步返回数据成功,tpiID:{}, 总消耗时间{}", tpiID, // 评测总时间(除回传结果给educoder之外的总时间)
// 当前时间 -
// 存储在redis中的开始时间
(System.currentTimeMillis() - TimeHelper.convertTimeToMillis(evaluateStartTime)));
}
response.put("syncResult", buildThreadPersistence.getSyncResult());
response.put("ableToCreate", 1);
response.put("costTime", System.currentTimeMillis() - TimeHelper.convertTimeToMillis(evaluateStartTime));
response.put("waitNum", 0);
response.put("code", 0);
response.put("port", port);
response.put("msg", "评测完成");
logger.debug("直接执行任务task: {}, tpi: {}", response, tpiID);
return response;
}
/**
* tpm版本库已更新同步
*/
@ -413,25 +271,17 @@ public class GameController extends BaseController {
JSONObject response = new JSONObject();
tpiGitURL = Base64Util.decode(tpiGitURL);
tpiGitURL = GameHelper.appendGitUrlWithUser(appConfig.getGitUsername(), appConfig.getGitPassword(), tpiGitURL);
tpmGitURL = Base64Util.decode(tpmGitURL);
tpmGitURL = GameHelper.appendGitUrlWithUser(appConfig.getGitUsername(), appConfig.getGitPassword(), tpmGitURL);
String tpiRepoName = GameHelper.getRepoName(tpiGitURL);
String path = appConfig.getWorkspace() + File.separator + "myshixun_" + tpiID;
try {
// 从tpm远程库拉取代码到myshixun版本库然后强推到tpi远程库
gameService.gitPullFromTpm(path, tpmGitURL, tpiRepoName);
gameService.gitPushToTpi(path, tpiGitURL, identifier);
// 从tpm远程库拉取代码到myshixun版本库然后强推到tpi远程库
gameService.gitPullFromTpm(path, tpmGitURL, tpiRepoName, tpiID);
gameService.gitPushToTpi(path, tpiGitURL, identifier, tpiID);
logger.debug("tpm库更新内容已同步tpiID:{}", tpiID);
response.put("code", 0);
response.put("msg", "版本库更新成功");
} catch (GameException e) {
logger.error("tpm库更新内容同步失败, tpiID:{}", tpiID);
response.put("code", -1);
response.put("msg", "版本库同步失败!");
}
logger.debug("tpm库更新内容已同步tpiID:{}", tpiID);
response.put("code", 0);
response.put("msg", "版本库更新成功");
return response;
}
@ -452,5 +302,4 @@ public class GameController extends BaseController {
tpiGitURL = Base64Util.decode(tpiGitURL);
return gameService.check(tpiID, tpiGitURL);
}
}

View File

@ -1,52 +1,88 @@
package com.educoder.bridge.game.controller;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.controller.BaseController;
import com.educoder.bridge.game.service.VncService;
import com.educoder.bridge.common.utils.Base64Util;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.common.utils.PortUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.educoder.bridge.common.settings.AppConfig;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.utils.Base64Util;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.common.utils.PortUtil;
import com.educoder.bridge.game.service.VncService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@Api(value = "vnc控制器", hidden = true)
@RestController
@RequestMapping("/vnc")
public class VncController extends BaseController {
public class VncController {
private static final Logger logger = LoggerFactory.getLogger(VncController.class);
@Autowired
private AppConfig appConfig;
@Autowired
private VncService vncService;
@Autowired
private VncService vncService;
@RequestMapping(path = "/getvnc")
@ApiOperation(value = "图形界面", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public JSONObject getvnc(
@ApiParam(name = "tpiID", required = true, value = "实训实例的ID") @RequestParam String tpiID,
@ApiParam(name = "containers", required = true, value = "需要使用的容器,base64编码") @RequestParam String containers)
throws Exception{
logger.info("获取vnc图形界面端口tpiID: {}, containers: {}", tpiID, containers);
@RequestMapping(path = "/getvnc")
@ApiOperation(value = "图形界面", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public JSONObject getvnc(@ApiParam(name = "tpiID", required = true, value = "实训实例的ID") @RequestParam String tpiID,
@ApiParam(name = "containers", required = true, value = "需要使用的容器,base64编码") @RequestParam String containers)
throws Exception {
logger.info("获取vnc图形界面端口tpiID: {}, containers: {}", tpiID, containers);
JSONObject response = new JSONObject();
JSONObject response = new JSONObject();
String podName = "vnc-" + tpiID;
containers = Base64Util.decode(containers);
String podName = "vnc-" + tpiID;
containers = Base64Util.decode(containers);
// 为vnc分配port
String port = JedisUtil.hget("port", podName);
if (port == null) {
port = PortUtil.getPort() + "";
JedisUtil.hset("port", podName, port);
}
// 为vnc分配port
String port = JedisUtil.hget("port-vnc", podName);
if (port == null) {
port = PortUtil.getPort() + "";
JedisUtil.hset("port-vnc", podName, port);
}
vncService.getvnc(tpiID, containers);
vncService.getVnc(tpiID, containers);
response.put("code", 0);
response.put("port", port);
return response;
}
response.put("code", 0);
response.put("port", port);
return response;
}
@ApiOperation(value = "删除tpiID对应的VNC类型的pod", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@RequestMapping(path = "/delete")
public JSONObject delete(@ApiParam(name = "tpiID", required = true, value = "tpiID") @RequestParam String tpiID,
@ApiParam(name = "digestKey", required = true, value = "签名") @RequestParam String digestKey,
@ApiParam(name = "identifier", required = true, value = "game的标示") @RequestParam String identifier)
throws Exception {
logger.info("前端主动调用vnc删除命令tpiID: {}", tpiID);
JSONObject response = new JSONObject();
// 用identifier与私钥拼接与digestKey比较相等响应不想等拒绝
String serverDigestKey = DigestUtils.sha1Hex(identifier + appConfig.getSecretKey());
if (digestKey.equals(serverDigestKey)) {
try {
vncService.deleteNow(tpiID);
response.put("code", 0);
response.put("msg", "成功发起删除命令");
} catch (Exception e) {
logger.error("主动删除pod失败", e);
response.put("code", -1);
response.put("msg", "删除pod失败");
}
} else {
response.put("code", -1);
response.put("msg", "认证不通过,服务端拒绝连接");
}
return response;
}
}

View File

@ -1,11 +1,16 @@
package com.educoder.bridge.game.exception;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import com.alibaba.fastjson.JSONObject;
/**
* 异常处理类
*
@ -14,28 +19,32 @@ import org.springframework.web.context.request.WebRequest;
@ControllerAdvice
public class ControllerExceptionHandler {
@ExceptionHandler(GameException.class)
@ResponseBody
public JSONObject handleGameExceptions(GameException e, WebRequest request) {
JSONObject response = new JSONObject();
private final Logger logger = LoggerFactory.getLogger(getClass());
response.put("code", e.getCode());
response.put("msg", e.getMsg());
@ExceptionHandler(GameException.class)
@ResponseBody
public ResponseEntity<JSONObject> handleGameExceptions(GameException e, WebRequest request) {
logger.error("捕获到GameException", e);
return response;
}
JSONObject jsonObj = new JSONObject();
jsonObj.put("code", e.getCode());
jsonObj.put("msg", e.getMsg());
@ExceptionHandler(Throwable.class)
@ResponseBody
public JSONObject handleOtherExceptions(Throwable e, WebRequest request) {
JSONObject response = new JSONObject();
ResponseEntity<JSONObject> res = new ResponseEntity<>(jsonObj, HttpStatus.OK);
return res;
}
e.printStackTrace();
@ExceptionHandler(Throwable.class)
@ResponseBody
public ResponseEntity<JSONObject> handleOtherExceptions(Throwable e, WebRequest request) {
logger.error("捕获到Throwable", e);
response.put("code", -1);
response.put("msg", "未知错误!" + e.getMessage());
JSONObject jsonObj = new JSONObject();
jsonObj.put("code", -1);
jsonObj.put("msg", "未知错误!" + e.getMessage());
return response;
}
ResponseEntity<JSONObject> res = new ResponseEntity<>(jsonObj, HttpStatus.OK);
return res;
}
}

View File

@ -20,11 +20,13 @@ public class GameException extends Exception {
}
public GameException(int code, String msg) {
super(msg);
this.code = code;
this.msg = msg;
}
public GameException(String msg) {
super(msg);
this.code = -1;
this.msg = msg;
}

View File

@ -3,38 +3,31 @@
*/
package com.educoder.bridge.game.exception;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.utils.GameHelper;
import com.educoder.bridge.game.service.GameService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.game.thread.AftermathException;
/**
* 未经捕获的异常处理
*
* @author weishao
*/
@Service
public class UncaughtBridgeExceptionHandler implements Thread.UncaughtExceptionHandler {
@Autowired
private GameService gameService;
private static Logger logger = LoggerFactory.getLogger(UncaughtBridgeExceptionHandler.class);
private JSONObject buildParams;
private Logger logger = LoggerFactory.getLogger(UncaughtBridgeExceptionHandler.class);
@Override
public void uncaughtException(Thread t, Throwable e) {
// 此处只处理善后异常其它已经在善后处理中解决
if (e instanceof AftermathException) {
AftermathException ae = (AftermathException) e;
JSONObject buildParams = ae.getBuildParams();
logger.error("评测线程" + buildParams.getString("tpiID") + "出错,善后异常", e);
}
public UncaughtBridgeExceptionHandler (JSONObject buildParams) {
this.buildParams = buildParams;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
logger.error("评测线程抛出异常:", e);
e.printStackTrace();
String testCases = buildParams.getString("testCases");
// 回传错误信息到前台
gameService.encapsulateBuildResult(GameHelper.getUnknowErrorResult(JSONObject.parseObject(testCases).size()), buildParams, testCases);
}
}
}

View File

@ -0,0 +1,37 @@
package com.educoder.bridge.game.filter;
import org.slf4j.MDC;
import javax.servlet.*;
import java.io.IOException;
/**
* 为每一条日志增加sec_key
*/
public class LogbackFilter implements Filter {
// 每一次评测的唯一标识
private static final String SEC_KEY = "sec_key";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
MDC.put(SEC_KEY, request.getParameter("sec_key"));
try {
chain.doFilter(request, response);
} finally {
MDC.remove(SEC_KEY);
}
}
@Override
public void destroy() {
}
}

View File

@ -4,7 +4,8 @@ import java.util.List;
/**
* 评测结果
* @author liliy
*
* @author liliy
*/
public class BuildResult {
@ -14,6 +15,25 @@ public class BuildResult {
private List<Case> msg;
private String resubmit;
private String compileSuccess;
private String createPodStatus;
private String downloadStatus;
private String sec_key;
/**
* 步骤输出分步输出时的步骤
*/
private String step;
/**
* 输出存文本
*/
private String textMsg;
public String getSec_key() {
return sec_key;
}
public void setSec_key(String sec_key) {
this.sec_key = sec_key;
}
public String getBuildID() {
return buildID;
@ -55,12 +75,13 @@ public class BuildResult {
this.resubmit = resubmit;
}
public BuildResult(String buildID, String status, String outPut, List<Case> msg, String resubmit) {
public BuildResult(String buildID, String status, String outPut, List<Case> msg, String resubmit, String sec_key) {
this.buildID = buildID;
this.status = status;
this.outPut = outPut;
this.msg = msg;
this.resubmit = resubmit;
this.sec_key = sec_key;
}
public String getCompileSuccess() {
@ -70,4 +91,37 @@ public class BuildResult {
public void setCompileSuccess(String compileSuccess) {
this.compileSuccess = compileSuccess;
}
public String getStep() {
return step;
}
public void setStep(String step) {
this.step = step;
}
public String getTextMsg() {
return textMsg;
}
public void setTextMsg(String textMsg) {
this.textMsg = textMsg;
}
public String getCreatePodStatus() {
return createPodStatus;
}
public void setCreatePodStatus(String createPodStatus) {
this.createPodStatus = createPodStatus;
}
public String getDownloadStatus() {
return downloadStatus;
}
public void setDownloadStatus(String downloadStatus) {
this.downloadStatus = downloadStatus;
}
}

View File

@ -0,0 +1,57 @@
package com.educoder.bridge.game.model;
/**
* 评测结果
*
* @author jiangzhongxiang
*
*/
public class EvaluatingResult {
/**
* 整体成功
*/
Boolean wholeSuccess;
/**
* 分步失败
*/
Boolean stepFail;
public Boolean getWholeSuccess() {
return wholeSuccess;
}
public void setWholeSuccess(Boolean wholeSuccess) {
this.wholeSuccess = wholeSuccess;
}
public Boolean getStepFail() {
return stepFail;
}
public void setStepFail(Boolean stepFail) {
this.stepFail = stepFail;
}
public void merge(EvaluatingResult eResult) {
if (null != eResult.wholeSuccess) {
if (null == this.wholeSuccess) {
this.wholeSuccess = eResult.wholeSuccess;
} else {
this.wholeSuccess = this.wholeSuccess && eResult.wholeSuccess;
}
}
if (null != eResult.stepFail) {
if (null == this.stepFail) {
this.stepFail = eResult.stepFail;
} else {
this.stepFail = this.stepFail || eResult.stepFail;
}
}
}
public boolean isTaskSuccess() {
return Boolean.TRUE.equals(wholeSuccess) || Boolean.FALSE.equals(stepFail);
}
}

View File

@ -0,0 +1,16 @@
package com.educoder.bridge.game.model;
public class PodCreateStrategy {
private Integer timeLimit;
public Integer getTimeLimit() {
return timeLimit;
}
public PodCreateStrategy setTimeLimit(Integer timeLimit) {
this.timeLimit = timeLimit;
return this;
}
}

View File

@ -0,0 +1,16 @@
package com.educoder.bridge.game.model;
import io.fabric8.kubernetes.api.model.Pod;
public class PodRef {
private Pod pod;
public Pod getPod() {
return pod;
}
public void setPod(Pod pod) {
this.pod = pod;
}
}

View File

@ -0,0 +1,29 @@
package com.educoder.bridge.game.model;
/**
* 简单评测结果
*
* @author jzx
*/
public class SimpleBuildResult {
private String buildID;
private String textMsg;
public String getBuildID() {
return buildID;
}
public void setBuildID(String buildID) {
this.buildID = buildID;
}
public String getTextMsg() {
return textMsg;
}
public void setTextMsg(String textMsg) {
this.textMsg = textMsg;
}
}

View File

@ -0,0 +1,48 @@
package com.educoder.bridge.game.model;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import io.fabric8.kubernetes.client.dsl.ExecWatch;
public class WatchObject {
PipedInputStream in;
PipedInputStream pis;
PipedOutputStream pos;
ExecWatch watch;
public PipedInputStream getIn() {
return in;
}
public void setIn(PipedInputStream in) {
this.in = in;
}
public PipedInputStream getPis() {
return pis;
}
public void setPis(PipedInputStream pis) {
this.pis = pis;
}
public PipedOutputStream getPos() {
return pos;
}
public void setPos(PipedOutputStream pos) {
this.pos = pos;
}
public ExecWatch getWatch() {
return watch;
}
public void setWatch(ExecWatch watch) {
this.watch = watch;
}
}

View File

@ -1,40 +1,38 @@
package com.educoder.bridge.game.service;
import java.util.Map;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.common.utils.HttpHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.common.utils.NioHttpClientUtils;
/**
* Created by guange on 17/02/2017.
*/
@Service("EducoderService")
public class EducoderService {
private final static Logger logger = LoggerFactory.getLogger(EducoderService.class);
private final static Logger logger = LoggerFactory.getLogger(EducoderService.class);
@Autowired
AppConfig appConfig;
@Autowired
AppConfig appConfig;
public void commitResultToEducoder(Map buildResult) {
JSONObject result = new JSONObject(buildResult);
logger.info("educoderURL: {}, result: {}", appConfig.getEducoderURL(), result);
NioHttpClientUtils.sendPost(appConfig.getEducoderURL(), result);
}
public void commitResultToEducoder (Map buildResult){
JSONObject result = new JSONObject(buildResult);
public void commitResultToEducoder(Map buildResult, int readTimeOut) {
JSONObject result = new JSONObject(buildResult);
logger.info("educoderURL: {}, result: {}", appConfig.getEducoderURL(), result);
NioHttpClientUtils.sendPost(appConfig.getEducoderURL(), result, readTimeOut);
}
logger.info("educoderURL: {}, result: {}", appConfig.getEducoderURL(), result);
HttpHelper.sendPost(appConfig.getEducoderURL(), result);
}
public void commitResultToEducoder (Map buildResult, int readTimeOut){
JSONObject result = new JSONObject(buildResult);
logger.info("educoderURL: {}, result: {}", appConfig.getEducoderURL(), result);
HttpHelper.sendPost(appConfig.getEducoderURL(), result, readTimeOut);
}
}
public void commitSimpileResultToEducoder(Map buildResult) {
JSONObject result = new JSONObject(buildResult);
logger.info("educoderURL: {}, result: {}", appConfig.getSimpileEducoderURL(), result);
NioHttpClientUtils.sendPost(appConfig.getSimpileEducoderURL(), result);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
package com.educoder.bridge.game.service;
import org.springframework.stereotype.Service;
/**
* 暂时不使用
*
* @author mm
*
*/
@Service("K8sExecService")
public class K8sExecService {
}

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,29 @@
package com.educoder.bridge.game.service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.utils.Base64Util;
import com.educoder.bridge.common.utils.GameHelper;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.common.utils.ShellUtil;
import com.educoder.bridge.game.exception.GameException;
import java.time.Duration;
import java.time.Instant;
import org.apache.commons.lang.StringUtils;
import org.omg.CORBA.TIMEOUT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeoutException;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.common.utils.Base64Util;
import com.educoder.bridge.common.utils.GameHelper;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.common.utils.ProcessStatusUtil;
import com.educoder.bridge.common.utils.ShellUtil;
import com.educoder.bridge.common.utils.TpUtils;
import com.educoder.bridge.game.exception.GameException;
import com.educoder.bridge.game.model.BuildResult;
import com.educoder.bridge.k8s.service.BridgePodService;
import io.fabric8.kubernetes.api.model.Pod;
/**
* 与kubernetes交互的service
@ -25,178 +34,187 @@ import java.util.concurrent.TimeoutException;
@Service
public class KubernetesService {
private static final Logger logger = LoggerFactory.getLogger(KubernetesService.class);
private static final Logger logger = LoggerFactory.getLogger(KubernetesService.class);
@Autowired
PodManagerService podManagerService;
@Autowired
private K8sService k8sService;
@Autowired
private GameService gameService;
@Autowired
private AppConfig appConfig;
@Autowired
private BridgePodService bridgePodService;
/**
* 在pod中执行评测脚本
*/
public void executeShellInPod(JSONObject buildParams, Pod pod, int needPortMapping, int timeLimit, int isPublished,
int instanceChallenge, String testCases) {
String podName = pod.getMetadata().getName();
logger.debug("podName: {}, needPortMapping: {}, timeLimit: {}, isPublished: {}, instanceChallenge: {}", podName,
needPortMapping, timeLimit, isPublished, instanceChallenge);
// 在pod中限时执行评测脚本
// 设置输入数组
StringBuilder ins = new StringBuilder();
JSONArray cases = JSONArray.parseArray(testCases);
for (int i = 0; i < cases.size(); i++) {
String input = cases.getJSONObject(i).getString("input");
ins.append("\"" + Base64Util.encodeNoSafe("".equals(input) ? " " : input) + "\"" + ",");
}
ins = ins.length() == 0 ? ins : ins.deleteCharAt(ins.length() - 1);
String tpiID = buildParams.getString("tpiID");
String buildID = buildParams.getString("buildID");
String tpiWorkspace = TpUtils.buildTpiWorkspace(appConfig.getWorkspace(), tpiID);
String shFile = tpiWorkspace + "/evaluate.sh";
String command = "kubectl exec " + podName + " timeout " + timeLimit + " bash " + shFile + " " + instanceChallenge + " " + ins;
logger.info("evaluate command: {}", command);
// 为pod的score加1若pod之前不存在则score为1
JedisUtil.zup("taskNum", podName);
Instant executeStartInstant = Instant.now();
JSONObject buildResult = ShellUtil.executeAndGetExitStatus(command);
int exitStatus = buildResult.getInteger("exitStatus");
String out = buildResult.getString("out");
JSONObject timeCost = this.recordExecuteTime(executeStartInstant, tpiID, buildID);
BuildResult result = processResult(buildParams, podName, needPortMapping, timeLimit, isPublished, instanceChallenge, testCases,
command, exitStatus, out);// timeout, 繁忙
boolean taskResult = "0".equals(result.getStatus());
if (taskResult) { // 如果正常完成清理资源
clearResource(podName);
}
bridgePodService.updateExecuteTime(buildParams, timeCost, pod, result);
JedisUtil.del("timeCost:" + tpiID + ":" + buildID);
}
private JSONObject recordExecuteTime(Instant executeStartInstant, String tpiID, String buildID) {
double executeCost = (double) Duration.between(executeStartInstant, Instant.now()).toMillis() / 1000;
JSONObject timeCost = GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "execute",
String.format("%.3f", executeCost));
return timeCost;
}
@Autowired
PodManagerService podManagerService;
public BuildResult processResult(JSONObject buildParams, String podName, int needPortMapping, int timeLimit,
int isPublished, int instanceChallenge, String testCases, String command, int exitStatus, String out) {
JSONArray cases = JSONArray.parseArray(testCases);
if (ProcessStatusUtil.isTimeout(exitStatus)) {
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
}
String oriOut = out;
// 为了避免其他输出干扰结果判断仅提取平台封装输出
out = GameHelper.getRealResult(out);
// 如果不是调试模式
if (isPublished == 1) {
// 正式环境下如果结果为空或者不是有效的json格式报系统繁忙
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
debugErrorOut(command, oriOut, out);
out = GameHelper.getUnknowErrorResult(cases.size());
}
} else {
// 测试环境下如果提出自定义输出后结果为空或者不是有效的json格式可判定为脚本错误
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
out = GameHelper.getShellErrorResult(cases.size(), oriOut);
} else { // 否则为正常输出
if (!out.equals(oriOut)) { // 对于正常输出如果没有任何冗余不予提示否则提示为调试模式
JSONObject buildOutAndOriOut = JSONObject.parseObject(out);
buildOutAndOriOut.put("oriOut", oriOut);
out = buildOutAndOriOut.toString();
}
}
}
// 此时已经在pod中执行完评测脚本pod失去了一个正在执行任务.
// 大多数情况下此时该pod对应的score为0即无任务,将该pod从zset中移除表示这不再是一个任务运行期pod
JedisUtil.zdown("taskNum", podName);
return gameService.encapsulateBuildResult(out, buildParams, testCases);
}
/**
* 在pod中执行评测脚本
*/
public String executeShellInPod(String podName, int needPortMapping, int timeLimit, int isPublished, int instanceChallenge,
String testCases) {
logger.debug("podName: {}, needPortMapping: {}, timeLimit: {}, isPublished: {}, instanceChallenge: {}",
podName, needPortMapping, timeLimit, isPublished, instanceChallenge);
private void clearResource(String podName) {
if (!svcExist(podName) && !svcExist(podName + "-22") // 22的特殊处理
&& !JedisUtil.zhas("taskNum", podName)) {
deletePod(podName);
}
gameService.executeWaitingTask();
}
// 设置输入数组
StringBuffer ins = new StringBuffer();
JSONArray cases = JSONArray.parseArray(testCases);
for (int i = 0; i < cases.size(); i++) {
String input = cases.getJSONObject(i).getString("input");
ins.append("\"" + Base64Util.encodeNoSafe("".equals(input) ? " " : input) + "\"" + ",");
}
ins = ins.length() == 0 ? ins : ins.deleteCharAt(ins.length() - 1);
/**
* 在pod中执行评测脚本
*/
public String executePersistenceShellInPod(String podName, String tpiID, int needPortMapping, int timeLimit,
int instanceChallenge, String testCases) throws GameException {
logger.debug("podName: {}, needPortMapping: {}, timeLimit: {}, instanceChallenge: {}", podName, needPortMapping,
timeLimit, instanceChallenge);
// 设置输入数组
StringBuffer ins = new StringBuffer();
JSONArray cases = JSONArray.parseArray(testCases);
for (int i = 0; i < cases.size(); i++) {
String input = cases.getJSONObject(i).getString("input");
ins.append("\"" + Base64Util.encodeNoSafe("".equals(input) ? " " : input) + "\"" + ",");
}
ins = ins.length() == 0 ? ins : ins.deleteCharAt(ins.length() - 1);
int setTimeLimit = timeLimit / 2;
// 拼接出k8s执行命令
String command = "timeout " + setTimeLimit + " kubectl exec " + podName + " bash " + appConfig.getWorkspace()
+ "/myshixun_" + tpiID + "/evaluate.sh " + instanceChallenge + " " + ins;
logger.debug("evaluate command: {}", command);
// 为pod的score加1若pod之前不存在则score为1
JedisUtil.zup("taskNum", podName);
// 在pod中限时执行评测脚本
String out;
try {
JSONObject buildResult = ShellUtil.executeAndGetExitStatus(command, 1);
out = buildResult.getString("out");
// todo: 有时候不抛异常只是任务被kill掉很奇怪
if (buildResult.getInteger("exitStatus") == 137) {
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
}
if (StringUtils.isBlank(out)) {
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
}
} catch (Exception e) {
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
}
String oriOut = out;
// 为了避免其他输出干扰结果判断仅提取平台封装输出
out = GameHelper.getRealResult(out);
// 如果结果为空或者不是有效的json格式可判定为脚本错误
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
debugErrorOut(command, oriOut, out);
out = GameHelper.getShellErrorResult(cases.size(), out);
}
// 此时已经在pod中执行完评测脚本pod失去了一个正在执行任务.
// 大多数情况下此时该pod对应的score为0即无任务,将该pod从zset中移除表示这不再是一个任务运行期pod
JedisUtil.zdown("taskNum", podName);
return out;
}
// 拼接出k8s执行命令
String command = "timeout " + timeLimit + " kubectl exec " + podName + " bash "
+ "/data/workspace/myshixun_" + podName.split("-")[1] + "/evaluate.sh " + instanceChallenge + " " + ins;
/**
* 输出执行信息
*
* @param command
* @param oriOut
* @param out
*/
private void debugErrorOut(String command, String oriOut, String out) {
logger.info("执行命令:{}, 原始输出:{}, 最终输出: {}", command, oriOut, out);
}
logger.debug("evaluate command: {}", command);
/**
* 需要端口映射服务的pod判断其svc是否存在
*
* @param podName
* @return
*/
public boolean svcExist(String podName) {
return k8sService.svcExist(podName);
}
// 为pod的score加1若pod之前不存在则score为1
JedisUtil.zup("taskNum", podName);
// 在pod中限时执行评测脚本
JSONObject buildResult = ShellUtil.executeAndGetExitStatus(command);
String out = buildResult.getString("out");
// 详见timeout的help说明
if (buildResult.getInteger("exitStatus") == 124 || buildResult.getInteger("exitStatus") == (128 + 9)) {
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
}
String oriOut = out;
// 为了避免其他输出干扰结果判断仅提取平台封装输出
out = GameHelper.getRealResult(out);
// 如果不是调试模式
if (isPublished == 1) {
// 正式环境下如果结果为空或者不是有效的json格式报系统繁忙
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
debugErrorOut(command, oriOut, out);
out = GameHelper.getUnknowErrorResult(cases.size());
}
} else {
// 测试环境下如果提出自定义输出后结果为空或者不是有效的json格式可判定为脚本错误
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
out = GameHelper.getShellErrorResult(cases.size(), oriOut);
} else { // 否则为正常输出
if (!out.equals(oriOut)) { // 对于正常输出如果没有任何冗余不予提示否则提示为调试模式
JSONObject buildOutAndOriOut = JSONObject.parseObject(out);
buildOutAndOriOut.put("oriOut", oriOut);
out = buildOutAndOriOut.toString();
}
}
}
// 此时已经在pod中执行完评测脚本pod失去了一个正在执行任务.
// 大多数情况下此时该pod对应的score为0即无任务,将该pod从zset中移除表示这不再是一个任务运行期pod
JedisUtil.zdown("taskNum", podName);
return out;
}
/**
* 在pod中执行评测脚本
*/
public String executePersistenceShellInPod(String podName,String tpiID, int needPortMapping, int timeLimit, int instanceChallenge,
String testCases) throws GameException {
logger.debug("podName: {}, needPortMapping: {}, timeLimit: {}, instanceChallenge: {}",
podName, needPortMapping, timeLimit, instanceChallenge);
// 设置输入数组
StringBuffer ins = new StringBuffer();
JSONArray cases = JSONArray.parseArray(testCases);
for (int i = 0; i < cases.size(); i++) {
String input = cases.getJSONObject(i).getString("input");
ins.append("\"" + Base64Util.encodeNoSafe("".equals(input) ? " " : input) + "\"" + ",");
}
ins = ins.length() == 0 ? ins : ins.deleteCharAt(ins.length() - 1);
int setTimeLimit = timeLimit/2;
// 拼接出k8s执行命令
String command = "timeout " + setTimeLimit + " kubectl exec " + podName + " bash "
+ "/data/workspace/myshixun_" + tpiID + "/evaluate.sh " + instanceChallenge + " " + ins;
logger.debug("evaluate command: {}", command);
// 为pod的score加1若pod之前不存在则score为1
JedisUtil.zup("taskNum", podName);
// 在pod中限时执行评测脚本
String out;
try {
JSONObject buildResult = ShellUtil.executeAndGetExitStatus(command, 1);
out = buildResult.getString("out");
// todo: 有时候不抛异常只是任务被kill掉很奇怪
if (buildResult.getInteger("exitStatus") == 137) {
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
}
if(StringUtils.isBlank(out)){
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
}
} catch (Exception e) {
out = GameHelper.getTimeOutResult(cases.size(), timeLimit);
}
String oriOut = out;
// 为了避免其他输出干扰结果判断仅提取平台封装输出
out = GameHelper.getRealResult(out);
// 如果结果为空或者不是有效的json格式可判定为脚本错误
if (StringUtils.isEmpty(out) || !GameHelper.isValidJSON(out)) {
debugErrorOut(command, oriOut, out);
out = GameHelper.getShellErrorResult(cases.size(), out);
}
// 此时已经在pod中执行完评测脚本pod失去了一个正在执行任务.
// 大多数情况下此时该pod对应的score为0即无任务,将该pod从zset中移除表示这不再是一个任务运行期pod
JedisUtil.zdown("taskNum", podName);
return out;
}
/**
* 输出执行信息
* @param command
* @param oriOut
* @param out
*/
private void debugErrorOut(String command, String oriOut, String out) {
logger.info("执行命令:{}, 原始输出:{}, 最终输出: {}",
command, oriOut, out);
}
/**
* 需要端口映射服务的pod判断其svc是否存在
*
* @param podName
* @return
*/
public boolean svcExist(String podName) {
JSONObject out = ShellUtil.executeAndGetExitStatus("kubectl get service " + podName);
if (out.getInteger("exitStatus") == 0) {
return true;
} else {
return false;
}
}
/**
* 删除pod
* @param podName
*/
public void deletePod(String podName) {
// 若Pod的删除定时任务之前已经生成则取消
podManagerService.cancelDel(podName);
logger.info("直接删除pod{}", podName);
String command = "kubectl delete pod " + podName + " --now";
ShellUtil.executeAndGetExitStatus(command);
}
}
/**
* 删除pod
*
* @param podName
*/
public void deletePod(String podName) {
// 若Pod的删除定时任务之前已经生成则取消
podManagerService.cancelDel(podName);
k8sService.deletePod(podName);
}
}

View File

@ -1,110 +1,104 @@
package com.educoder.bridge.game.service;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.utils.BeanFactory;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.common.utils.ShellUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.educoder.bridge.common.utils.BeanFactory;
import com.educoder.bridge.common.utils.JedisUtil;
/**
* pod生命周期管理
*/
@Service
public class PodManagerService {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Logger logger = LoggerFactory.getLogger(getClass());
private final ConcurrentHashMap<String, Long> deleteTimeMap = new ConcurrentHashMap<>();
@Autowired
private K8sService k8sService;
private final ConcurrentHashMap<String, Long> deleteTimeMap = new ConcurrentHashMap<>();
/**
* 在指定时间删除pod 重复调用可以重置设定
*
* @param podName
* @param delayTime
* 单位秒
*/
public void deletePodAfterTime(String podName, long delayTime) {
deleteTimeMap.put(podName, System.currentTimeMillis() + delayTime * 1000);
}
/**
* 在指定时间删除pod
* 重复调用可以重置设定
*
* @param podName
* @param delayTime 单位秒
*/
public void deletePodAfterTime(String podName, long delayTime) {
deleteTimeMap.put(podName, System.currentTimeMillis() + delayTime * 1000);
}
@PostConstruct
public void init() {
new Thread(() -> {
this.doWork();
}).start();
}
private void doWork() {
AtomicBoolean hasDel = new AtomicBoolean(false);
while (true) {
hasDel.set(false);
deleteTimeMap.forEach((podName, delTime) -> {
if (delTime < System.currentTimeMillis()) {
hasDel.set(true);
try {
delPod(podName);
} catch (Exception e) {
logger.error("delPod:" + podName, e);
}
}
});
try {
if (!hasDel.get()) {
Thread.sleep(1000);
} // 没任务休眠2秒
} catch (Exception e) {
// ignore quietly
}
}
}
@PostConstruct
public void init(){
new Thread(() -> {
this.doWork();
}).start();
}
// TODO 不需要 synchronized
private synchronized void delService(String podName) {
Boolean r = k8sService.deleteService(podName);
logger.info("定时任务:删除实训 {} service结果{}", podName, r);
if (Boolean.TRUE.equals(r)) {
JedisUtil.hdel("port", podName);
JedisUtil.hdel("port1", podName);
logger.info("定时任务: 删除pod {}对应的port", podName);
}
}
private void doWork() {
AtomicBoolean hasDel = new AtomicBoolean(false);
// TODO 不需要 synchronized
private synchronized void delPod(String podName) throws Exception {
// 将本定时任务从deleteTimeMap中去除
deleteTimeMap.remove(podName);
// 根据podName来删除pod
Boolean r = k8sService.deletePod(podName);
logger.info("定时任务: 删除pod {}结果: {}", podName, r);
if (Boolean.TRUE.equals(r)) {
delService(podName);
delService(podName + "-22"); // 特殊处理-22的服务
}
// 一个pod被删除则执行一个正在等待的任务
GameService gameService = (GameService) BeanFactory.getObejct("GameService");
gameService.executeWaitingTask();
}
while (true) {
hasDel.set(false);
deleteTimeMap.forEach((podName, delTime) -> {
if (delTime < System.currentTimeMillis()) {
hasDel.set(true);
try {
delPod(podName);
} catch (Exception e) {
logger.error("delPod", e);
}
}
});
try {
if(!hasDel.get()) {Thread.sleep(1000);} //没任务休眠2秒
} catch (Exception e) {
}
}
}
private synchronized void delService(String podName, JSONObject result){
// 若存在端口映射service则一并删除
JSONObject svc = ShellUtil.executeAndGetExitStatus("kubectl get service " + podName);
if (result.getInteger("exitStatus") == 0 && svc.getInteger("exitStatus") == 0) {
logger.info("定时任务: 删除pod对应的service: {}", podName);
// 根据podName删除service
JSONObject out = ShellUtil.executeAndGetExitStatus("kubectl delete service " + podName + " --now");
// 移除tpi-port键值对
JedisUtil.hdel("port", podName);
JedisUtil.hdel("port1", podName);
logger.info("定时任务删除service结果{}", out.getString("out"));
}
}
private synchronized void delPod(String podName) throws Exception {
// 根据podName来删除pod
JSONObject result = ShellUtil.executeAndGetExitStatus("kubectl delete pod " + podName + " --now");
logger.info("定时任务: 删除pod-{}结果: {}", podName, result.getString("out"));
delService(podName, result);
delService(podName+"-22", result); //特殊处理-22的服务
// 将本定时任务从deleteTimeMap中去除
deleteTimeMap.remove(podName);
// 一个pod被删除则执行一个正在等待的任务
GameService gameService = (GameService) BeanFactory.getObejct("GameService");
gameService.executeWaitingTask();
}
/**
* 取消删除
*/
public synchronized void cancelDel(String podName) {
if (deleteTimeMap.containsKey(podName)) {
deleteTimeMap.remove(podName);
logger.info("取消定时删除podName: {}", podName);
}
}
}
/**
* 取消删除
*/
// TODO 不需要 synchronized
public synchronized void cancelDel(String podName) {
if (deleteTimeMap.containsKey(podName)) {
deleteTimeMap.remove(podName);
logger.info("取消定时删除podName: {}", podName);
}
}
}

View File

@ -0,0 +1,36 @@
package com.educoder.bridge.game.service;
import java.io.InputStream;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;
@Service
public class ResourceFileService {
private final ConcurrentHashMap<String, String> cacheMap = new ConcurrentHashMap<>();
public String getResourceFileContent(String name) {
String content = cacheMap.get(name);
if (content == null) {
content = this.readResourceFileContent(name);
cacheMap.put(name, content);
}
return content;
}
private String readResourceFileContent(String name) {
InputStream in = null;
try {
in = this.getClass().getClassLoader().getResourceAsStream(name);
String c = IOUtils.toString(in, Charsets.toCharset("UTF-8"));
return c;
} catch (Exception e) {
throw new RuntimeException("读取资源文件" + name + "失败", e);
} finally {
IOUtils.closeQuietly(in);
}
}
}

View File

@ -0,0 +1,120 @@
package com.educoder.bridge.game.service;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.educoder.bridge.game.model.WatchObject;
import io.fabric8.kubernetes.client.dsl.ExecWatch;
/**
* shell 执行时间管理
*/
@Service
public class ShellExecManageService {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final ConcurrentHashMap<Long, ExecTime> execTimeMap = new ConcurrentHashMap<>();
private final AtomicLong key = new AtomicLong(1);
private static class ExecTime {
private WatchObject wo;
private Long overtime;
private String podName;
public ExecTime(WatchObject wo, Long overtime, String podName) {
super();
this.wo = wo;
this.overtime = overtime;
this.podName = podName;
}
}
/**
* 加入执行时间
*
* @param execWatch
* @param delayTime
* 单位秒
*/
public Long putExecTime(WatchObject wo, long delayTime, String podName) {
long overtime = System.currentTimeMillis() + delayTime * 1000;
ExecTime execTime = new ExecTime(wo, overtime, podName);
Long k = key.incrementAndGet();
execTimeMap.put(k, execTime);
return k;
}
@PostConstruct
public void init() {
new Thread(() -> {
this.doWork();
}).start();
}
private void doWork() {
AtomicBoolean hasDel = new AtomicBoolean(false);
while (true) {
hasDel.set(false);
execTimeMap.forEach((execKey, execTime) -> {
if (execTime.overtime < System.currentTimeMillis()) {
hasDel.set(true);
try {
overtime(execKey, execTime);
} catch (Exception e) {
logger.error("pod [" + execTime.podName + "] 评测超时,关闭连接发生异常", e);
}
}
});
if (!hasDel.get()) {
try {
Thread.sleep(1000);
} catch (Exception e) {
// ignore quietly
}
}
}
}
/**
* 超时处理
*
* @param execKey
* @param execTime
* @throws Exception
*/
private void overtime(Long execKey, ExecTime execTime) throws Exception {
// KubernetesService.close(execTime.podName,
// execTime.wo.getWatch(),
// execTime.wo.getIn(),
// execTime.wo.getPis(),
// execTime.wo.getPos());
execTimeMap.remove(execKey);
logger.info("pod [{}] 评测超时,关闭连接", execTime.podName);
}
/**
* 已经完成删除执行时间
*/
public void removeExecTime(Long execKey) {
execTimeMap.remove(execKey);
}
}

View File

@ -1,24 +1,89 @@
package com.educoder.bridge.game.service;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.common.utils.PortUtil;
import com.educoder.bridge.common.utils.TimeHelper;
import com.educoder.bridge.webssh.model.Webssh;
import io.fabric8.kubernetes.api.model.Pod;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.educoder.bridge.common.utils.JedisUtil;
import java.util.HashMap;
import java.util.Map;
/**
* Created by zzx on 17/12/29.
*/
@Service("VncService")
public class VncService {
private Logger logger = LoggerFactory.getLogger(VncService.class);
@Autowired
private K8sService k8sService;
public void getvnc(String tpiID, String containers) {
@Autowired
private AppConfig appConfig;
@Autowired
private PodManagerService podManagerService;
/**
* 创建VNC连接需要的pod和svc
* @param tpiID
* @param containers
*/
public void getVnc(String tpiID, String containers) {
logger.debug("tpiID: {}, podType: {}", tpiID, "vnc");
String podName = "vnc-" + tpiID;
// 查看pod是否已经存在
Pod pod = k8sService.getPod(podName);
boolean existPod = false;
if(pod != null) {
String phase = pod.getStatus().getPhase();
if ("Running".equals(phase)) {
existPod = true;
} else {
k8sService.deletePod(podName);
logger.info("获取vnc连接信息delete 处于{}状态的 pod {}", phase, podName);
}
}
// 创建pod(type直接为vnc)
k8sService.createPod(podName, tpiID, "vnc", containers);
if (!existPod) {
k8sService.createPod(podName, tpiID, "vnc", containers, null);
}
// 创建svc
int vncPort = Integer.parseInt(JedisUtil.hget("port", podName));
k8sService.createService(podName, tpiID, 8080, vncPort);
boolean existService = k8sService.svcExist(podName);
if (!existService) {
int vncPort = Integer.parseInt(JedisUtil.hget("port-vnc", podName));
k8sService.createService(podName, tpiID, appConfig.getVncPort(), vncPort);
}
}
}
/**
* 直接删除
*
* @param tpiID
* @throws Exception
*/
public void deleteNow(String tpiID) throws Exception {
logger.info("主动不经过定时任务即时删除pod, tpiID: {}", tpiID);
String podName = getPodNameFromTpiId(tpiID);
if (StringUtils.isEmpty(podName)) {
return;
}
// 删除pod及svc
podManagerService.deletePodAfterTime(podName, 0);
// 移除占用的端口
JedisUtil.hdel("port-vnc", podName);
}
/**
* 通过tpiID获取podName
*
* @param tpiID
* @return
*/
private String getPodNameFromTpiId(String tpiID) {
Map<String, String> inLabels = new HashMap<>();
inLabels.put("tpiID", tpiID);
inLabels.put("type", "vnc");
Map<String, String> notInLabels = new HashMap<>();
Pod pod = k8sService.getK8sPod(inLabels, notInLabels);
return pod == null ? null : pod.getMetadata().getName();
}
}

View File

@ -0,0 +1,24 @@
package com.educoder.bridge.game.thread;
import com.alibaba.fastjson.JSONObject;
/**
* 善后异常评测线程出错善后处理发生的异常
*
* @author mumu
*
*/
@SuppressWarnings("serial")
public class AftermathException extends RuntimeException {
JSONObject buildParams = null;
public AftermathException(String message, Throwable cause, JSONObject buildParams) {
super(message, cause);
this.buildParams = buildParams;
}
public JSONObject getBuildParams() {
return buildParams;
}
}

View File

@ -0,0 +1,51 @@
package com.educoder.bridge.game.thread;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.utils.BeanFactory;
import com.educoder.bridge.common.utils.GameHelper;
import com.educoder.bridge.game.service.GameService;
public class BridgeThreadPoolExecutor extends ThreadPoolExecutor {
private Logger logger = LoggerFactory.getLogger(getClass());
public BridgeThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
if (t == null) {
return;
}
JSONObject buildParams = null;
try {
BuildThread task = (BuildThread) r;
buildParams = task.getBuildParams();
String tpiID = buildParams.getString("tpiID");
logger.error("评测线程" + tpiID + "出错", t);
String testCases = buildParams.getString("testCases");
// 回传错误信息到前台
GameService gameService = BeanFactory.getObejct(GameService.class);
gameService.encapsulateBuildResult(
GameHelper.getUnknowErrorResult(JSONObject.parseObject(testCases).size()), buildParams, testCases);
} catch (Throwable e) {
throw new AftermathException("评测线程出错,善后处理发生异常", e, buildParams);
}
}
}

View File

@ -0,0 +1,112 @@
package com.educoder.bridge.game.thread;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.*;
import org.slf4j.MDC;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ReflectionUtils;
import com.educoder.bridge.common.utils.BeanFactory;
import com.educoder.bridge.game.exception.UncaughtBridgeExceptionHandler;
@SuppressWarnings("serial")
public class BridgeThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
private int queueCapacity = Integer.MAX_VALUE;
private TaskDecorator taskDecorator;
private boolean allowCoreThreadTimeOut = false;
/**
* 所有线程都会委托给这个execute方法在这个方法中我们把父线程的MDC内容赋值给子线程
* https://logback.qos.ch/manual/mdc.html#managedThreads
*
* @param runnable
*/
@Override
public void execute(Runnable runnable) {
// 获取父线程MDC中的内容必须在run方法之前否则等异步线程执行的时候有可能MDC里面的值已经被清空了这个时候就会返回null
Map<String, String> context = MDC.getCopyOfContextMap();
super.execute(() -> run(runnable, context));
}
/**
* 子线程委托的执行方法
*
* @param runnable {@link Runnable}
* @param context 父线程MDC内容
*/
private void run(Runnable runnable, Map<String, String> context) {
// 将父线程的MDC内容传给子线程
MDC.setContextMap(context);
try {
// 执行异步操作
runnable.run();
} finally {
// 清空MDC内容
MDC.clear();
}
}
@Override
public Thread newThread(Runnable runnable) {
Thread t = super.newThread(runnable);
UncaughtBridgeExceptionHandler eh = BeanFactory.getObejct(UncaughtBridgeExceptionHandler.class);
t.setUncaughtExceptionHandler(eh);
return t;
}
@Override
protected ExecutorService initializeExecutor(ThreadFactory threadFactory,
RejectedExecutionHandler rejectedExecutionHandler) {
BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
ThreadPoolExecutor executor;
if (this.taskDecorator != null) {
// 使用 BridgeThreadPoolExecutor 执行 afterExecute 处理异常情况
executor = new BridgeThreadPoolExecutor(super.getCorePoolSize(), super.getMaxPoolSize(),
super.getKeepAliveSeconds(), TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler) {
@Override
public void execute(Runnable command) {
super.execute(taskDecorator.decorate(command));
}
};
} else {
// 使用 BridgeThreadPoolExecutor 执行 afterExecute 处理异常情况
executor = new BridgeThreadPoolExecutor(super.getCorePoolSize(), super.getMaxPoolSize(),
super.getKeepAliveSeconds(), TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler);
}
if (this.allowCoreThreadTimeOut) {
executor.allowCoreThreadTimeOut(true);
}
Field field = ReflectionUtils.findField(ThreadPoolTaskExecutor.class, "threadPoolExecutor",
ThreadPoolExecutor.class);
field.setAccessible(true);
ReflectionUtils.setField(field, this, executor);
return executor;
}
public void setQueueCapacity(int queueCapacity) {
super.setQueueCapacity(queueCapacity);
this.queueCapacity = queueCapacity;
}
public void setTaskDecorator(TaskDecorator taskDecorator) {
super.setTaskDecorator(taskDecorator);
this.taskDecorator = taskDecorator;
}
public void setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
super.setAllowCoreThreadTimeOut(allowCoreThreadTimeOut);
this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
}
}

View File

@ -1,22 +1,5 @@
package com.educoder.bridge.game.thread;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.common.utils.GameHelper;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.game.exception.GameException;
import com.educoder.bridge.game.exception.UncaughtBridgeExceptionHandler;
import com.educoder.bridge.game.service.GameService;
import com.educoder.bridge.game.service.K8sService;
import com.educoder.bridge.game.service.KubernetesService;
import io.fabric8.kubernetes.api.model.Pod;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import java.io.File;
import java.time.Duration;
import java.time.Instant;
@ -27,6 +10,29 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.constant.BuildResultCsts;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.common.utils.GameHelper;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.game.model.PodCreateStrategy;
import com.educoder.bridge.game.model.PodRef;
import com.educoder.bridge.game.service.GameService;
import com.educoder.bridge.game.service.K8sService;
import com.educoder.bridge.game.service.KubernetesService;
import com.educoder.bridge.k8s.service.BridgePodService;
import io.fabric8.kubernetes.api.model.Pod;
/**
* 评测线程
*
@ -37,6 +43,7 @@ import java.util.concurrent.Future;
@Service("BuildThread")
@Scope("prototype")
public class BuildThread extends Thread {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private GameService gameService;
@Autowired
@ -45,11 +52,12 @@ public class BuildThread extends Thread {
private AppConfig appConfig;
@Autowired
private K8sService k8sService;
@Autowired
private BridgePodService bridgePodService;
private JSONObject buildParams;
public BuildThread() {
this.setUncaughtExceptionHandler(new UncaughtBridgeExceptionHandler(buildParams));
}
public BuildThread(JSONObject buildParams) {
@ -61,6 +69,10 @@ public class BuildThread extends Thread {
this.buildParams = buildParams;
}
public JSONObject getBuildParams() {
return buildParams;
}
@Override
public void run() {
String tpiID = buildParams.getString("tpiID");
@ -69,80 +81,122 @@ public class BuildThread extends Thread {
Map<String, String> podInLabels = new HashMap<>(1);
Map<String, String> podNotInLabels = new HashMap<>(1);
podInLabels.put("tpiID", tpiID);
podNotInLabels.put("type", "webssh");
podInLabels.put("type", "evaluate,evassh");
String type = buildParams.getInteger("podType") != 2 ? "evaluate" : "evassh";
String testCases = buildParams.getString("testCases");
String out = GameHelper.getTextMsgResult("服务启动中...");
gameService.encapsulateStepByStepResult(out, buildParams, testCases);
ExecutorService executor = Executors.newFixedThreadPool(2);
// 传递MDC的内容
final Map<String, String> mdc = MDC.getCopyOfContextMap();
// git pull
Future<Object> pull = executor.submit(Executors.callable(() -> {
Future<Boolean> pull = executor.submit(() -> {
try {
MDC.setContextMap(mdc);
Instant pullStartInstant = Instant.now();
gameService.gitPull(tpiWorkspace, buildParams.getString("tpiGitURL"), buildParams.getInteger("contentModified"));
gameService.gitPull(tpiWorkspace, buildParams.getString("tpiGitURL"),
buildParams.getInteger("contentModified"));
double pullCost = (double) Duration.between(pullStartInstant, Instant.now()).toMillis() / 1000;
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "pull", String.format("%.3f", pullCost));
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "pull",
String.format("%.3f", pullCost));
return true;
} catch (Exception e) {
e.printStackTrace();
logger.error("下载实训" + tpiID + "代码失败", e);
return false;
}
}));
});
// 创建pod
final PodRef podRef = new PodRef();
Instant podStartInstant = Instant.now();
Future<Object> createPod = executor.submit(Executors.callable(() -> {
String podName = k8sService.getPod(podInLabels, podNotInLabels);
if (StringUtils.isEmpty(podName)) {
Pod pod = k8sService.createPod(type + "-" + tpiID, tpiID, type, buildParams.getString("containers"));
podName = pod.getMetadata().getName();
}
MDC.setContextMap(mdc);
// 设立(重设)对应pod的定时删除任务这个时间必须大于${timeLimit}确保脚本执行期间pod不会中途死 单位
int timeLimit = buildParams.getInteger("timeLimit");
gameService.reTiming(podName, timeLimit + 60);
gameService.reTiming(type + "-" + tpiID, timeLimit + 60);
Pod pod = k8sService.getK8sRunningPod(podInLabels, podNotInLabels);
String podName = pod == null ? null : pod.getMetadata().getName();
if (StringUtils.isEmpty(podName)) {
PodCreateStrategy podCreateStrategy = new PodCreateStrategy().setTimeLimit(timeLimit);
pod = k8sService.createPod(type + "-" + tpiID, tpiID, type, buildParams.getString("containers"),
podCreateStrategy);
}
if (pod != null) {
podRef.setPod(pod);
podName = pod.getMetadata().getName();
// 设立(重设)对应pod的定时删除任务这个时间必须大于${timeLimit}确保脚本执行期间pod不会中途死 单位
gameService.reTiming(podName, timeLimit + 60);
}
}));
boolean pullResult = false;
try {
pull.get();
createPod.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
pullResult = pull.get();
} catch (InterruptedException e) {// 不应该发生
logger.error("等待下载实训" + tpiID + "代码被中断", e);
} catch (ExecutionException e) {// 不应该发生
logger.error("等待下载实训" + tpiID + "代码出错", e);
} finally {
executor.shutdown();
try {
createPod.get();
} catch (InterruptedException e) {// 不应该发生
logger.error("创建实训pod " + tpiID + "代码被中断", e);
} catch (ExecutionException e) {
logger.error("创建实训pod " + tpiID + "失败", e);
} finally {
executor.shutdown();
}
}
JSONArray cases = JSONArray.parseArray(testCases);
if (!pullResult) {
String msg = GameHelper.getResult("系统繁忙,请稍后重试", cases.size(),
BuildResultCsts.DOWNLOAD_STATUS_FAIL, BuildResultCsts.CREATE_POD_STATUS_FAIL);
gameService.encapsulateBuildResult(msg, buildParams, testCases);
return;
} else {
if (podRef.getPod() == null) {
String msg = GameHelper.getResult("系统繁忙,请稍后重试", cases.size(),
BuildResultCsts.DOWNLOAD_STATUS_SUCCESS, BuildResultCsts.CREATE_POD_STATUS_FAIL);
gameService.encapsulateBuildResult(msg, buildParams, testCases);
return;
}
}
// 通过标签获取pod名
String podName = k8sService.getPod(podInLabels, podNotInLabels);
String podName = podRef.getPod().getMetadata().getName();
// 按需创建端口映射svc
if (buildParams.getInteger("needPortMapping") != 0 && !kubernetesService.svcExist(podName)) {
k8sService.createService(podName, tpiID, buildParams.getInteger("needPortMapping"),
Integer.parseInt(JedisUtil.hget("port", podName)));
}
out = GameHelper.getTextMsgResult("服务启动完成");
gameService.encapsulateStepByStepResult(out, buildParams, testCases);
// 记录创建pod耗时
double createPodAndSvcCost = (double) Duration.between(podStartInstant, Instant.now()).toMillis() / 1000;
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "createPod", String.format("%.3f", createPodAndSvcCost));
JSONObject timeCost = GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "createPod",
String.format("%.3f", createPodAndSvcCost));
//bridgePodService.updateBridgePod(buildParams, timeCost, podRef.getPod());
// 在pod中执行评测脚本
Instant executeStartInstant = Instant.now();
Integer executeTimeLimit = buildParams.getInteger("executeTime") == null ? buildParams.getInteger("timeLimit") : buildParams.getInteger("executeTime");
String out = kubernetesService.executeShellInPod(podName, buildParams.getInteger("needPortMapping"),
Integer executeTimeLimit = buildParams.getInteger("executeTime") == null ? buildParams.getInteger("timeLimit")
: buildParams.getInteger("executeTime");
kubernetesService.executeShellInPod(buildParams, podRef.getPod(), buildParams.getInteger("needPortMapping"),
executeTimeLimit, buildParams.getInteger("isPublished"), buildParams.getInteger("instanceChallenge"),
buildParams.getString("testCases"));
double executeCost = (double) Duration.between(executeStartInstant, Instant.now()).toMillis() / 1000;
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "execute", String.format("%.3f", executeCost));
// 封装结果并回传给前台
String status = gameService.encapsulateBuildResult(out, buildParams, buildParams.getString("testCases"));
// 如果成功过关删除评测pod并执行等待任务
if ("0".equals(status)) {
// service不存在且pod不处于任务运行期才删除pod
if (!kubernetesService.svcExist(podName)
&& !kubernetesService.svcExist(podName+"-22") //22的特殊处理
&& !JedisUtil.zhas("taskNum", podName)) {
kubernetesService.deletePod(podName);
}
gameService.executeWaitingTask();
}
}
@Override
public String toString() {
return "BuildThread{" + buildParams.toJSONString() + '}';
}
}

View File

@ -18,9 +18,9 @@ import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.common.utils.BeanFactory;
import com.educoder.bridge.common.utils.GameHelper;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.game.exception.GameException;
import com.educoder.bridge.game.exception.UncaughtBridgeExceptionHandler;
import com.educoder.bridge.game.service.GameService;
import com.educoder.bridge.game.service.K8sService;
@ -59,7 +59,8 @@ public class BuildThreadPersistence extends Thread {
private final static Logger logger = LoggerFactory.getLogger(BuildThreadPersistence.class);
public BuildThreadPersistence() {
this.setUncaughtExceptionHandler(new UncaughtBridgeExceptionHandler(buildParams));
UncaughtBridgeExceptionHandler eh = BeanFactory.getObejct(UncaughtBridgeExceptionHandler.class);
this.setUncaughtExceptionHandler(eh);
}
public BuildThreadPersistence(JSONObject buildParams) {
@ -85,7 +86,7 @@ public class BuildThreadPersistence extends Thread {
Map<String, String> podNotInLabels = new HashMap<>(1);
podNotInLabels.put("type", "webssh");
String type = buildParams.getInteger("podType") != 2 ? "evaluate" : "evassh";
podInLabels.put("name", type + "-" + persistenceName );
podInLabels.put("name", type + "-" + persistenceName);
ExecutorService executor = Executors.newFixedThreadPool(2);
// git pull
Future<Object> pull = executor.submit(Executors.callable(() -> {
@ -95,9 +96,10 @@ public class BuildThreadPersistence extends Thread {
buildParams.getInteger("contentModified"));
double pullCost = (double) Duration.between(pullStartInstant, Instant.now()).toMillis() / 1000;
logger.debug("pull耗时{}, tpiID{}", pullCost, tpiID);
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "pull", String.format("%.3f", pullCost));
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "pull",
String.format("%.3f", pullCost));
} catch (Exception e) {
e.printStackTrace();
logger.error(e.getMessage(), e);
}
}));
@ -109,7 +111,7 @@ public class BuildThreadPersistence extends Thread {
{
String pod = k8sService.getPod(podInLabels, podNotInLabels);
if (pod.equals("")) {
Pod createPod = k8sService.createPersistencePod(type + "-" + persistenceName , tpiID, type,
Pod createPod = k8sService.createPersistencePod(type + "-" + persistenceName, tpiID, type,
buildParams.getString("containers"));
// 返回容器pod名称
return createPod.getMetadata().getName();
@ -132,12 +134,13 @@ public class BuildThreadPersistence extends Thread {
// 记录创建pod耗时
double createPodAndSvcCost = (double) Duration.between(podStartInstant, Instant.now()).toMillis() / 1000;
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "createPod", String.format("%.3f", createPodAndSvcCost));
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "createPod",
String.format("%.3f", createPodAndSvcCost));
// 设立(重设)对应pod的定时删除任务这个时间必须大于${timeLimit}确保脚本执行期间pod不会中途死 单位
int timeLimit = buildParams.getInteger("timeLimit");
gameService.reTiming(podName, timeLimit + 1800);
logger.info("当前容器同步返回失败tipId:{} , 总消耗时间{}", buildParams.getString("tpiID"),
System.currentTimeMillis() - currentTimeMillis);
// 在pod中执行评测脚本
@ -147,7 +150,8 @@ public class BuildThreadPersistence extends Thread {
buildParams.getInteger("instanceChallenge"), buildParams.getString("testCases"));
double executeCost = (double) Duration.between(executeStartInstant, Instant.now()).toMillis() / 1000;
logger.debug("执行耗时{}, tpiID{}", executeCost, tpiID);
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "execute", String.format("%.3f", executeCost));
GameHelper.setTimeCostInJedis("timeCost:" + tpiID + ":" + buildID, "execute",
String.format("%.3f", executeCost));
//
// 封装结果并回传给前台
Map<String, String> persistenceEncapsulateBuildResult = gameService.persistenceEncapsulateBuildResult(out,
@ -163,7 +167,6 @@ public class BuildThreadPersistence extends Thread {
} catch (Exception e) {
logger.error("评测线程抛出异常:", e);
e.printStackTrace();
}
}

View File

@ -0,0 +1,7 @@
package com.educoder.bridge.k8s.constant;
public interface BridgePodCsts {
String STATUS_BEGIN = "0";
String STATUS_END = "1";
}

View File

@ -0,0 +1,77 @@
package com.educoder.bridge.k8s.controller;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.educoder.bridge.common.constant.ApiResultCodeCsts;
import com.educoder.bridge.common.model.ApiResult;
import com.educoder.bridge.game.service.K8sService;
import com.educoder.bridge.k8s.model.NodeQueryParam;
import io.fabric8.kubernetes.api.model.Node;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* Node相关的接口
*
* @author jiangzhongxiang
*/
@Api(value = "Node", hidden = true)
@RestController
@RequestMapping("/nodes")
public class NodeController {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private K8sService k8sService;
/**
* 获取Node列表
*/
@RequestMapping(path = "/list", method = RequestMethod.POST)
@ApiOperation(value = "获取Node列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<List<Node>> getNodes(@RequestBody(required = false) NodeQueryParam param) throws Exception {
logger.info("获取Node列表");
ApiResult<List<Node>> result = new ApiResult<>();
List<Node> nodeList = k8sService.getNodes(param);
result.setData(nodeList);
return result;
}
/**
* 获取Node列表
*/
@RequestMapping(path = "/{name}", method = RequestMethod.GET)
@ApiOperation(value = "获取Node详情", httpMethod = "GET", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<Node> getNode(@PathVariable("name") String name) throws Exception {
logger.info("获取Node {}详情", name);
ApiResult<Node> result = new ApiResult<>();
NodeQueryParam param = new NodeQueryParam();
param.setName(name);
List<Node> nodeList = k8sService.getNodes(param);
if(nodeList != null && nodeList.size() > 0) {
result.setData(nodeList.get(0));
} else {
result.setCode(ApiResultCodeCsts.FAIL);
}
return result;
}
}

View File

@ -0,0 +1,79 @@
package com.educoder.bridge.k8s.controller;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.educoder.bridge.common.constant.ApiResultCodeCsts;
import com.educoder.bridge.common.model.ApiResult;
import com.educoder.bridge.common.model.BridgePage;
import com.educoder.bridge.game.service.K8sService;
import com.educoder.bridge.k8s.model.BridgePod;
import com.educoder.bridge.k8s.model.PodQueryParam;
import com.educoder.bridge.k8s.service.BridgePodService;
import com.github.pagehelper.Page;
import io.fabric8.kubernetes.api.model.Pod;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* Pod相关的接口
*
* @author jiangzhongxiang
*/
@Api(value = "Pod", hidden = true)
@RestController
@RequestMapping("/pods")
public class PodController {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private K8sService k8sService;
@Autowired
private BridgePodService bridgePodService;
/**
* 获取Node列表
*/
@RequestMapping(path = "/list", method = RequestMethod.POST)
@ApiOperation(value = "获取Pod列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<BridgePage<BridgePod>> getPods(@RequestBody(required = false) PodQueryParam param)
throws Exception {
logger.info("获取Pod列表");
ApiResult<BridgePage<BridgePod>> result = new ApiResult<>();
List<BridgePod> list = bridgePodService.getBridgePods(param);
BridgePage<BridgePod> page = new BridgePage<>((Page<BridgePod>) list);
result.setData(page);
return result;
}
/**
* 获取Pod详情
*/
@RequestMapping(path = "/{name}", method = RequestMethod.GET)
@ApiOperation(value = "获取Pod详情", httpMethod = "GET", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<Pod> getPod(@PathVariable("name") String name) throws Exception {
logger.info("获取Pod {} 详情", name);
ApiResult<Pod> result = new ApiResult<>();
Pod pod = k8sService.getPod(name);
if (pod != null) {
result.setData(pod);
} else {
result.setCode(ApiResultCodeCsts.FAIL);
}
return result;
}
}

View File

@ -0,0 +1,22 @@
package com.educoder.bridge.k8s.dao;
import java.util.List;
import com.educoder.bridge.k8s.model.BridgePod;
import com.educoder.bridge.k8s.model.PodQueryParam;
public interface BridgePodMapper {
int deleteByPrimaryKey(Long id);
int insert(BridgePod record);
int insertSelective(BridgePod record);
BridgePod selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(BridgePod record);
int updateByPrimaryKey(BridgePod record);
List<BridgePod> selectBridgePod(PodQueryParam param);
}

View File

@ -0,0 +1,195 @@
package com.educoder.bridge.k8s.model;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "bridge pod 信息", description = "bridge pod 信息")
public class BridgePod {
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "pod name")
private String name;
@ApiModelProperty(value = "实训id")
private String tpiID;
@ApiModelProperty(value = "k8s pod创建时间")
private LocalDateTime k8sCreateTime;
@ApiModelProperty(value = "删除时间")
private LocalDateTime deleteTime;
@ApiModelProperty(value = "测评标识")
private String secKey;
@ApiModelProperty(value = "评测请求到达时间")
private LocalDateTime requestTime;
@ApiModelProperty(value = "下载代码耗时")
private Double pull;
@ApiModelProperty(value = "创建pod耗时")
private Double createPod;
@ApiModelProperty(value = "执行评测脚本耗时")
private Double execute;
@ApiModelProperty(value = "评测总耗时")
private Double evaluateAllTime;
@ApiModelProperty(value = "pod所在node名称")
private String nodeName;
@ApiModelProperty(value = "pod所在node ip")
private String nodeIp;
@ApiModelProperty(value = "下载代码结果0,失败; 1,成功.")
private String downloadStatus;
@ApiModelProperty(value = "创建pod结果0,失败; 1,成功.")
private String createPodStatus;
@ApiModelProperty(value = "编译结果0,失败; 1,成功.")
private String compileStatus;
@ApiModelProperty(value = "运行结果:-1,失败; 0,成功.")
private String runStatus;
@ApiModelProperty(value = "评测状态0,开始; 1,评测结束.")
private String status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTpiID() {
return tpiID;
}
public void setTpiID(String tpiID) {
this.tpiID = tpiID;
}
public LocalDateTime getK8sCreateTime() {
return k8sCreateTime;
}
public void setK8sCreateTime(LocalDateTime k8sCreateTime) {
this.k8sCreateTime = k8sCreateTime;
}
public LocalDateTime getDeleteTime() {
return deleteTime;
}
public void setDeleteTime(LocalDateTime deleteTime) {
this.deleteTime = deleteTime;
}
public String getSecKey() {
return secKey;
}
public void setSecKey(String secKey) {
this.secKey = secKey;
}
public LocalDateTime getRequestTime() {
return requestTime;
}
public void setRequestTime(LocalDateTime requestTime) {
this.requestTime = requestTime;
}
public Double getPull() {
return pull;
}
public void setPull(Double pull) {
this.pull = pull;
}
public Double getCreatePod() {
return createPod;
}
public void setCreatePod(Double createPod) {
this.createPod = createPod;
}
public Double getExecute() {
return execute;
}
public void setExecute(Double execute) {
this.execute = execute;
}
public Double getEvaluateAllTime() {
return evaluateAllTime;
}
public void setEvaluateAllTime(Double evaluateAllTime) {
this.evaluateAllTime = evaluateAllTime;
}
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
public String getNodeIp() {
return nodeIp;
}
public void setNodeIp(String nodeIp) {
this.nodeIp = nodeIp;
}
public String getDownloadStatus() {
return downloadStatus;
}
public void setDownloadStatus(String downloadStatus) {
this.downloadStatus = downloadStatus;
}
public String getCreatePodStatus() {
return createPodStatus;
}
public void setCreatePodStatus(String createPodStatus) {
this.createPodStatus = createPodStatus;
}
public String getCompileStatus() {
return compileStatus;
}
public void setCompileStatus(String compileStatus) {
this.compileStatus = compileStatus;
}
public String getRunStatus() {
return runStatus;
}
public void setRunStatus(String runStatus) {
this.runStatus = runStatus;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@ -0,0 +1,26 @@
package com.educoder.bridge.k8s.model;
import java.util.Map;
public class NodeQueryParam {
private String name;
private Map<String, String> labels;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, String> getLabels() {
return labels;
}
public void setLabels(Map<String, String> labels) {
this.labels = labels;
}
}

View File

@ -0,0 +1,196 @@
package com.educoder.bridge.k8s.model;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "pod查询参数", description = "pod查询参数")
public class PodQueryParam {
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "pod name")
private String name;
@ApiModelProperty(value = "实训id")
private String tpiID;
@ApiModelProperty(value = "请求时间")
private LocalDateTime requestTime;
@ApiModelProperty(value = "最小请求时间")
private LocalDateTime minRequestTime;
@ApiModelProperty(value = "最大请求时间")
private LocalDateTime maxRequestTime;
@ApiModelProperty(value = "测评标识")
private String secKey;
@ApiModelProperty(value = "pod所在node名称")
private String nodeName;
@ApiModelProperty(value = "pod所在node ip")
private String nodeIp;
@ApiModelProperty(value = "下载代码结果0,失败; 1,成功.")
private String downloadStatus;
@ApiModelProperty(value = "创建pod结果0,失败; 1,成功.")
private String createPodStatus;
@ApiModelProperty(value = "编译结果0,失败; 1,成功.")
private String compileStatus;
@ApiModelProperty(value = "运行结果:-1,失败; 0,成功.")
private String runStatus;
@ApiModelProperty(value = "评测状态0,开始; 1,评测结束.")
private String status;
@ApiModelProperty(value = "排序字段。默认按id降序")
private String sortField;
@ApiModelProperty(value = "排序字段方向asc或者desc。默认desc")
private String sortDirection;
@ApiModelProperty(value = "第几页从1开始")
private Integer pageNum = 1;
@ApiModelProperty(value = "每页数量")
private Integer pageSize = 10;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTpiID() {
return tpiID;
}
public void setTpiID(String tpiID) {
this.tpiID = tpiID;
}
public LocalDateTime getRequestTime() {
return requestTime;
}
public void setRequestTime(LocalDateTime requestTime) {
this.requestTime = requestTime;
}
public LocalDateTime getMinRequestTime() {
return minRequestTime;
}
public void setMinRequestTime(LocalDateTime minRequestTime) {
this.minRequestTime = minRequestTime;
}
public LocalDateTime getMaxRequestTime() {
return maxRequestTime;
}
public void setMaxRequestTime(LocalDateTime maxRequestTime) {
this.maxRequestTime = maxRequestTime;
}
public String getSecKey() {
return secKey;
}
public void setSecKey(String secKey) {
this.secKey = secKey;
}
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
public String getNodeIp() {
return nodeIp;
}
public void setNodeIp(String nodeIp) {
this.nodeIp = nodeIp;
}
public String getDownloadStatus() {
return downloadStatus;
}
public void setDownloadStatus(String downloadStatus) {
this.downloadStatus = downloadStatus;
}
public String getCreatePodStatus() {
return createPodStatus;
}
public void setCreatePodStatus(String createPodStatus) {
this.createPodStatus = createPodStatus;
}
public String getCompileStatus() {
return compileStatus;
}
public void setCompileStatus(String compileStatus) {
this.compileStatus = compileStatus;
}
public String getRunStatus() {
return runStatus;
}
public void setRunStatus(String runStatus) {
this.runStatus = runStatus;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getSortField() {
return sortField;
}
public void setSortField(String sortField) {
this.sortField = sortField;
}
public String getSortDirection() {
return sortDirection;
}
public void setSortDirection(String sortDirection) {
this.sortDirection = sortDirection;
}
public Integer getPageNum() {
return pageNum;
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
}

View File

@ -0,0 +1,121 @@
package com.educoder.bridge.k8s.service;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.utils.TimeHelper;
import com.educoder.bridge.game.model.BuildResult;
import com.educoder.bridge.k8s.constant.BridgePodCsts;
import com.educoder.bridge.k8s.dao.BridgePodMapper;
import com.educoder.bridge.k8s.model.BridgePod;
import com.educoder.bridge.k8s.model.PodQueryParam;
import com.github.pagehelper.PageHelper;
import io.fabric8.kubernetes.api.model.Pod;
@Service
public class BridgePodService {
@Autowired
private BridgePodMapper bridgePodMapper;
public List<BridgePod> getBridgePods(PodQueryParam param) {
PageHelper.startPage(param.getPageNum(), param.getPageSize());
return bridgePodMapper.selectBridgePod(param);
}
public void createBridgePod(BridgePod bridgePod) {
bridgePodMapper.insert(bridgePod);
}
public BridgePod createBridgePod(String name, String tpiID, LocalDateTime requestTime, String secKey) {
BridgePod bridgePod = new BridgePod();
bridgePod.setName(name);
bridgePod.setTpiID(tpiID);
bridgePod.setSecKey(secKey);
bridgePod.setRequestTime(requestTime);
bridgePod.setStatus(BridgePodCsts.STATUS_BEGIN);
bridgePodMapper.insert(bridgePod);
return bridgePod;
}
/**
* 更新下载代码时间创建pod时间pod信息
*
* @param buildParams
* @param timeCost
* @param pod
*/
public void updateBridgePod(JSONObject buildParams, JSONObject timeCost, Pod pod) {
BridgePod bridgePod = new BridgePod();
bridgePod.setId(buildParams.getLong("bridgePodId"));
String pull = timeCost.getString("pull");
Double takeTime = pull == null ? null : Double.parseDouble(pull);
bridgePod.setPull(takeTime);
String createPod = timeCost.getString("createPod");
takeTime = createPod == null ? null : Double.parseDouble(createPod);
bridgePod.setCreatePod(takeTime);
String createTime = pod.getMetadata().getCreationTimestamp();
if (createTime.endsWith("Z")) {
createTime = createTime.substring(0, createTime.length() - 1);
}
LocalDateTime time = LocalDateTime.parse(createTime);
bridgePod.setK8sCreateTime(time);
bridgePod.setNodeName(pod.getSpec().getNodeName());
bridgePod.setNodeIp(pod.getStatus().getHostIP());
bridgePodMapper.updateByPrimaryKeySelective(bridgePod);
}
public void updateExecuteTime(JSONObject buildParams, JSONObject timeCost, Pod pod, BuildResult result) {
BridgePod bridgePod = new BridgePod();
bridgePod.setId(buildParams.getLong("bridgePodId"));
// 下载代码和创建pod
String pull = timeCost.getString("pull");
Double takeTime = pull == null ? null : Double.parseDouble(pull);
bridgePod.setPull(takeTime);
String createPod = timeCost.getString("createPod");
takeTime = createPod == null ? null : Double.parseDouble(createPod);
bridgePod.setCreatePod(takeTime);
String createTime = pod.getMetadata().getCreationTimestamp();
if (createTime.endsWith("Z")) {
createTime = createTime.substring(0, createTime.length() - 1);
}
LocalDateTime time = LocalDateTime.parse(createTime);
bridgePod.setK8sCreateTime(time);
bridgePod.setNodeName(pod.getSpec().getNodeName());
bridgePod.setNodeIp(pod.getStatus().getHostIP());
// 评测数据
String execute = timeCost.getString("execute");
takeTime = execute == null ? null : Double.parseDouble(execute);
bridgePod.setExecute(takeTime);
takeTime = (double) (System.currentTimeMillis()
- TimeHelper.convertTimeToMillis(timeCost.getString("evaluateStartTime"))) / 1000;
bridgePod.setEvaluateAllTime(takeTime);
bridgePod.setDownloadStatus(result.getDownloadStatus());
bridgePod.setCreatePodStatus(result.getCreatePodStatus());
bridgePod.setCompileStatus(result.getCompileSuccess());
bridgePod.setRunStatus(result.getStatus());
bridgePod.setStatus(BridgePodCsts.STATUS_END);
bridgePodMapper.updateByPrimaryKeySelective(bridgePod);
}
}

View File

@ -0,0 +1,103 @@
package com.educoder.bridge.log.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.model.ApiResult;
import com.educoder.bridge.log.model.LogLevel;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import io.swagger.annotations.ApiOperation;
@RestController
@RequestMapping("/logs")
public class LogController {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* 修改项目日志输出级别
*
* @param allLevel
* 全局日志级别
* @param singleLevel
* 某个类日志级别
* @param singlePath
* 需要单独设置日志输出级别的类的全限定名log.SecondController
* @return
*/
@Deprecated
@RequestMapping(value = "levels/set", method = RequestMethod.PUT)
public String changeLevel(@RequestParam(required = false) String allLevel,
@RequestParam(required = false) String singleLevel, @RequestParam(required = false) String singlePath) {
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
if (!StringUtils.isEmpty(allLevel)) {
// 设置全局日志级别
ch.qos.logback.classic.Logger logger = loggerContext.getLogger("root");
logger.setLevel(Level.toLevel(allLevel));
}
if (!StringUtils.isEmpty(singleLevel)) {
// 设置某个类日志级别-可以实现定向日志级别调整
ch.qos.logback.classic.Logger vLogger = loggerContext.getLogger(singlePath);
if (vLogger != null) {
vLogger.setLevel(Level.toLevel(singleLevel));
}
}
testLogLevel();
JSONObject response = new JSONObject();
response.put("code", 0);
response.put("msg", "修改log level级别成功");
return "success";
}
@RequestMapping(value = "levels/{name}", method = RequestMethod.PUT)
@ApiOperation(value = "设置日志级别", httpMethod = "PUT", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<LogLevel> setLevel(@PathVariable("name") String name, @RequestParam("level") String level) {
ApiResult<LogLevel> result = new ApiResult<>();
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
ch.qos.logback.classic.Logger logger = loggerContext.getLogger(name);
logger.setLevel(Level.toLevel(level));
testLogLevel();
result.setMsg("设置日志级别成功");
return result;
}
@RequestMapping(path = "levels/{name}", method = RequestMethod.GET)
@ApiOperation(value = "获取 日志级别", httpMethod = "GET", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<LogLevel> getRootLevel(@PathVariable("name") String name) {
ApiResult<LogLevel> result = new ApiResult<>();
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
ch.qos.logback.classic.Logger logger = loggerContext.getLogger(name);
Level level = logger.getLevel();
LogLevel logLevel = new LogLevel();
logLevel.setLevel(level.toString());
result.setData(logLevel);
return result;
}
/**
* 此方法用于测试
*/
private void testLogLevel() {
logger.trace("test log level");
logger.debug("test log level");
logger.info("test log level");
logger.warn("test log level");
logger.error("test log level");
}
}

View File

@ -0,0 +1,30 @@
package com.educoder.bridge.log.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "日志级别", description = "日志级别")
public class LogLevel {
@ApiModelProperty(value = "root或者具体类名")
private String name;
@ApiModelProperty(value = "日志级别")
private String level;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
}

View File

@ -0,0 +1,77 @@
package com.educoder.bridge.user.controller;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.educoder.bridge.common.model.ApiResult;
import com.educoder.bridge.user.model.LoginInfo;
import com.educoder.bridge.user.model.User;
import com.educoder.bridge.user.service.UserService;
import com.educoder.bridge.user.util.JwtUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* 登录相关的接口
*
* @author jiangzhongxiang
*/
@Api(value = "用户登录", hidden = true)
@RestController
@RequestMapping("/users")
public class LoginController {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private UserService userService;
/**
* 登录
*/
@RequestMapping(path = "/login")
@ApiOperation(value = "登录", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<String> login(@RequestBody LoginInfo loginInfo) throws Exception {
logger.info("用户{}登录", loginInfo.getLoginName());
ApiResult<String> result = new ApiResult<>();
User user = userService.login(loginInfo);
long expireTime = System.currentTimeMillis() + 1000L * 60 * 30;
Date expireDatePoint = new Date(expireTime);
String token = JwtUtils.genToken(user, expireDatePoint);
result.setData(token);
result.setMsg("登录成功");
return result;
}
/**
* 退出
*/
@RequestMapping(path = "/logout")
@ApiOperation(value = "退出", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<?> logout(HttpServletRequest request) throws Exception {
HttpSession session = request.getSession(true);
User user = (User) session.getAttribute("user");
String name = user == null ? "" : user.getName();
logger.info("用户{}退出", name);
session.removeAttribute("user");
ApiResult<?> result = new ApiResult<>();
result.setMsg("退出成功");
return result;
}
}

View File

@ -0,0 +1,41 @@
package com.educoder.bridge.user.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.educoder.bridge.common.model.ApiResult;
import com.educoder.bridge.user.model.PasswordUpdateInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* 用户相关的接口
*
* @author jiangzhongxiang
*/
@Api(value = "用户", hidden = true)
@RestController
@RequestMapping("/users")
public class UserController {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* 登录
*/
@RequestMapping(path = "/passwords/update")
@ApiOperation(value = "修改密码", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ApiResult<?> updatePassword(@RequestBody PasswordUpdateInfo pui) throws Exception {
logger.info("用户{}修改密码", "xxx");
ApiResult<?> result = new ApiResult<>();
result.setMsg("修改成功");
return result;
}
}

View File

@ -0,0 +1,22 @@
package com.educoder.bridge.user.dao;
import java.util.List;
import java.util.Map;
import com.educoder.bridge.user.model.User;
public interface UserMapper {
int deleteByPrimaryKey(Long id);
int insert(User record);
int insertSelective(User record);
User selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(User record);
int updateByPrimaryKey(User record);
List<User> selectUser(Map<String,Object> param);
}

View File

@ -0,0 +1,43 @@
package com.educoder.bridge.user.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.educoder.bridge.game.exception.GameException;
import com.educoder.bridge.user.util.JwtUtils;
public class AuthorizationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
String token = req.getHeader("ACCESS_TOKEN");
if (StringUtils.isBlank(token)) {
// res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
throw new GameException(-2, "未授权"); // 改成直接返回不要抛异常
}
try {
JwtUtils.verifyToken(token);
} catch (Exception e) {
// res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
throw new GameException(-2, "未授权"); // 改成直接返回不要抛异常
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
}
}

View File

@ -0,0 +1,30 @@
package com.educoder.bridge.user.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "登录信息", description = "登录信息")
public class LoginInfo {
@ApiModelProperty(value = "登录名")
private String loginName;
@ApiModelProperty(value = "密码")
private String password;
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@ -0,0 +1,31 @@
package com.educoder.bridge.user.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "密码修改信息", description = "密码修改信息")
public class PasswordUpdateInfo {
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "新密码")
private String newPassword;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNewPassword() {
return newPassword;
}
public void setNewPassword(String newPassword) {
this.newPassword = newPassword;
}
}

View File

@ -0,0 +1,85 @@
package com.educoder.bridge.user.model;
import java.util.Date;
public class User {
private Long id;
private String name;
private String password;
private String email;
private String mobile;
private Date createTime;
private Date updateTime;
private String status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@ -0,0 +1,66 @@
package com.educoder.bridge.user.service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.crypto.hash.HashRequest;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.SimpleByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.educoder.bridge.game.exception.GameException;
import com.educoder.bridge.user.dao.UserMapper;
import com.educoder.bridge.user.model.LoginInfo;
import com.educoder.bridge.user.model.User;
@Service
public class UserService {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private UserMapper userMapper;
public User login(LoginInfo loginInfo) throws GameException {
// 查询用户
String name = loginInfo.getLoginName();
Map<String, Object> param = new HashMap<>();
param.put("name", name);
List<User> list = userMapper.selectUser(param);
User user = list.size() > 0 ? list.get(0) : null;
if (user == null) {
logger.error("不存在的用户{}请求登录 ", name);
throw new GameException(-2, "用户名或者密码错误:" + name);
}
// 用户密码
String password = user.getPassword();
int index = password.indexOf("$");
String salt = password.substring(0, index);
String realPassword = user.getPassword().substring(index + 1);
DefaultHashService hashService = new DefaultHashService();
hashService.setHashAlgorithmName("MD5");
hashService.setPrivateSalt(new SimpleByteSource("bridge_admin"));
hashService.setRandomNumberGenerator(new SecureRandomNumberGenerator());// 用于生成公盐默认就这个
hashService.setHashIterations(1000); // 生成Hash值的迭代次数
HashRequest request = new HashRequest.Builder().setSource(ByteSource.Util.bytes(loginInfo.getPassword()))
.setSalt(ByteSource.Util.bytes(Base64.decode(salt))).build();
Hash hash = hashService.computeHash(request);
boolean r = hash.toHex().equals(realPassword);
if (!r) {
logger.error("用户{}密码错误 ", name);
throw new GameException(-2, "用户名或者密码错误:" + name);
}
return user;
}
}

View File

@ -0,0 +1,74 @@
package com.educoder.bridge.user.util;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.educoder.bridge.user.model.User;
public class JwtUtils {
private static final String SECRET = "61bfbcf03829f424726e357fd0bb4095";
private static String ISSUER = "educoder_bridge";
/**
* 生成token
*
* @param claims
* @param expireDatePoint
* 过期时间点
* @return
*/
public static String genToken(User user, Date expireDatePoint) {
try {
// 使用HMAC256进行加密
Algorithm algorithm = Algorithm.HMAC256(SECRET);
// 创建jwt
JWTCreator.Builder builder = JWT.create().withIssuer(ISSUER). // 发行人
withExpiresAt(expireDatePoint); // 过期时间点
// 传入参数
builder.withClaim("name", user.getName());
// 签名加密
return builder.sign(algorithm);
} catch (IllegalArgumentException e) {
throw new RuntimeException("创建token失败", e);
}
}
/**
* 解密jwt
*
* @param token
* @return
* @throws RuntimeException
*/
public static Map<String, String> verifyToken(String token) throws RuntimeException {
Algorithm algorithm = null;
try {
// 使用HMAC256进行加密
algorithm = Algorithm.HMAC256(SECRET);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
}
// 解密
JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER).build();
DecodedJWT jwt = verifier.verify(token);
Map<String, Claim> map = jwt.getClaims();
Map<String, String> resultMap = new HashMap<>();
map.forEach((k, v) -> resultMap.put(k, v.asString()));
return resultMap;
}
}

View File

@ -1,17 +1,9 @@
package com.educoder.bridge.webssh.controller;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.controller.BaseController;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.webssh.model.Webssh;
import com.educoder.bridge.webssh.service.WebsshService;
import com.educoder.bridge.common.utils.Base64Util;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -19,20 +11,30 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.settings.AppConfig;
import com.educoder.bridge.common.utils.Base64Util;
import com.educoder.bridge.webssh.model.Webssh;
import com.educoder.bridge.webssh.service.WebsshService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
/**
* @author guange
* @date 2017/08/02
*/
@Api(value = "提供webssh连接", hidden = true)
@RestController
public class WebsshController extends BaseController {
@Autowired
private WebsshService websshService;
public class WebsshController {
private static final Logger logger = LoggerFactory.getLogger(WebsshController.class);
@Autowired
private AppConfig appConfig;
private WebsshService websshService;
@Autowired
private AppConfig appConfig;
@ApiOperation(value = "获取连接容器所需的ip和端口信息", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@RequestMapping(path = "/webssh/getConnectInfo")
@ -49,17 +51,15 @@ public class WebsshController extends BaseController {
JSONObject response = new JSONObject();
response.put("address", sshInfo.getAddress());
response.put("port", Integer.parseInt(sshInfo.getPort()) + "");
response.put("ws_address", appConfig.getServerUrl()); //websocket连接地址
response.put("ws_address", appConfig.getServerUrl()); // websocket连接地址
response.put("code", 0);
return response;
}
@ApiOperation(value = "删除tpiID对应的webssh类型的pod", httpMethod = "POST", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@RequestMapping(path = "/webssh/delete")
public JSONObject delete(
@ApiParam(name = "tpiID", required = true, value = "tpiID") @RequestParam String tpiID,
public JSONObject delete(@ApiParam(name = "tpiID", required = true, value = "tpiID") @RequestParam String tpiID,
@ApiParam(name = "digestKey", required = true, value = "签名") @RequestParam String digestKey,
@ApiParam(name = "identifier", required = true, value = "game的标示") @RequestParam String identifier)
throws Exception {
@ -67,40 +67,33 @@ public class WebsshController extends BaseController {
JSONObject response = new JSONObject();
// 用identifier与私钥拼接与digestKey比较相等响应不想等拒绝
String serverDigestKey = DigestUtils.sha1Hex(identifier + appConfig.getSecretKey());
if (digestKey.equals(serverDigestKey)) {
try {
websshService.deleteNow(tpiID);
response.put("code", 0);
response.put("msg", "成功发起删除命令");
} catch (Exception e) {
logger.error("主动删除pod失败{}", e.getMessage());
response.put("code", -1);
response.put("msg", "删除pod失败");
}
} else {
response.put("code", -1);
response.put("msg", "认证不通过,服务端拒绝连接");
}
String serverDigestKey = DigestUtils.sha1Hex(identifier + appConfig.getSecretKey());
if (digestKey.equals(serverDigestKey)) {
try {
websshService.deleteNow(tpiID);
response.put("code", 0);
response.put("msg", "成功发起删除命令");
} catch (Exception e) {
logger.error("主动删除pod失败", e);
response.put("code", -1);
response.put("msg", "删除pod失败");
}
} else {
response.put("code", -1);
response.put("msg", "认证不通过,服务端拒绝连接");
}
return response;
}
@RequestMapping(value = { "/", "ssh" }, method = RequestMethod.GET)
public ModelAndView index(@RequestParam("Host") String host, @RequestParam("Port") int port,
@RequestParam("Gameid") int gameId, @RequestParam("Username") String username,
@RequestParam("Password") String password, @RequestParam("Tab") String tab, @RequestParam("Rows") int rows,
@RequestParam("Columns") int columns, @RequestParam("Width") int width, @RequestParam("Height") int height
@RequestMapping(value={"/", "ssh"}, method= RequestMethod.GET)
public ModelAndView index(@RequestParam("Host")String host,
@RequestParam("Port")int port,
@RequestParam("Gameid")int gameId,
@RequestParam("Username")String username,
@RequestParam("Password")String password,
@RequestParam("Tab")String tab,
@RequestParam("Rows")int rows,
@RequestParam("Columns")int columns,
@RequestParam("Width")int width,
@RequestParam("Height")int height
) {
//index就是视图的名称index.ftl
) {
// index就是视图的名称index.ftl
logger.debug("/ssh 接收到前端连接请求,host: {}, port: {}, {}", host, port, appConfig.getServerUrl());
ModelAndView mv = new ModelAndView();
mv.setViewName("index");

View File

@ -1,21 +1,5 @@
package com.educoder.bridge.webssh.service;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.webssh.model.ConnectInfo;
import com.educoder.bridge.webssh.model.WebscoketObj;
import com.educoder.bridge.common.utils.Base64Util;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -26,278 +10,294 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.utils.Base64Util;
import com.educoder.bridge.webssh.model.ConnectInfo;
import com.educoder.bridge.webssh.model.WebscoketObj;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
@Service
public class JchService {
@Autowired
private WebsshService websshService;
@Autowired
private WebsshService websshService;
private static List<WebscoketObj> sessionQueue = new CopyOnWriteArrayList<>();
private Logger logger = LoggerFactory.getLogger(getClass());
private static List<WebscoketObj> sessionQueue = new CopyOnWriteArrayList<>();
private Logger logger = LoggerFactory.getLogger(getClass());
com.jcraft.jsch.Logger jschLogger = new com.jcraft.jsch.Logger() {
com.jcraft.jsch.Logger jschLogger = new com.jcraft.jsch.Logger() {
@Override
public boolean isEnabled(int arg0) {
return true;
}
@Override
public boolean isEnabled(int arg0) {
return true;
}
@Override
public void log(int arg0, String arg1) {
if (logger.isTraceEnabled()) {
logger.trace("JSch Log [Level " + arg0 + "]: " + arg1);
}
}
};
@Override
public void log(int arg0, String arg1) {
if (logger.isTraceEnabled()) {
logger.trace("JSch Log [Level " + arg0 + "]: " + arg1);
}
}
};
ExecutorService executorService = Executors.newCachedThreadPool();
@Value("${trustiePodUrl}")
String trustiePodUrl;
/**
* 在webssh连接时初始化一个ssh连接
*
* @param wsSession
*/
public void add(WebSocketSession wsSession) {
ExecutorService executorService = Executors.newCachedThreadPool();
WebscoketObj webscoketObj = new WebscoketObj();
webscoketObj.setSession(wsSession);
/**
* 在webssh连接时初始化一个ssh连接
*
* @param wsSession
*/
public void add(WebSocketSession wsSession) {
sessionQueue.add(webscoketObj);
}
WebscoketObj webscoketObj = new WebscoketObj();
webscoketObj.setSession(wsSession);
/**
* 处理客户端发过来的数据
*
* @param buffer
*/
public void recv(String buffer, WebSocketSession session) {
logger.debug("webssh收到数据" + buffer);
WebscoketObj webscoketObj = null;
try {
// logger.debug("recv函数进程{},sessionID:{},信息:{}",
// Thread.currentThread().getId(), session.getId(), buffer);
JSONObject object = JSONObject.parseObject(buffer);
String tp = object.getString("tp");
if ("init".equals(tp)) {
// 初始化连接
// {"tp":"init","data":{"host":"106.75.96.108","port":"41080","username":"root","secret":"123123","gameid":"1080","rows":"30"}}
ConnectInfo connectInfo = object.getObject("data", ConnectInfo.class);
webscoketObj = findBySession(session);
if (webscoketObj != null) {
WebscoketObj finalWebscoketObj = webscoketObj;
executorService.execute(() -> {
logger.debug("connectToSSH 内线程id:{}session:{},websocketObj:{}",
Thread.currentThread().getId(), session.getId(),
finalWebscoketObj.getSession().getId());
connectTossh(finalWebscoketObj, connectInfo, session);
sessionQueue.add(webscoketObj);
}
});
}
} else if ("client".equals(tp)) {
String data = object.getString("data");
webscoketObj = findBySession(session);
if (webscoketObj != null) {
transTossh(webscoketObj.getOutputStream(), data);
}
} else if ("h".equals(tp)) {
webscoketObj = findBySession(session);
if (webscoketObj != null && webscoketObj.getChannel() != null) {
webscoketObj.getChannel().getSession().sendKeepAliveMsg();
}
}
} catch (Exception e) {
logger.error("转发命令到ssh出错: {}", e);
// closeBySsh(webscoketObj);
if (webscoketObj != null) {
closeByWebsocket(webscoketObj.getSession());
}
}
/**
* 处理客户端发过来的数据
* @param buffer
*/
public void recv(String buffer, WebSocketSession session) {
logger.debug("webssh收到数据" + buffer);
WebscoketObj webscoketObj = null;
try {
// logger.debug("recv函数进程{},sessionID:{},信息:{}", Thread.currentThread().getId(), session.getId(), buffer);
JSONObject object = JSONObject.parseObject(buffer);
String tp = object.getString("tp");
if ("init".equals(tp)) {
//初始化连接
// {"tp":"init","data":{"host":"106.75.96.108","port":"41080","username":"root","secret":"123123","gameid":"1080","rows":"30"}}
ConnectInfo connectInfo = object.getObject("data", ConnectInfo.class);
webscoketObj = findBySession(session);
if (webscoketObj != null) {
WebscoketObj finalWebscoketObj = webscoketObj;
executorService.execute(() -> {
logger.debug("connectToSSH 内线程id:{}session:{},websocketObj:{}",
Thread.currentThread().getId(), session.getId(), finalWebscoketObj.getSession().getId());
connectTossh(finalWebscoketObj, connectInfo, session);
}
});
}
} else if ("client".equals(tp)) {
String data = object.getString("data");
webscoketObj = findBySession(session);
if (webscoketObj != null) {
transTossh(webscoketObj.getOutputStream(), data);
}
} else if ("h".equals(tp)){
webscoketObj = findBySession(session);
if (webscoketObj != null && webscoketObj.getChannel()!=null) {
webscoketObj.getChannel().getSession().sendKeepAliveMsg();
}
}
} catch (Exception e) {
logger.error("转发命令到ssh出错: {}", e);
//closeBySsh(webscoketObj);
closeByWebsocket(webscoketObj.getSession());
}
private void transTossh(OutputStream outputStream, String data) throws IOException {
if (outputStream != null) {
outputStream.write(data.getBytes());
outputStream.flush();
}
}
}
private void connectTossh(WebscoketObj webscoketObj, ConnectInfo connectInfo, WebSocketSession webSocketSession) {
Session session = null;
try {
JSch jsch = new JSch();
JSch.setLogger(jschLogger);
private void transTossh(OutputStream outputStream, String data) throws IOException {
if (outputStream != null) {
outputStream.write(data.getBytes());
outputStream.flush();
}
}
// 启动线程
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session = jsch.getSession(connectInfo.getUsername(), connectInfo.getHost(), connectInfo.getPort());
private void connectTossh(WebscoketObj webscoketObj, ConnectInfo connectInfo, WebSocketSession webSocketSession) {
Session session = null;
try {
JSch jsch = new JSch();
JSch.setLogger(jschLogger);
session.setConfig(config);
session.setPassword(connectInfo.getSecret());
session.setUserInfo(new UserInfo() {
@Override
public String getPassphrase() {
return null;
}
//启动线程
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session = jsch.getSession(connectInfo.getUsername(), connectInfo.getHost(), connectInfo.getPort());
@Override
public String getPassword() {
return null;
}
session.setConfig(config);
session.setPassword(connectInfo.getSecret());
session.setUserInfo(new UserInfo() {
@Override
public String getPassphrase() {
return null;
}
@Override
public boolean promptPassword(String s) {
return false;
}
@Override
public String getPassword() {
return null;
}
@Override
public boolean promptPassphrase(String s) {
return false;
}
@Override
public boolean promptPassword(String s) {
return false;
}
@Override
public boolean promptYesNo(String s) {
return true;
} // Accept all server keys
@Override
public boolean promptPassphrase(String s) {
return false;
}
@Override
public void showMessage(String s) {
}
});
@Override
public boolean promptYesNo(String s) {
return true;
} // Accept all server keys
session.setServerAliveInterval(30 * 1000); // 30秒心跳一次用于保活
@Override
public void showMessage(String s) {
}
});
session.connect();
ChannelShell channel = (ChannelShell) session.openChannel("shell");
channel.setPtyType("xterm");
if (connectInfo.getRows() > 0 && connectInfo.getColumns() > 0) {
channel.setPtySize(connectInfo.getColumns(), connectInfo.getRows(), connectInfo.getWidth(),
connectInfo.getHeight());
}
session.setServerAliveInterval(30*1000); //30秒心跳一次用于保活
channel.connect();
session.connect();
ChannelShell channel = (ChannelShell) session.openChannel("shell");
channel.setPtyType("xterm");
webscoketObj.setChannel(channel);
InputStream inputStream = channel.getInputStream();
webscoketObj.setOutputStream(channel.getOutputStream());
if (connectInfo.getRows()>0&&connectInfo.getColumns()>0) {
channel.setPtySize(
connectInfo.getColumns(),
connectInfo.getRows(),
connectInfo.getWidth(),
connectInfo.getHeight());
}
webscoketObj.setConnectInfo(connectInfo);
channel.connect();
websshService.active("" + connectInfo.getGameid());
webscoketObj.setChannel(channel);
InputStream inputStream = channel.getInputStream();
webscoketObj.setOutputStream(channel.getOutputStream());
// 循环读取
byte[] buf = new byte[1024];
while (true) {
int length = inputStream.read(buf);
if (length < 0) {
throw new Exception("读取终止,连接: " + connectInfo.getHost() + ",端口: " + connectInfo.getPort());
}
sendMsg(webSocketSession, Arrays.copyOfRange(buf, 0, length));
}
webscoketObj.setConnectInfo(connectInfo);
} catch (Exception e) {
logger.error("连接关闭: " + connectInfo.getHost() + ",端口: " + connectInfo.getPort(), e);
} finally {
logger.info("连接关闭, {}", connectInfo.getHost());
if (session != null) {
session.disconnect();
}
websshService.active(""+connectInfo.getGameid());
closeByWebsocket(webscoketObj.getSession());
}
}
//循环读取
byte[] buf = new byte[1024];
while (true) {
int length = inputStream.read(buf);
if (length < 0) {
throw new Exception("读取终止,连接: " + connectInfo.getHost() + ",端口: " + connectInfo.getPort());
}
sendMsg(webSocketSession, Arrays.copyOfRange(buf, 0, length));
}
/**
* 发送数据回websocket
*
* @param session
* @param buffer
* @throws IOException
*/
public void sendMsg(WebSocketSession session, byte[] buffer) throws IOException {
session.sendMessage(new TextMessage(Base64Util.encodeBytes(buffer)));
}
/**
* 关闭ssh和websocket
*
* @param webscoketObj
*/
private void _close(WebscoketObj webscoketObj) {
if (webscoketObj != null && webscoketObj.getChannel() != null) {
webscoketObj.getChannel().disconnect();
try {
webscoketObj.getSession().close();
webscoketObj.getOutputStream().close();
} catch (IOException e) {
// e.printStackTrace();
}
} catch (Exception e) {
logger.error("连接关闭: " + connectInfo.getHost() + ",端口: " + connectInfo.getPort(), e);
} finally {
logger.info("连接关闭, {}", connectInfo.getHost());
if (session!=null) {
session.disconnect();
}
// 从队列中去除
// sessionQueue.remove(webscoketObj);
}
}
closeByWebsocket(webscoketObj.getSession());
}
}
/**
* 因ssh关闭需要主动关闭websocket
*
* @param webscoketObj
*/
private void closeBySsh(WebscoketObj webscoketObj) {
_close(webscoketObj);
}
/**
* 因为webscoket关闭需要关闭内部ssh
*
* @param session
*/
public void closeByWebsocket(WebSocketSession session) {
WebscoketObj webscoketObj = findBySession(session);
this._close(webscoketObj);
/**
* 发送数据回websocket
*
* @param session
* @param buffer
* @throws IOException
*/
public void sendMsg(WebSocketSession session, byte[] buffer) throws IOException {
session.sendMessage(new TextMessage(Base64Util.encodeBytes(buffer)));
}
if (webscoketObj != null && webscoketObj.getConnectInfo() != null) {
int gameId = webscoketObj.getConnectInfo().getGameid();
/**
* 关闭ssh和websocket
*
* @param webscoketObj
*/
private void _close(WebscoketObj webscoketObj) {
if (webscoketObj != null && webscoketObj.getChannel()!=null) {
webscoketObj.getChannel().disconnect();
try {
webscoketObj.getSession().close();
webscoketObj.getOutputStream().close();
} catch (IOException e) {
// e.printStackTrace();
}
// 如果只剩下这个才删除
if (findExistConnectByGameId(gameId)) {
try {
logger.debug("ssh的pod删除任务加入任务队列{}", gameId);
websshService.delete("" + gameId);
} catch (Exception e) {
logger.error("删除pod-{}失败:{}", webscoketObj.getConnectInfo().getGameid(), e);
}
}
}
sessionQueue.remove(webscoketObj);
}
//从队列中去除
// sessionQueue.remove(webscoketObj);
}
}
// TODO 这里要注意如果gameId对应多台主机怎么处理?
/**
* 通过gameId来匹配
*
* @param gameId
*/
public boolean findExistConnectByGameId(int gameId) {
/**
* 因ssh关闭需要主动关闭websocket
*
* @param webscoketObj
*/
private void closeBySsh(WebscoketObj webscoketObj) {
_close(webscoketObj);
}
logger.debug("当前gameID对应的websocket数目{}",
sessionQueue.stream().filter(webscoketObj -> webscoketObj.getConnectInfo() != null
&& webscoketObj.getConnectInfo().getGameid() == gameId).count());
return sessionQueue.stream()
.filter(webscoketObj -> webscoketObj.getConnectInfo() != null
&& webscoketObj.getConnectInfo().getGameid() == gameId)
// .count() > 0;
.count() == 1;
}
/**
* 因为webscoket关闭需要关闭内部ssh
*
* @param session
*/
public void closeByWebsocket(WebSocketSession session) {
WebscoketObj webscoketObj = findBySession(session);
this._close(webscoketObj);
if (webscoketObj!=null && webscoketObj.getConnectInfo() != null) {
int gameId = webscoketObj.getConnectInfo().getGameid();
// 如果只剩下这个才删除
if(findExistConnectByGameId(gameId)){
try {
logger.debug("ssh的pod删除任务加入任务队列{}",gameId);
websshService.delete("" + gameId);
} catch (Exception e) {
logger.error("删除pod-{}失败:{}", webscoketObj.getConnectInfo().getGameid(), e);
}
}
}
sessionQueue.remove(webscoketObj);
}
//TODO 这里要注意如果gameId对应多台主机怎么处理?
/**
* 通过gameId来匹配
* @param gameId
*/
public boolean findExistConnectByGameId(int gameId){
logger.debug("当前gameID对应的websocket数目{}",sessionQueue.stream().filter(webscoketObj ->webscoketObj.getConnectInfo()!=null &&webscoketObj.getConnectInfo().getGameid()==gameId).count());
return sessionQueue.stream().filter(webscoketObj ->
webscoketObj.getConnectInfo()!=null && webscoketObj.getConnectInfo().getGameid()==gameId)
// .count() > 0;
.count() == 1;
}
public WebscoketObj findBySession(WebSocketSession session) {
Optional<WebscoketObj> optional = sessionQueue.stream().filter(webscoketObj -> webscoketObj.getSession() == session).findFirst();
if (optional.isPresent()) {
return optional.get();
}
return null;
}
public WebscoketObj findBySession(WebSocketSession session) {
Optional<WebscoketObj> optional = sessionQueue.stream()
.filter(webscoketObj -> webscoketObj.getSession() == session).findFirst();
if (optional.isPresent()) {
return optional.get();
}
return null;
}
}

View File

@ -1,13 +1,8 @@
package com.educoder.bridge.webssh.service;
import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.common.utils.PortUtil;
import com.educoder.bridge.common.utils.ShellUtil;
import com.educoder.bridge.common.utils.TimeHelper;
import com.educoder.bridge.game.service.K8sService;
import com.educoder.bridge.game.service.PodManagerService;
import com.educoder.bridge.webssh.model.Webssh;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -15,7 +10,14 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.concurrent.ScheduledExecutorService;
import com.educoder.bridge.common.utils.JedisUtil;
import com.educoder.bridge.common.utils.PortUtil;
import com.educoder.bridge.common.utils.TimeHelper;
import com.educoder.bridge.game.service.K8sService;
import com.educoder.bridge.game.service.PodManagerService;
import com.educoder.bridge.webssh.model.Webssh;
import io.fabric8.kubernetes.api.model.Pod;
/**
* @author guange
@ -23,139 +25,143 @@ import java.util.concurrent.ScheduledExecutorService;
*/
@Service("WebsshService")
public class WebsshService {
private final static Logger logger = LoggerFactory.getLogger(WebsshService.class);
private final static Logger logger = LoggerFactory.getLogger(WebsshService.class);
@Value("${webssh.configBakPath}")
private String configBakPath;
@Value("${webssh.configBakPath}")
private String configBakPath;
@Value("${k8s.serverUrl}")
private String k8sServer;
@Value("${k8s.serverUrl}")
private String k8sServer;
@Value("${webssh.delayDeleteTime:900}") //15分钟
private int delayDeleteTime;
@Value("${webssh.delayDeleteTime:900}") // 15分钟
private int delayDeleteTime;
@Autowired
private K8sService k8sService;
@Autowired
private K8sService k8sService;
@Autowired
PodManagerService podManagerService;
@Autowired
PodManagerService podManagerService;
private static ScheduledExecutorService timer;
public Webssh create(String tpiID, Integer podType, String containers) throws Exception {
logger.debug("tpiID: {}, podType: {}", tpiID, podType);
Webssh webssh = new Webssh();
public Webssh create(String tpiID, Integer podType, String containers) throws Exception {
logger.debug("tpiID: {}, podType: {}", tpiID, podType);
Webssh webssh = new Webssh();
String baseName = podType != 2 ? "webssh" : "evassh";
String podName = baseName + "-" + tpiID;
String baseName = podType != 2 ? "webssh" : "evassh";
String podName = baseName + "-" + tpiID;
String websshServiceName = podName + "-22";
String websshServiceName = podName + "-22";
// 取对应的port号
String svcPort = JedisUtil.hget("port1", podName);
// 获取svcPort或新生成svcPortwebssh的映射端口号
if (svcPort == null) {
svcPort = PortUtil.getPort() + "";
JedisUtil.hset("port1", podName, svcPort);
}
// 取对应的port号
String svcPort = JedisUtil.hget("port1", podName);
// 获取svcPort或新生成svcPortwebssh的映射端口号
if (svcPort == null) {
svcPort = PortUtil.getPort() + "";
JedisUtil.hset("port1", podName, svcPort);
}
// 如果pod和服务都存在
boolean existService = serviceExist(websshServiceName);
boolean existPod = false;
Pod pod = k8sService.getPod(podName);
if(pod != null) {
String phase = pod.getStatus().getPhase();
if ("Running".equals(phase)) {
existPod = true;
} else {
k8sService.deletePod(podName);
logger.info("获取ssh连接信息delete 处于{}状态的 pod {}", phase, podName);
}
}
if (existService && existPod) {
// 如果已经被加入删除任务移除删除任务
podManagerService.cancelDel(podName);
// 如果pod和服务都存在
if (serviceExist(websshServiceName) && podExist(podName)) {
// 如果已经被加入删除任务移除删除任务
podManagerService.cancelDel(podName);
// 直接返回结果
webssh.setAddress(k8sServer);
webssh.setPort(svcPort);
return webssh;
}
// 直接返回结果
webssh.setAddress(k8sServer);
webssh.setPort(svcPort);
return webssh;
}
if (!existPod) {
k8sService.createPod(podName, tpiID, baseName, containers, null);
}
if (!podExist(podName)) {
k8sService.createPod(podName, tpiID, baseName, containers);
}
if (!existService) {
k8sService.createService(websshServiceName, podName, tpiID, 22, Integer.parseInt(svcPort));
}
logger.info("Pod成功创建Webssh连入tpiID: {}, podName: {}, time: {}", tpiID, websshServiceName,
TimeHelper.getCurrentTime());
webssh.setAddress(k8sServer);
webssh.setPort(svcPort + "");
logger.debug("response: ip: {}, port: {}", webssh.getAddress(), webssh.getPort());
return webssh;
}
if (!serviceExist(websshServiceName)) {
k8sService.createService(websshServiceName, podName, tpiID, 22, Integer.parseInt(svcPort));
}
logger.info("Pod成功创建Webssh连入tpiID: {}, podName: {}, time: {}",
tpiID, websshServiceName, TimeHelper.getCurrentTime());
public boolean serviceExist(String podName) {
return k8sService.svcExist(podName);
}
webssh.setAddress(k8sServer);
webssh.setPort(svcPort + "");
logger.debug("response: ip: {}, port: {}", webssh.getAddress(), webssh.getPort());
return webssh;
}
public boolean podExist(String podName) {
return k8sService.podExist(podName);
}
public boolean serviceExist(String podName) {
JSONObject out = ShellUtil.executeAndGetExitStatus("kubectl get service " + podName);
if (out.getInteger("exitStatus") == 0) {
return true;
} else {
return false;
}
}
public void delete(String tpiID) {
delete(tpiID, delayDeleteTime);
}
public boolean podExist(String podName) {
JSONObject out = ShellUtil.executeAndGetExitStatus("kubectl get pod " + podName);
if (out.getInteger("exitStatus") == 0) {
return true;
} else {
return false;
}
}
public void delete(String tpiID, int delayTime) {
// 获取pod名
String websshPodName = getPodNameFromTpiId(tpiID);
public void delete(String tpiID) {
delete(tpiID, delayDeleteTime);
}
if (StringUtils.isEmpty(websshPodName)) {
return;
}
public void delete(String tpiID,int delayTime) {
// 获取pod名
String websshPodName = getPodNameFromTpiId(tpiID);
// 当删除队列中已经有删除当前port对应的任务的时候就直接返回
podManagerService.deletePodAfterTime(websshPodName, delayTime);
if (StringUtils.isEmpty(websshPodName)) {
return;
}
logger.info("Webssh连接断开生成定时删除任务Pod加入删除队列: tpiID: {}, podName: {}, time: {}", tpiID, websshPodName,
TimeHelper.getCurrentTime());
}
//当删除队列中已经有删除当前port对应的任务的时候就直接返回
podManagerService.deletePodAfterTime(websshPodName, delayTime);
public void deleteNow(String tpiID) throws Exception {
logger.info("主动不经过定时任务即时删除pod, tpiID: {}", tpiID);
String websshPodName = getPodNameFromTpiId(tpiID);
logger.info("Webssh连接断开生成定时删除任务Pod加入删除队列: tpiID: {}, podName: {}, time: {}", tpiID, websshPodName, TimeHelper.getCurrentTime());
}
if (StringUtils.isEmpty(websshPodName)) {
return;
}
public void deleteNow(String tpiID) throws Exception {
logger.info("主动不经过定时任务即时删除pod, tpiID: {}", tpiID);
String websshPodName = getPodNameFromTpiId(tpiID);
delete(tpiID, 0);
if (StringUtils.isEmpty(websshPodName)) {
return;
}
int timeout = 10;
while ((podExist(websshPodName) || serviceExist(websshPodName)) && timeout > 0) {
Thread.sleep(1000);
timeout--;
}
}
delete(tpiID, 0);
/**
* 通过tpiID获取podName
*
* @param tpiID
* @return
*/
private String getPodNameFromTpiId(String tpiID) {
Map<String, String> inLabels = new HashMap<>();
inLabels.put("tpiID", tpiID);
inLabels.put("type", "webssh,evassh");
Map<String, String> notInLabels = new HashMap<>();
Pod pod = k8sService.getK8sPod(inLabels, notInLabels);
return pod == null ? null : pod.getMetadata().getName();
}
int timeout = 10;
while (podExist(websshPodName) || serviceExist(websshPodName) && timeout > 0) {
Thread.sleep(1000);
timeout--;
}
}
public void active(String tpiID) {
String websshPodName = getPodNameFromTpiId(tpiID);
/**
* 通过tpiID获取podName
* @param tpiID
* @return
*/
private String getPodNameFromTpiId(String tpiID){
String out = ShellUtil.execute("kubectl get pods -l tpiID=" + tpiID + ",type!=evaluate | grep -v NAME");
String websshPodName = out.substring(0, out.indexOf(" "));
return websshPodName;
}
public void active(String tpiID) {
String websshPodName = getPodNameFromTpiId(tpiID);
logger.info("Webssh active方法被调用连接被激活将pod从定时删除队列中移除: tpiID: {}, podName: {}, time: {}",
tpiID, websshPodName, TimeHelper.getCurrentTime());
podManagerService.cancelDel(websshPodName);
}
logger.info("Webssh active方法被调用连接被激活将pod从定时删除队列中移除: tpiID: {}, podName: {}, time: {}", tpiID, websshPodName,
TimeHelper.getCurrentTime());
podManagerService.cancelDel(websshPodName);
}
}

View File

@ -0,0 +1,119 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.nio.client;
import java.io.IOException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.nio.NHttpClientEventHandler;
import org.apache.http.nio.conn.NHttpClientConnectionManager;
import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.util.Asserts;
abstract class BridgeCloseableHttpAsyncClientBase extends CloseableHttpPipeliningClient {
private final Log log = LogFactory.getLog(getClass());
static enum Status {INACTIVE, ACTIVE, STOPPED}
private final NHttpClientConnectionManager connmgr;
private final Thread reactorThread;
private final AtomicReference<Status> status;
public BridgeCloseableHttpAsyncClientBase(
final NHttpClientConnectionManager connmgr,
final ThreadFactory threadFactory,
final NHttpClientEventHandler handler, long bodyLength) {
super();
this.connmgr = connmgr;
if (threadFactory != null && handler != null) {
this.reactorThread = threadFactory.newThread(new Runnable() {
@Override
public void run() {
try {
// 使用 bridge
final IOEventDispatch ioEventDispatch = new BridgeInternalIODispatch(handler, bodyLength,
BridgeCloseableHttpAsyncClientBase.this);
connmgr.execute(ioEventDispatch);
} catch (final Exception ex) {
log.error("I/O reactor terminated abnormally", ex);
} finally {
status.set(Status.STOPPED);
}
}
});
} else {
this.reactorThread = null;
}
this.status = new AtomicReference<Status>(Status.INACTIVE);
}
@Override
public void start() {
if (this.status.compareAndSet(Status.INACTIVE, Status.ACTIVE)) {
if (this.reactorThread != null) {
this.reactorThread.start();
}
}
}
protected void ensureRunning() {
final Status currentStatus = this.status.get();
Asserts.check(currentStatus == Status.ACTIVE, "Request cannot be executed; " +
"I/O reactor status: %s", currentStatus);
}
@Override
public void close() {
if (this.status.compareAndSet(Status.ACTIVE, Status.STOPPED)) {
if (this.reactorThread != null) {
try {
this.connmgr.shutdown();
} catch (final IOException ex) {
this.log.error("I/O error shutting down connection manager", ex);
}
try {
this.reactorThread.join();
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
@Override
public boolean isRunning() {
return this.status.get() == Status.ACTIVE;
}
}

View File

@ -0,0 +1,873 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.nio.client;
import java.net.ProxySelector;
import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.RedirectStrategy;
import org.apache.http.client.UserTokenHandler;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.RequestAddCookies;
import org.apache.http.client.protocol.RequestAuthCache;
import org.apache.http.client.protocol.RequestClientConnControl;
import org.apache.http.client.protocol.RequestDefaultHeaders;
import org.apache.http.client.protocol.RequestExpectContinue;
import org.apache.http.client.protocol.ResponseProcessCookies;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.Lookup;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.SchemePortResolver;
import org.apache.http.conn.routing.HttpRoutePlanner;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.conn.util.PublicSuffixMatcher;
import org.apache.http.conn.util.PublicSuffixMatcherLoader;
import org.apache.http.cookie.CookieSpecProvider;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.NoConnectionReuseStrategy;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.auth.DigestSchemeFactory;
import org.apache.http.impl.auth.KerberosSchemeFactory;
import org.apache.http.impl.auth.NTLMSchemeFactory;
import org.apache.http.impl.auth.SPNegoSchemeFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.NoopUserTokenHandler;
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
import org.apache.http.impl.client.TargetAuthenticationStrategy;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.DefaultRoutePlanner;
import org.apache.http.impl.conn.DefaultSchemePortResolver;
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
import org.apache.http.impl.cookie.DefaultCookieSpecProvider;
import org.apache.http.impl.cookie.IgnoreSpecProvider;
import org.apache.http.impl.cookie.NetscapeDraftSpecProvider;
import org.apache.http.impl.cookie.RFC6265CookieSpecProvider;
import org.apache.http.impl.nio.conn.BridgeManagedNHttpClientConnectionFactory;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.NHttpClientEventHandler;
import org.apache.http.nio.conn.NHttpClientConnectionManager;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpProcessorBuilder;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.protocol.RequestUserAgent;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.TextUtils;
import org.apache.http.util.VersionInfo;
/**
* Builder for {@link CloseableHttpAsyncClient} instances.
* <p>
* When a particular component is not explicitly this class will use its default
* implementation. System properties will be taken into account when configuring
* the default implementations when {@link #useSystemProperties()} method is
* called prior to calling {@link #build()}.
* <ul>
* <li>ssl.TrustManagerFactory.algorithm</li>
* <li>javax.net.ssl.trustStoreType</li>
* <li>javax.net.ssl.trustStore</li>
* <li>javax.net.ssl.trustStoreProvider</li>
* <li>javax.net.ssl.trustStorePassword</li>
* <li>ssl.KeyManagerFactory.algorithm</li>
* <li>javax.net.ssl.keyStoreType</li>
* <li>javax.net.ssl.keyStore</li>
* <li>javax.net.ssl.keyStoreProvider</li>
* <li>javax.net.ssl.keyStorePassword</li>
* <li>https.protocols</li>
* <li>https.cipherSuites</li>
* <li>http.proxyHost</li>
* <li>http.proxyPort</li>
* <li>http.keepAlive</li>
* <li>http.maxConnections</li>
* <li>http.agent</li>
* </ul>
* <p>
* Please note that some settings used by this class can be mutually exclusive
* and may not apply when building {@link CloseableHttpAsyncClient} instances.
*
* @since 4.0
*/
public class BridgeHttpAsyncClientBuilder {
private NHttpClientConnectionManager connManager;
private boolean connManagerShared;
private SchemePortResolver schemePortResolver;
private SchemeIOSessionStrategy sslStrategy;
private HostnameVerifier hostnameVerifier;
private SSLContext sslcontext;
private ConnectionReuseStrategy reuseStrategy;
private ConnectionKeepAliveStrategy keepAliveStrategy;
private AuthenticationStrategy targetAuthStrategy;
private AuthenticationStrategy proxyAuthStrategy;
private UserTokenHandler userTokenHandler;
private HttpProcessor httpprocessor;
private LinkedList<HttpRequestInterceptor> requestFirst;
private LinkedList<HttpRequestInterceptor> requestLast;
private LinkedList<HttpResponseInterceptor> responseFirst;
private LinkedList<HttpResponseInterceptor> responseLast;
private HttpRoutePlanner routePlanner;
private RedirectStrategy redirectStrategy;
private Lookup<AuthSchemeProvider> authSchemeRegistry;
private Lookup<CookieSpecProvider> cookieSpecRegistry;
private CookieStore cookieStore;
private CredentialsProvider credentialsProvider;
private String userAgent;
private HttpHost proxy;
private Collection<? extends Header> defaultHeaders;
private IOReactorConfig defaultIOReactorConfig;
private ConnectionConfig defaultConnectionConfig;
private RequestConfig defaultRequestConfig;
private ThreadFactory threadFactory;
private NHttpClientEventHandler eventHandler;
private PublicSuffixMatcher publicSuffixMatcher;
private boolean systemProperties;
private boolean cookieManagementDisabled;
private boolean authCachingDisabled;
private boolean connectionStateDisabled;
private int maxConnTotal = 0;
private int maxConnPerRoute = 0;
/**
* 请求体长度
*/
private long bodyLength;
public static BridgeHttpAsyncClientBuilder create() {
return new BridgeHttpAsyncClientBuilder();
}
protected BridgeHttpAsyncClientBuilder() {
super();
}
/**
* Assigns file containing public suffix matcher. Instances of this class can be
* created with {@link org.apache.http.conn.util.PublicSuffixMatcherLoader}.
*
* @see org.apache.http.conn.util.PublicSuffixMatcher
* @see org.apache.http.conn.util.PublicSuffixMatcherLoader
*
* @since 4.1
*/
public final BridgeHttpAsyncClientBuilder setPublicSuffixMatcher(final PublicSuffixMatcher publicSuffixMatcher) {
this.publicSuffixMatcher = publicSuffixMatcher;
return this;
}
/**
* Assigns {@link NHttpClientConnectionManager} instance.
*/
public final BridgeHttpAsyncClientBuilder setConnectionManager(final NHttpClientConnectionManager connManager) {
this.connManager = connManager;
return this;
}
/**
* Defines the connection manager is to be shared by multiple client instances.
* <p>
* If the connection manager is shared its life-cycle is expected to be managed
* by the caller and it will not be shut down if the client is closed.
*
* @param shared
* defines whether or not the connection manager can be shared by
* multiple clients.
*
* @since 4.1
*/
public final BridgeHttpAsyncClientBuilder setConnectionManagerShared(final boolean shared) {
this.connManagerShared = shared;
return this;
}
/**
* Assigns {@link SchemePortResolver} instance.
*/
public final BridgeHttpAsyncClientBuilder setSchemePortResolver(final SchemePortResolver schemePortResolver) {
this.schemePortResolver = schemePortResolver;
return this;
}
/**
* Assigns maximum total connection value.
* <p>
* Please note this value can be overridden by the
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
* method.
*/
public final BridgeHttpAsyncClientBuilder setMaxConnTotal(final int maxConnTotal) {
this.maxConnTotal = maxConnTotal;
return this;
}
/**
* Assigns maximum connection per route value.
* <p>
* Please note this value can be overridden by the
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
* method.
*/
public final BridgeHttpAsyncClientBuilder setMaxConnPerRoute(final int maxConnPerRoute) {
this.maxConnPerRoute = maxConnPerRoute;
return this;
}
/**
* Assigns {@link ConnectionReuseStrategy} instance.
*/
public final BridgeHttpAsyncClientBuilder setConnectionReuseStrategy(final ConnectionReuseStrategy reuseStrategy) {
this.reuseStrategy = reuseStrategy;
return this;
}
/**
* Assigns {@link ConnectionKeepAliveStrategy} instance.
*/
public final BridgeHttpAsyncClientBuilder setKeepAliveStrategy(
final ConnectionKeepAliveStrategy keepAliveStrategy) {
this.keepAliveStrategy = keepAliveStrategy;
return this;
}
/**
* Assigns {@link UserTokenHandler} instance.
* <p>
* Please note this value can be overridden by the
* {@link #disableConnectionState()} method.
*/
public final BridgeHttpAsyncClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) {
this.userTokenHandler = userTokenHandler;
return this;
}
/**
* Assigns {@link AuthenticationStrategy} instance for proxy authentication.
*/
public final BridgeHttpAsyncClientBuilder setTargetAuthenticationStrategy(
final AuthenticationStrategy targetAuthStrategy) {
this.targetAuthStrategy = targetAuthStrategy;
return this;
}
/**
* Assigns {@link AuthenticationStrategy} instance for target host
* authentication.
*/
public final BridgeHttpAsyncClientBuilder setProxyAuthenticationStrategy(
final AuthenticationStrategy proxyAuthStrategy) {
this.proxyAuthStrategy = proxyAuthStrategy;
return this;
}
/**
* Assigns {@link HttpProcessor} instance.
*/
public final BridgeHttpAsyncClientBuilder setHttpProcessor(final HttpProcessor httpprocessor) {
this.httpprocessor = httpprocessor;
return this;
}
/**
* Adds this protocol interceptor to the head of the protocol processing list.
* <p>
* Please note this value can be overridden by the
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
*/
public final BridgeHttpAsyncClientBuilder addInterceptorFirst(final HttpResponseInterceptor itcp) {
if (itcp == null) {
return this;
}
if (responseFirst == null) {
responseFirst = new LinkedList<HttpResponseInterceptor>();
}
responseFirst.addFirst(itcp);
return this;
}
/**
* Adds this protocol interceptor to the tail of the protocol processing list.
* <p>
* Please note this value can be overridden by the
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
*/
public final BridgeHttpAsyncClientBuilder addInterceptorLast(final HttpResponseInterceptor itcp) {
if (itcp == null) {
return this;
}
if (responseLast == null) {
responseLast = new LinkedList<HttpResponseInterceptor>();
}
responseLast.addLast(itcp);
return this;
}
/**
* Adds this protocol interceptor to the head of the protocol processing list.
* <p>
* Please note this value can be overridden by the
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
*/
public final BridgeHttpAsyncClientBuilder addInterceptorFirst(final HttpRequestInterceptor itcp) {
if (itcp == null) {
return this;
}
if (requestFirst == null) {
requestFirst = new LinkedList<HttpRequestInterceptor>();
}
requestFirst.addFirst(itcp);
return this;
}
/**
* Adds this protocol interceptor to the tail of the protocol processing list.
* <p>
* Please note this value can be overridden by the
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
*/
public final BridgeHttpAsyncClientBuilder addInterceptorLast(final HttpRequestInterceptor itcp) {
if (itcp == null) {
return this;
}
if (requestLast == null) {
requestLast = new LinkedList<HttpRequestInterceptor>();
}
requestLast.addLast(itcp);
return this;
}
/**
* Assigns {@link HttpRoutePlanner} instance.
*/
public final BridgeHttpAsyncClientBuilder setRoutePlanner(final HttpRoutePlanner routePlanner) {
this.routePlanner = routePlanner;
return this;
}
/**
* Assigns {@link RedirectStrategy} instance.
*/
public final BridgeHttpAsyncClientBuilder setRedirectStrategy(final RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
return this;
}
/**
* Assigns default {@link CookieStore} instance which will be used for request
* execution if not explicitly set in the client execution context.
*/
public final BridgeHttpAsyncClientBuilder setDefaultCookieStore(final CookieStore cookieStore) {
this.cookieStore = cookieStore;
return this;
}
/**
* Assigns default {@link CredentialsProvider} instance which will be used for
* request execution if not explicitly set in the client execution context.
*/
public final BridgeHttpAsyncClientBuilder setDefaultCredentialsProvider(
final CredentialsProvider credentialsProvider) {
this.credentialsProvider = credentialsProvider;
return this;
}
/**
* Assigns default {@link org.apache.http.auth.AuthScheme} registry which will
* be used for request execution if not explicitly set in the client execution
* context.
*/
public final BridgeHttpAsyncClientBuilder setDefaultAuthSchemeRegistry(
final Lookup<AuthSchemeProvider> authSchemeRegistry) {
this.authSchemeRegistry = authSchemeRegistry;
return this;
}
/**
* Assigns default {@link org.apache.http.cookie.CookieSpec} registry which will
* be used for request execution if not explicitly set in the client execution
* context.
*/
public final BridgeHttpAsyncClientBuilder setDefaultCookieSpecRegistry(
final Lookup<CookieSpecProvider> cookieSpecRegistry) {
this.cookieSpecRegistry = cookieSpecRegistry;
return this;
}
/**
* Assigns {@code User-Agent} value.
* <p>
* Please note this value can be overridden by the
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
*/
public final BridgeHttpAsyncClientBuilder setUserAgent(final String userAgent) {
this.userAgent = userAgent;
return this;
}
/**
* Assigns default proxy value.
* <p>
* Please note this value can be overridden by the
* {@link #setRoutePlanner( org.apache.http.conn.routing.HttpRoutePlanner)}
* method.
*/
public final BridgeHttpAsyncClientBuilder setProxy(final HttpHost proxy) {
this.proxy = proxy;
return this;
}
/**
* Assigns {@link SchemeIOSessionStrategy} instance.
* <p>
* Please note this value can be overridden by the
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
* method.
*/
public final BridgeHttpAsyncClientBuilder setSSLStrategy(final SchemeIOSessionStrategy strategy) {
this.sslStrategy = strategy;
return this;
}
/**
* Assigns {@link SSLContext} instance.
* <p>
* Please note this value can be overridden by the
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
* and the
* {@link #setSSLStrategy( org.apache.http.nio.conn.SchemeIOSessionStrategy)}
* methods.
*/
public final BridgeHttpAsyncClientBuilder setSSLContext(final SSLContext sslcontext) {
this.sslcontext = sslcontext;
return this;
}
/**
* Assigns {@link X509HostnameVerifier} instance.
* <p>
* Please note this value can be overridden by the
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
* and the
* {@link #setSSLStrategy( org.apache.http.nio.conn.SchemeIOSessionStrategy)}
* methods.
*
* @deprecated (4.1) use
* {@link #setSSLHostnameVerifier(javax.net.ssl.HostnameVerifier)}
*/
@Deprecated
public final BridgeHttpAsyncClientBuilder setHostnameVerifier(final X509HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
return this;
}
/**
* Assigns {@link javax.net.ssl.HostnameVerifier} instance.
* <p>
* Please note this value can be overridden by the
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
* and the
* {@link #setSSLStrategy( org.apache.http.nio.conn.SchemeIOSessionStrategy)}
* methods.
*
* @since 4.1
*/
public final BridgeHttpAsyncClientBuilder setSSLHostnameVerifier(final HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
return this;
}
/**
* Assigns default request header values.
* <p>
* Please note this value can be overridden by the
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
*/
public final BridgeHttpAsyncClientBuilder setDefaultHeaders(final Collection<? extends Header> defaultHeaders) {
this.defaultHeaders = defaultHeaders;
return this;
}
/**
* Assigns default {@link IOReactorConfig}.
* <p>
* Please note this value can be overridden by the
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
* method.
*/
public final BridgeHttpAsyncClientBuilder setDefaultIOReactorConfig(final IOReactorConfig config) {
this.defaultIOReactorConfig = config;
return this;
}
/**
* Assigns default {@link ConnectionConfig}.
* <p>
* Please note this value can be overridden by the
* {@link #setConnectionManager( org.apache.http.nio.conn.NHttpClientConnectionManager)}
* method.
*/
public final BridgeHttpAsyncClientBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
this.defaultConnectionConfig = config;
return this;
}
/**
* Assigns default {@link RequestConfig} instance which will be used for request
* execution if not explicitly set in the client execution context.
*/
public final BridgeHttpAsyncClientBuilder setDefaultRequestConfig(final RequestConfig config) {
this.defaultRequestConfig = config;
return this;
}
/**
* Assigns {@link ThreadFactory} instance.
*/
public final BridgeHttpAsyncClientBuilder setThreadFactory(final ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
return this;
}
/**
* Assigns {@link NHttpClientEventHandler} instance.
*
* @since 4.1
*/
public final BridgeHttpAsyncClientBuilder setEventHandler(final NHttpClientEventHandler eventHandler) {
this.eventHandler = eventHandler;
return this;
}
/**
* Disables connection state tracking.
*/
public final BridgeHttpAsyncClientBuilder disableConnectionState() {
connectionStateDisabled = true;
return this;
}
/**
* Disables state (cookie) management.
* <p>
* Please note this value can be overridden by the
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
*/
public final BridgeHttpAsyncClientBuilder disableCookieManagement() {
cookieManagementDisabled = true;
return this;
}
/**
* Disables authentication scheme caching.
* <p>
* Please note this value can be overridden by the
* {@link #setHttpProcessor( org.apache.http.protocol.HttpProcessor)} method.
*/
public final BridgeHttpAsyncClientBuilder disableAuthCaching() {
authCachingDisabled = true;
return this;
}
/**
* Use system properties when creating and configuring default implementations.
*/
public final BridgeHttpAsyncClientBuilder useSystemProperties() {
systemProperties = true;
return this;
}
public final BridgeHttpAsyncClientBuilder setBodyLength(long bodyLength) {
this.bodyLength = bodyLength;
return this;
}
private static String[] split(final String s) {
if (TextUtils.isBlank(s)) {
return null;
}
return s.split(" *, *");
}
public CloseableHttpAsyncClient build() {
PublicSuffixMatcher publicSuffixMatcher = this.publicSuffixMatcher;
if (publicSuffixMatcher == null) {
publicSuffixMatcher = PublicSuffixMatcherLoader.getDefault();
}
NHttpClientConnectionManager connManager = this.connManager;
if (connManager == null) {
SchemeIOSessionStrategy sslStrategy = this.sslStrategy;
if (sslStrategy == null) {
SSLContext sslcontext = this.sslcontext;
if (sslcontext == null) {
if (systemProperties) {
sslcontext = SSLContexts.createSystemDefault();
} else {
sslcontext = SSLContexts.createDefault();
}
}
final String[] supportedProtocols = systemProperties ? split(System.getProperty("https.protocols"))
: null;
final String[] supportedCipherSuites = systemProperties
? split(System.getProperty("https.cipherSuites"))
: null;
HostnameVerifier hostnameVerifier = this.hostnameVerifier;
if (hostnameVerifier == null) {
hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);
}
sslStrategy = new SSLIOSessionStrategy(sslcontext, supportedProtocols, supportedCipherSuites,
hostnameVerifier);
}
final ConnectingIOReactor ioreactor = IOReactorUtils.create(
defaultIOReactorConfig != null ? defaultIOReactorConfig : IOReactorConfig.DEFAULT, threadFactory);
// 加入 BridgeManagedNHttpClientConnectionFactory
final PoolingNHttpClientConnectionManager poolingmgr = new PoolingNHttpClientConnectionManager(ioreactor,
BridgeManagedNHttpClientConnectionFactory.INSTANCE,
RegistryBuilder.<SchemeIOSessionStrategy>create().register("http", NoopIOSessionStrategy.INSTANCE)
.register("https", sslStrategy).build());
if (defaultConnectionConfig != null) {
poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
}
if (systemProperties) {
String s = System.getProperty("http.keepAlive", "true");
if ("true".equalsIgnoreCase(s)) {
s = System.getProperty("http.maxConnections", "5");
final int max = Integer.parseInt(s);
poolingmgr.setDefaultMaxPerRoute(max);
poolingmgr.setMaxTotal(2 * max);
}
} else {
if (maxConnTotal > 0) {
poolingmgr.setMaxTotal(maxConnTotal);
}
if (maxConnPerRoute > 0) {
poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
}
}
connManager = poolingmgr;
}
ConnectionReuseStrategy reuseStrategy = this.reuseStrategy;
if (reuseStrategy == null) {
if (systemProperties) {
final String s = System.getProperty("http.keepAlive", "true");
if ("true".equalsIgnoreCase(s)) {
reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
} else {
reuseStrategy = NoConnectionReuseStrategy.INSTANCE;
}
} else {
reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
}
}
ConnectionKeepAliveStrategy keepAliveStrategy = this.keepAliveStrategy;
if (keepAliveStrategy == null) {
keepAliveStrategy = DefaultConnectionKeepAliveStrategy.INSTANCE;
}
AuthenticationStrategy targetAuthStrategy = this.targetAuthStrategy;
if (targetAuthStrategy == null) {
targetAuthStrategy = TargetAuthenticationStrategy.INSTANCE;
}
AuthenticationStrategy proxyAuthStrategy = this.proxyAuthStrategy;
if (proxyAuthStrategy == null) {
proxyAuthStrategy = ProxyAuthenticationStrategy.INSTANCE;
}
UserTokenHandler userTokenHandler = this.userTokenHandler;
if (userTokenHandler == null) {
if (!connectionStateDisabled) {
userTokenHandler = DefaultAsyncUserTokenHandler.INSTANCE;
} else {
userTokenHandler = NoopUserTokenHandler.INSTANCE;
}
}
SchemePortResolver schemePortResolver = this.schemePortResolver;
if (schemePortResolver == null) {
schemePortResolver = DefaultSchemePortResolver.INSTANCE;
}
HttpProcessor httpprocessor = this.httpprocessor;
if (httpprocessor == null) {
String userAgent = this.userAgent;
if (userAgent == null) {
if (systemProperties) {
userAgent = System.getProperty("http.agent");
}
if (userAgent == null) {
userAgent = VersionInfo.getUserAgent("Apache-HttpAsyncClient", "org.apache.http.nio.client",
getClass());
}
}
final HttpProcessorBuilder b = HttpProcessorBuilder.create();
if (requestFirst != null) {
for (final HttpRequestInterceptor i : requestFirst) {
b.addFirst(i);
}
}
if (responseFirst != null) {
for (final HttpResponseInterceptor i : responseFirst) {
b.addFirst(i);
}
}
b.addAll(new RequestDefaultHeaders(defaultHeaders), new RequestContent(), new RequestTargetHost(),
new RequestClientConnControl(), new RequestUserAgent(userAgent), new RequestExpectContinue());
if (!cookieManagementDisabled) {
b.add(new RequestAddCookies());
}
if (!authCachingDisabled) {
b.add(new RequestAuthCache());
}
if (!cookieManagementDisabled) {
b.add(new ResponseProcessCookies());
}
if (requestLast != null) {
for (final HttpRequestInterceptor i : requestLast) {
b.addLast(i);
}
}
if (responseLast != null) {
for (final HttpResponseInterceptor i : responseLast) {
b.addLast(i);
}
}
httpprocessor = b.build();
}
// Add redirect executor, if not disabled
HttpRoutePlanner routePlanner = this.routePlanner;
if (routePlanner == null) {
if (proxy != null) {
routePlanner = new DefaultProxyRoutePlanner(proxy, schemePortResolver);
} else if (systemProperties) {
routePlanner = new SystemDefaultRoutePlanner(schemePortResolver, ProxySelector.getDefault());
} else {
routePlanner = new DefaultRoutePlanner(schemePortResolver);
}
}
Lookup<AuthSchemeProvider> authSchemeRegistry = this.authSchemeRegistry;
if (authSchemeRegistry == null) {
authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register(AuthSchemes.BASIC, new BasicSchemeFactory())
.register(AuthSchemes.DIGEST, new DigestSchemeFactory())
.register(AuthSchemes.NTLM, new NTLMSchemeFactory())
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory())
.register(AuthSchemes.KERBEROS, new KerberosSchemeFactory()).build();
}
Lookup<CookieSpecProvider> cookieSpecRegistry = this.cookieSpecRegistry;
if (cookieSpecRegistry == null) {
final CookieSpecProvider defaultProvider = new DefaultCookieSpecProvider(publicSuffixMatcher);
final CookieSpecProvider laxStandardProvider = new RFC6265CookieSpecProvider(
RFC6265CookieSpecProvider.CompatibilityLevel.RELAXED, publicSuffixMatcher);
final CookieSpecProvider strictStandardProvider = new RFC6265CookieSpecProvider(
RFC6265CookieSpecProvider.CompatibilityLevel.STRICT, publicSuffixMatcher);
cookieSpecRegistry = RegistryBuilder.<CookieSpecProvider>create()
.register(CookieSpecs.DEFAULT, defaultProvider).register("best-match", defaultProvider)
.register("compatibility", defaultProvider).register(CookieSpecs.STANDARD, laxStandardProvider)
.register(CookieSpecs.STANDARD_STRICT, strictStandardProvider)
.register(CookieSpecs.NETSCAPE, new NetscapeDraftSpecProvider())
.register(CookieSpecs.IGNORE_COOKIES, new IgnoreSpecProvider()).build();
}
CookieStore defaultCookieStore = this.cookieStore;
if (defaultCookieStore == null) {
defaultCookieStore = new BasicCookieStore();
}
CredentialsProvider defaultCredentialsProvider = this.credentialsProvider;
if (defaultCredentialsProvider == null) {
if (systemProperties) {
defaultCredentialsProvider = new SystemDefaultCredentialsProvider();
} else {
defaultCredentialsProvider = new BasicCredentialsProvider();
}
}
RedirectStrategy redirectStrategy = this.redirectStrategy;
if (redirectStrategy == null) {
redirectStrategy = DefaultRedirectStrategy.INSTANCE;
}
RequestConfig defaultRequestConfig = this.defaultRequestConfig;
if (defaultRequestConfig == null) {
defaultRequestConfig = RequestConfig.DEFAULT;
}
final MainClientExec exec = new MainClientExec(httpprocessor, routePlanner, redirectStrategy,
targetAuthStrategy, proxyAuthStrategy, userTokenHandler);
ThreadFactory threadFactory = null;
NHttpClientEventHandler eventHandler = null;
if (!this.connManagerShared) {
threadFactory = this.threadFactory;
if (threadFactory == null) {
threadFactory = Executors.defaultThreadFactory();
}
eventHandler = this.eventHandler;
if (eventHandler == null) {
eventHandler = new HttpAsyncRequestExecutor();
}
}
// 使用 bridge
return new BridgeInternalHttpAsyncClient(connManager, reuseStrategy, keepAliveStrategy, threadFactory,
eventHandler, exec, cookieSpecRegistry, authSchemeRegistry, defaultCookieStore,
defaultCredentialsProvider, defaultRequestConfig, bodyLength);
}
}

View File

@ -0,0 +1,158 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.nio.client;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthState;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.concurrent.BasicFuture;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.config.Lookup;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.cookie.CookieSpecProvider;
import org.apache.http.nio.NHttpClientEventHandler;
import org.apache.http.nio.conn.NHttpClientConnectionManager;
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
import org.apache.http.nio.protocol.HttpAsyncResponseConsumer;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
class BridgeInternalHttpAsyncClient extends BridgeCloseableHttpAsyncClientBase {
private final Log log = LogFactory.getLog(getClass());
private final NHttpClientConnectionManager connmgr;
private final ConnectionReuseStrategy connReuseStrategy;
private final ConnectionKeepAliveStrategy keepaliveStrategy;
private final InternalClientExec exec;
private final Lookup<CookieSpecProvider> cookieSpecRegistry;
private final Lookup<AuthSchemeProvider> authSchemeRegistry;
private final CookieStore cookieStore;
private final CredentialsProvider credentialsProvider;
private final RequestConfig defaultConfig;
public BridgeInternalHttpAsyncClient(
final NHttpClientConnectionManager connmgr,
final ConnectionReuseStrategy connReuseStrategy,
final ConnectionKeepAliveStrategy keepaliveStrategy,
final ThreadFactory threadFactory,
final NHttpClientEventHandler handler,
final InternalClientExec exec,
final Lookup<CookieSpecProvider> cookieSpecRegistry,
final Lookup<AuthSchemeProvider> authSchemeRegistry,
final CookieStore cookieStore,
final CredentialsProvider credentialsProvider,
final RequestConfig defaultConfig, final long bodyLength) {
super(connmgr, threadFactory, handler, bodyLength);
this.connmgr = connmgr;
this.connReuseStrategy = connReuseStrategy;
this.keepaliveStrategy = keepaliveStrategy;
this.exec = exec;
this.cookieSpecRegistry = cookieSpecRegistry;
this.authSchemeRegistry = authSchemeRegistry;
this.cookieStore = cookieStore;
this.credentialsProvider = credentialsProvider;
this.defaultConfig = defaultConfig;
}
private void setupContext(final HttpClientContext context) {
if (context.getAttribute(HttpClientContext.TARGET_AUTH_STATE) == null) {
context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, new AuthState());
}
if (context.getAttribute(HttpClientContext.PROXY_AUTH_STATE) == null) {
context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, new AuthState());
}
if (context.getAttribute(HttpClientContext.AUTHSCHEME_REGISTRY) == null) {
context.setAttribute(HttpClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
}
if (context.getAttribute(HttpClientContext.COOKIESPEC_REGISTRY) == null) {
context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
}
if (context.getAttribute(HttpClientContext.COOKIE_STORE) == null) {
context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
}
if (context.getAttribute(HttpClientContext.CREDS_PROVIDER) == null) {
context.setAttribute(HttpClientContext.CREDS_PROVIDER, this.credentialsProvider);
}
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
context.setAttribute(HttpClientContext.REQUEST_CONFIG, this.defaultConfig);
}
}
@Override
public <T> Future<T> execute(
final HttpAsyncRequestProducer requestProducer,
final HttpAsyncResponseConsumer<T> responseConsumer,
final HttpContext context,
final FutureCallback<T> callback) {
ensureRunning();
final BasicFuture<T> future = new BasicFuture<T>(callback);
final HttpClientContext localcontext = HttpClientContext.adapt(
context != null ? context : new BasicHttpContext());
setupContext(localcontext);
@SuppressWarnings("resource")
final DefaultClientExchangeHandlerImpl<T> handler = new DefaultClientExchangeHandlerImpl<T>(
this.log,
requestProducer,
responseConsumer,
localcontext,
future,
this.connmgr,
this.connReuseStrategy,
this.keepaliveStrategy,
this.exec);
try {
handler.start();
} catch (final Exception ex) {
handler.failed(ex);
}
return new FutureWrapper<T>(future, handler);
}
@Override
public <T> Future<List<T>> execute(
final HttpHost target,
final List<? extends HttpAsyncRequestProducer> requestProducers,
final List<? extends HttpAsyncResponseConsumer<T>> responseConsumers,
final HttpContext context,
final FutureCallback<List<T>> callback) {
throw new UnsupportedOperationException("Pipelining not supported");
}
}

View File

@ -0,0 +1,66 @@
package org.apache.http.impl.nio.client;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.http.impl.nio.DefaultNHttpClientConnection;
import org.apache.http.impl.nio.conn.BridgeManagedNHttpClientConnectionImpl;
import org.apache.http.nio.NHttpClientEventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BridgeInternalIODispatch extends InternalIODispatch {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* 请求体长度
*/
private long bodyLength = -1;
private CloseableHttpAsyncClient client;
private AtomicBoolean sendOver = new AtomicBoolean();
public BridgeInternalIODispatch(NHttpClientEventHandler handler, long entityLength,
CloseableHttpAsyncClient client) {
super(handler);
this.bodyLength = entityLength;
this.client = client;
}
@Override
protected void onOutputReady(DefaultNHttpClientConnection conn) {
if (conn instanceof BridgeManagedNHttpClientConnectionImpl) {
BridgeManagedNHttpClientConnectionImpl c = (BridgeManagedNHttpClientConnectionImpl) conn;
boolean encoderNotCompleted = c.getContentEncoder() != null && !c.getContentEncoder().isCompleted();
if (c.isRequestNotSendComplete() || encoderNotCompleted) {// 需要发送数据
} else { // 收到server 确认
sendOver.compareAndSet(false, true);
}
}
super.onOutputReady(conn);
if (conn instanceof BridgeManagedNHttpClientConnectionImpl) {
BridgeManagedNHttpClientConnectionImpl c = (BridgeManagedNHttpClientConnectionImpl) conn;
boolean encoderNotCompleted = c.getContentEncoder() != null && !c.getContentEncoder().isCompleted();
if (c.isRequestNotSendComplete() || encoderNotCompleted) {// 需要发送数据
// do nothing
} else {
long length = c.getDataLengthTransferred();
if (length >= this.bodyLength) {
if (!sendOver.get()) {
logger.info("请求已经发送完毕, 总长度是 " + length);
} else {
logger.info("请求已经发送完毕, 总长度是 " + length + ",收到服务的确认,关闭连接");
try {
conn.close();
client.close();
} catch (IOException e) {
logger.error("nio 关闭异常", e);
}
}
}
}
}
}
}

View File

@ -0,0 +1,86 @@
package org.apache.http.impl.nio.conn;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.impl.nio.codecs.DefaultHttpRequestWriterFactory;
import org.apache.http.impl.nio.codecs.DefaultHttpResponseParserFactory;
import org.apache.http.nio.NHttpMessageParserFactory;
import org.apache.http.nio.NHttpMessageWriterFactory;
import org.apache.http.nio.conn.ManagedNHttpClientConnection;
import org.apache.http.nio.conn.NHttpConnectionFactory;
import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.nio.reactor.IOSession;
import org.apache.http.nio.util.ByteBufferAllocator;
import org.apache.http.nio.util.HeapByteBufferAllocator;
public class BridgeManagedNHttpClientConnectionFactory implements NHttpConnectionFactory<ManagedNHttpClientConnection> {
private final Log headerlog = LogFactory.getLog("org.apache.http.headers");
private final Log wirelog = LogFactory.getLog("org.apache.http.wire");
private final Log log = LogFactory.getLog(ManagedNHttpClientConnectionImpl.class);
private static final AtomicLong COUNTER = new AtomicLong();
// 使用 bridge
public static final BridgeManagedNHttpClientConnectionFactory INSTANCE = new BridgeManagedNHttpClientConnectionFactory();
private final ByteBufferAllocator allocator;
private final NHttpMessageWriterFactory<HttpRequest> requestWriterFactory;
private final NHttpMessageParserFactory<HttpResponse> responseParserFactory;
public BridgeManagedNHttpClientConnectionFactory(
final NHttpMessageWriterFactory<HttpRequest> requestWriterFactory,
final NHttpMessageParserFactory<HttpResponse> responseParserFactory,
final ByteBufferAllocator allocator) {
super();
this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory :
DefaultHttpRequestWriterFactory.INSTANCE;
this.responseParserFactory = responseParserFactory != null ? responseParserFactory :
DefaultHttpResponseParserFactory.INSTANCE;
this.allocator = allocator != null ? allocator : HeapByteBufferAllocator.INSTANCE;
}
public BridgeManagedNHttpClientConnectionFactory() {
this(null, null, null);
}
@Override
public ManagedNHttpClientConnection create(final IOSession iosession, final ConnectionConfig config) {
final String id = "http-outgoing-" + Long.toString(COUNTER.getAndIncrement());
CharsetDecoder chardecoder = null;
CharsetEncoder charencoder = null;
final Charset charset = config.getCharset();
final CodingErrorAction malformedInputAction = config.getMalformedInputAction() != null
? config.getMalformedInputAction()
: CodingErrorAction.REPORT;
final CodingErrorAction unmappableInputAction = config.getUnmappableInputAction() != null
? config.getUnmappableInputAction()
: CodingErrorAction.REPORT;
if (charset != null) {
chardecoder = charset.newDecoder();
chardecoder.onMalformedInput(malformedInputAction);
chardecoder.onUnmappableCharacter(unmappableInputAction);
charencoder = charset.newEncoder();
charencoder.onMalformedInput(malformedInputAction);
charencoder.onUnmappableCharacter(unmappableInputAction);
}
// 使用 bridge
final ManagedNHttpClientConnection conn = new BridgeManagedNHttpClientConnectionImpl(id, this.log,
this.headerlog,
this.wirelog, iosession, config.getBufferSize(), config.getFragmentSizeHint(), this.allocator,
chardecoder, charencoder, config.getMessageConstraints(), null, null, this.requestWriterFactory,
this.responseParserFactory);
iosession.setAttribute(IOEventDispatch.CONNECTION_KEY, conn);
return conn;
}
}

View File

@ -0,0 +1,43 @@
package org.apache.http.impl.nio.conn;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import org.apache.commons.logging.Log;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.config.MessageConstraints;
import org.apache.http.entity.ContentLengthStrategy;
import org.apache.http.nio.ContentEncoder;
import org.apache.http.nio.NHttpMessageParserFactory;
import org.apache.http.nio.NHttpMessageWriterFactory;
import org.apache.http.nio.conn.ManagedNHttpClientConnection;
import org.apache.http.nio.reactor.IOSession;
import org.apache.http.nio.util.ByteBufferAllocator;
public class BridgeManagedNHttpClientConnectionImpl extends ManagedNHttpClientConnectionImpl
implements ManagedNHttpClientConnection {
public BridgeManagedNHttpClientConnectionImpl(String id, Log log, Log headerlog, Log wirelog, IOSession iosession,
int buffersize, int fragmentSizeHint, ByteBufferAllocator allocator, CharsetDecoder chardecoder,
CharsetEncoder charencoder, MessageConstraints constraints, ContentLengthStrategy incomingContentStrategy,
ContentLengthStrategy outgoingContentStrategy, NHttpMessageWriterFactory<HttpRequest> requestWriterFactory,
NHttpMessageParserFactory<HttpResponse> responseParserFactory) {
super(id, log, headerlog, wirelog, iosession, buffersize, fragmentSizeHint, allocator, chardecoder, charencoder,
constraints, incomingContentStrategy, outgoingContentStrategy, requestWriterFactory,
responseParserFactory);
}
public boolean isRequestNotSendComplete() {
return super.hasBufferedOutput;
}
public long getDataLengthTransferred() {
return outTransportMetrics.getBytesTransferred();
}
public ContentEncoder getContentEncoder() {
return this.contentEncoder;
}
}

View File

@ -14,6 +14,9 @@
<aop:aspectj-autoproxy/>
<context:component-scan base-package="com.educoder.bridge.*.*"/>
<context:property-placeholder location="classpath:config_${spring.profiles.active}.properties" />
<import resource="classpath*:dataSource.xml" />
<!-- freemaker配置 -->
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
@ -38,7 +41,7 @@
<bean id="websshHandler" class="com.educoder.bridge.webssh.handler.WebsshHandler"/>
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<bean id="threadPoolTaskExecutor" class="com.educoder.bridge.game.thread.BridgeThreadPoolTaskExecutor">
<property name="corePoolSize" value="400"/>
<property name="maxPoolSize" value="400"/>
<property name="queueCapacity" value="5000"/>

View File

@ -1,4 +1,6 @@
educoderURL=https://testbdweb.educoder.net/myshixuns/training_task_status
educoderURL=https://testbdweb.educoder.net/myshixuns/training_task_status.json
simpileEducoderURL=https://testbdweb.educoder.net/myshixuns/code_runinng_message.json
workspace=/data/workspace
## webssh
@ -7,7 +9,11 @@ webssh.serverUrl=https://10.9.81.28:6443
webssh.userName=root
webssh.passwd=123123
#the k8s server IP that can be accessed from internet
## \u547d\u4ee4\u884c\u8fde\u63a5\u65f6\u7684websocket\u5730\u5740
websocket.addr=wss://testwebssh.educoder.net/ws
#the k8s server IP that can be accessed from internet
k8s.serverUrl=10.9.81.28
#to execute k8s cmds in slave node ,we have to provide the token
k8s.token=726b127bcf34784b
@ -19,32 +25,50 @@ maxRunningPodNum=20000
defaultTimeLimit=90
# redis
redisAddress=127.0.0.1
redisAddress=192.168.56.101
redisPort=6379
redisAuth=
#测试版kubernetes用户名和密码
k8sServer=127.0.0.1:8080
#\u6d4b\u8bd5\u7248kubernetes\u7528\u6237\u540d\u548c\u5bc6\u7801
k8sServer=10.9.81.28:8080
k8sUser=testk8s
k8sPasswd=testk8s
#测试版资源总量
#\u6d4b\u8bd5\u7248\u8d44\u6e90\u603b\u91cf
cpuAllocatable=4000
memAllocatable=10000
#测试版dockerURL(主节点)
#\u6d4b\u8bd5\u7248dockerURL(\u4e3b\u8282\u70b9)
dockerMaster=http://10.9.81.28:54243
#测试版dockerURL(副节点)
#\u6d4b\u8bd5\u7248dockerURL(\u526f\u8282\u70b9)
dockerDeputies=http://10.9.186.111:54243
#镜像仓库地址
registry=10.9.105.90:5000
#\u955c\u50cf\u4ed3\u5e93\u5730\u5740
registry=10.9.164.118:5000
#IP
gitIP=10.9.73.116
gitBackUpIP=10.9.73.116
#编译结果最大长度
#\u7f16\u8bd1\u7ed3\u679c\u6700\u5927\u957f\u5ea6
outputSize=65535
#认证密钥
secretKey=priEn3UwXfJs3PmyXnSG
#\u8ba4\u8bc1\u5bc6\u94a5
secretKey=priEn3UwXfJs3PmyXnSG
#GPU \u955c\u50cf
gpuImage=ubuntu-nvidia
#git\u7528\u6237\u540d\u53ca\u5bc6\u7801
gitUsername=edugit
gitPassword=xinedugit#
# mysql
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.56.101:3306/testbridge?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
jdbc.username=root
jdbc.password=123456
#novnc port
vncPort=6901

View File

@ -1,6 +1,7 @@
#Online
educoderURL=https://shixun.educoder.net/api/myshixuns/training_task_status.json
workspace=/data/workspace
educoderURL=https://www.educoder.net/myshixuns/training_task_status
simpileEducoderURL=https://www.educoder.net/myshixuns/code_runinng_message.json
workspace=/data2/workspace
## webssh
#webssh.configBakPath=/root/userYaml
@ -9,7 +10,7 @@ webssh.serverUrl=https://10.9.184.140:6443
webssh.userName=root
webssh.passwd=123123
## 命令行连接时的websocket地址
## \u547d\u4ee4\u884c\u8fde\u63a5\u65f6\u7684websocket\u5730\u5740
websocket.addr=wss://webssh.educoder.net/ws
#online
@ -29,35 +30,35 @@ redisAddress=127.0.0.1
redisPort=6379
redisAuth=
#正式版kubernetes用户名和密码
#\u6b63\u5f0f\u7248kubernetes\u7528\u6237\u540d\u548c\u5bc6\u7801
k8sServer=127.0.0.1:8080
k8sUser=testk8s
k8sPasswd=testk8s
#正式版dockerURL(主节点)
dockerMaster=http://10.9.184.140:4243
#正式版dockerURL(副节点)
dockerDeputies=http://10.9.105.90:4243;http://10.9.84.149:4243;http://10.9.46.46:4243;http://10.9.5.67:4243;http://10.9.144.249:4243;http://10.9.164.118:4243
#\u6b63\u5f0f\u7248dockerURL(\u4e3b\u8282\u70b9)
dockerMaster=http://10.9.5.67:4243
#\u6b63\u5f0f\u7248dockerURL(\u526f\u8282\u70b9)
dockerDeputies=http://10.9.164.118:4243;http://10.9.144.249:4243;http://10.9.46.46:4243
#镜像仓库地址
registry=10.9.105.90:5000
#\u955c\u50cf\u4ed3\u5e93\u5730\u5740
registry=10.9.164.118:5000
#正式版k8s可分配资源
#\u6b63\u5f0f\u7248k8s\u53ef\u5206\u914d\u8d44\u6e90
cpuAllocatable=24000
memAllocatable=46160
#IP
#git \u7248\u672c\u5e93IP
gitIP=10.9.62.218
gitBackUpIP=10.9.62.218
#编译结果最大长度
#\u7f16\u8bd1\u7ed3\u679c\u6700\u5927\u957f\u5ea6
outputSize=65535
#认证密钥
#\u8ba4\u8bc1\u5bc6\u94a5
secretKey=priEn3UwXfJs3PmyXnSG
#GPU 镜像
#GPU \u955c\u50cf
gpuImage=ubuntu-nvidia
#git用户名及密码
gitUsername=edugit
gitPassword=xinedugit#
#novnc port
vncPort=6901

View File

@ -1,19 +1,20 @@
educoderURL=https://testeduplus2.educoder.net/api/myshixuns/training_task_status.json
educoderURL=https://testbdweb.educoder.net/myshixuns/training_task_status.json
simpileEducoderURL=https://testbdweb.educoder.net/myshixuns/code_runinng_message.json
workspace=/data/workspace
## webssh
webssh.configBakPath=/root/userYaml
webssh.serverUrl=https://10.9.63.225:6443
webssh.serverUrl=https://10.9.81.28:6443
webssh.userName=root
webssh.passwd=123123
## 命令行连接时的websocket地址
## \u547d\u4ee4\u884c\u8fde\u63a5\u65f6\u7684websocket\u5730\u5740
websocket.addr=wss://testwebssh.educoder.net/ws
#the k8s server IP that can be accessed from internet
k8s.serverUrl=10.9.63.225
k8s.serverUrl=127.0.0.1
#to execute k8s cmds in slave node ,we have to provide the token
k8s.token=726b127bcf34784b
@ -28,36 +29,47 @@ redisAddress=127.0.0.1
redisPort=6379
redisAuth=
#测试版kubernetes用户名和密码
k8sServer=127.0.0.1:8080
#\u6d4b\u8bd5\u7248kubernetes\u7528\u6237\u540d\u548c\u5bc6\u7801
k8sServer=10.9.81.28:8080
k8sUser=testk8s
k8sPasswd=testk8s
#测试版资源总量
#\u6d4b\u8bd5\u7248\u8d44\u6e90\u603b\u91cf
cpuAllocatable=4000
memAllocatable=10000
#测试版dockerURL(主节点)
dockerMaster=http://10.9.63.225:54243
#测试版dockerURL(副节点)
dockerDeputies=http://10.9.29.180:54243
#\u6d4b\u8bd5\u7248dockerURL(\u4e3b\u8282\u70b9)
dockerMaster=http://10.9.81.28:54243
#\u6d4b\u8bd5\u7248dockerURL(\u526f\u8282\u70b9)
dockerDeputies=http://10.9.186.111:54243
#镜像仓库地址
registry=10.9.105.90:5000
#\u955c\u50cf\u4ed3\u5e93\u5730\u5740
registry=10.9.164.118:5000
#IP
gitIP=10.9.54.50
gitIP=10.9.73.116
gitBackUpIP=10.9.73.116
#编译结果最大长度
#\u7f16\u8bd1\u7ed3\u679c\u6700\u5927\u957f\u5ea6
outputSize=65535
#认证密钥
#\u8ba4\u8bc1\u5bc6\u94a5
secretKey=priEn3UwXfJs3PmyXnSG
#GPU 镜像
#GPU \u955c\u50cf
gpuImage=ubuntu-nvidia
#git用户名及密码
#git\u7528\u6237\u540d\u53ca\u5bc6\u7801
gitUsername=edugit
gitPassword=xinedugit#
gitPassword=xinedugit#
# mysql
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://10.9.70.25:3306/testbridge?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
jdbc.username=root
jdbc.password=Trust_#%01
#novnc port
vncPort=6901

View File

@ -0,0 +1,75 @@
educoderURL=https://testeduplus2.educoder.net/myshixuns/training_task_status.json
simpileEducoderURL=https://testeduplus2.educoder.net/myshixuns/code_runinng_message.json
workspace=/data/workspace
## webssh
webssh.configBakPath=/root/userYaml
webssh.serverUrl=https://10.9.81.28:6443
webssh.userName=root
webssh.passwd=123123
## \u547d\u4ee4\u884c\u8fde\u63a5\u65f6\u7684websocket\u5730\u5740
websocket.addr=wss://testwebssh2.educoder.net/ws
#the k8s server IP that can be accessed from internet
k8s.serverUrl=127.0.0.1
#to execute k8s cmds in slave node ,we have to provide the token
k8s.token=726b127bcf34784b
#limit of running pod number
maxRunningPodNum=20000
# defaultTimeLimit of executing time in a pod.
defaultTimeLimit=90
# redis
redisAddress=127.0.0.1
redisPort=6379
redisAuth=
#\u6d4b\u8bd5\u7248kubernetes\u7528\u6237\u540d\u548c\u5bc6\u7801
k8sServer=10.9.81.28:8080
k8sUser=testk8s
k8sPasswd=testk8s
#\u6d4b\u8bd5\u7248\u8d44\u6e90\u603b\u91cf
cpuAllocatable=4000
memAllocatable=10000
#\u6d4b\u8bd5\u7248dockerURL(\u4e3b\u8282\u70b9)
dockerMaster=http://10.9.81.28:54243
#\u6d4b\u8bd5\u7248dockerURL(\u526f\u8282\u70b9)
dockerDeputies=http://10.9.186.111:54243
#\u955c\u50cf\u4ed3\u5e93\u5730\u5740
registry=10.9.164.118:5000
#IP
gitIP=10.9.73.116
gitBackUpIP=10.9.73.116
#\u7f16\u8bd1\u7ed3\u679c\u6700\u5927\u957f\u5ea6
outputSize=65535
#\u8ba4\u8bc1\u5bc6\u94a5
secretKey=priEn3UwXfJs3PmyXnSG
#GPU \u955c\u50cf
gpuImage=ubuntu-nvidia
#git\u7528\u6237\u540d\u53ca\u5bc6\u7801
gitUsername=edugit
gitPassword=xinedugit#
# mysql
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://10.9.70.25:3306/testbridge?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
jdbc.username=root
jdbc.password=Trust_#%01
#novnc port
vncPort=6901

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialSize" value="10"></property>
<property name="maxActive" value="20"></property>
<property name="minIdle" value="10"></property>
</bean>
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage"
value="com.educoder.bridge.**.model"></property>
<property name="mapperLocations"
value="classpath*:mapper/*/*Mapper.xml"></property>
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<!-- 这里的几个配置主要演示如何使用,如果不理解,一定要去掉下面的配置 -->
<property name="properties">
<value>
helperDialect=mysql
reasonable=true
supportMethodsArguments=true
params=count=countSql
autoRuntimeDialect=true
</value>
</property>
</bean>
</array>
</property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName"
value="sqlSessionFactory"></property>
<property name="basePackage"
value="com.educoder.bridge.**.dao"></property>
</bean>
</beans>

View File

@ -0,0 +1,121 @@
#!/bin/bash
###日志函数开始
maxLogNum=10
logNum=1
eduLog() {
if [ $logNum -gt $maxLogNum ]
then
return
else
logNum=$[logNum+1]
fi
echo "educoder:"$1
}
###日志函数结束
###获取输出函数开始
getLogFile(){
if [ -z $evaLogFile ]
then
evaLogFile=$(cd `dirname $0`; pwd)"/eva.log";
fi
}
clearLogFile(){
getLogFile
rm -rf ${evaLogFile}
}
getPidnum(){
evaPidnum=0
pids=$(ps -ef | grep "$executeCommand" | grep -v "grep $executeCommand"| awk '{print $2}')
for pid in $pids
do
let evaPidnum=evaPidnum+1
done
}
readLine(){
linenumThisTime=0
readedLine=-1
while read LINE
do
let linenumThisTime=linenumThisTime+1
if [ $linenumThisTime -lt $linenum ]
then
continue
else
curline="$LINE"
readedLine=0
break
fi
done <${evaLogFile}
}
processLine() {
if [ ! $readedLine -eq 0 ];then
sleep 1s
else
match=$(echo $curline |grep -e "educoder:.*")
if [ ${#match} == 0 ]
then
alloutput="$alloutput""$curline""\n"
else
echo $curline
fi
let linenum=linenum+1
fi
}
getResult() {
linenum=1
alloutput=""
getPidnum
#eduLog "等待业务程序..。"$evaPidnum
while :
do
if [[ $evaPidnum -eq 0 ]]
then
if [[ -f ${evaLogFile} && (`cat ${evaLogFile} |wc -l` -gt 0) ]]
then
break
else
sleep 1s
#eduLog "继续等待业务程序..."
getPidnum
fi
else
if [[ -f ${evaLogFile} && (`cat ${evaLogFile} |wc -l` -gt 0) ]]
then
break
else
sleep 1s
#eduLog "继续等待业务程序..."
getPidnum
fi
fi
done
#eduLog "业务程序执行中..."$evaPidnum
getPidnum
while [[ $evaPidnum -eq 1 ]]
do
#eduLog "业务程序继续执行中..."$evaPidnum
readLine
processLine
sleep 1s
getPidnum
done
#eduLog "业务程序完成,读取剩余日志..."$evaPidnum
readLine
while [[ $readedLine -eq 0 ]]
do
processLine
readLine
done
result=$(echo -ne "$alloutput"|base64)
}
###获取输出函数结束
clearLogFile
source $(cd `dirname $0`; pwd)"/evaluate.sh" $1 $2

View File

@ -10,7 +10,7 @@
<appender name="bridge" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{MM-dd HH:mm:ss} [%thread] %-5level -- %msg%n</pattern>
<pattern>%d{MM-dd HH:mm:ss} [%X{sec_key}] [%thread] %-5level -- %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>

View File

@ -1,15 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<configuration scan="true" scanPeriod="10 minutes">
<property name="log_path" value="${catalina.home}/logs/"/>
<!-- 日志按天生成 -->
<appender name="bridge" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log_path}bridge.log</file>
<encoder>
<pattern>%d{MM-dd HH:mm:ss} [%thread] %-5level -- %msg%n</pattern>
<pattern>%d{MM-dd HH:mm:ss} [%X{sec_key}] [%thread] %-5level -- %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log_path}bridge.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>

View File

@ -1,15 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<configuration scan="true" scanPeriod="1 minutes">
<property name="log_path" value="${catalina.home}/logs/"/>
<!-- 日志按天生成 -->
<appender name="bridge" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log_path}bridge.log</file>
<encoder>
<pattern>%d{MM-dd HH:mm:ss} [%thread] %-5level -- %msg%n</pattern>
<pattern>%d{MM-dd HH:mm:ss} [%X{sec_key}] [%thread] %-5level -- %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log_path}bridge.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>

Some files were not shown because too many files have changed in this diff Show More