Commit 00467579 by Yiming Liu

Merge pull request #93 from lepdou/portal

规范portal异常处理
parents 0ac426a6 e856b5ad
...@@ -8,6 +8,7 @@ import com.ctrip.apollo.core.dto.ItemChangeSets; ...@@ -8,6 +8,7 @@ import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO; import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.dto.NamespaceDTO; import com.ctrip.apollo.core.dto.NamespaceDTO;
import com.ctrip.apollo.core.dto.ReleaseDTO; import com.ctrip.apollo.core.dto.ReleaseDTO;
import com.ctrip.apollo.core.exception.ServiceException;
import com.ctrip.apollo.core.utils.StringUtils; import com.ctrip.apollo.core.utils.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -145,8 +146,9 @@ public class AdminServiceAPI { ...@@ -145,8 +146,9 @@ public class AdminServiceAPI {
if (response != null && response.getStatusCode() == HttpStatus.OK){ if (response != null && response.getStatusCode() == HttpStatus.OK){
return response.getBody(); return response.getBody();
}else { }else {
logger.error("release fail.id:{}, env:{}, clusterName:{}, namespace:{},releaseBy{}",appId, env, clusterName, namespace, releaseBy); logger.error("createRelease fail.id:{}, env:{}, clusterName:{}, namespace:{},releaseBy{}",
return null; appId, env, clusterName, namespace, releaseBy);
throw new ServiceException("call create createRelease api error.");
} }
} }
} }
......
...@@ -5,15 +5,12 @@ import com.ctrip.apollo.Apollo; ...@@ -5,15 +5,12 @@ import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.core.dto.ReleaseDTO; import com.ctrip.apollo.core.dto.ReleaseDTO;
import com.ctrip.apollo.core.exception.BadRequestException; import com.ctrip.apollo.core.exception.BadRequestException;
import com.ctrip.apollo.core.utils.StringUtils; import com.ctrip.apollo.core.utils.StringUtils;
import com.ctrip.apollo.portal.entity.form.NamespaceModifyModel; import com.ctrip.apollo.portal.entity.form.NamespaceTextModel;
import com.ctrip.apollo.portal.entity.NamespaceVO; import com.ctrip.apollo.portal.entity.NamespaceVO;
import com.ctrip.apollo.portal.entity.SimpleMsg;
import com.ctrip.apollo.portal.entity.form.NamespaceReleaseModel; import com.ctrip.apollo.portal.entity.form.NamespaceReleaseModel;
import com.ctrip.apollo.portal.service.ConfigService; import com.ctrip.apollo.portal.service.ConfigService;
import com.ctrip.apollo.portal.service.txtresolver.TextResolverResult;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
...@@ -34,7 +31,7 @@ public class ConfigController { ...@@ -34,7 +31,7 @@ public class ConfigController {
public List<NamespaceVO> findNamespaces(@PathVariable String appId, @PathVariable String env, public List<NamespaceVO> findNamespaces(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName) { @PathVariable String clusterName) {
if (StringUtils.isContainEmpty(appId, env, clusterName)) { if (StringUtils.isContainEmpty(appId, env, clusterName)) {
throw new IllegalArgumentException("app id and cluster name can not be empty"); throw new BadRequestException("app id and cluster name can not be empty");
} }
return configService.findNampspaces(appId, Apollo.Env.valueOf(env), clusterName); return configService.findNampspaces(appId, Apollo.Env.valueOf(env), clusterName);
...@@ -42,9 +39,9 @@ public class ConfigController { ...@@ -42,9 +39,9 @@ public class ConfigController {
@RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = { @RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/items", method = RequestMethod.PUT, consumes = {
"application/json"}) "application/json"})
public ResponseEntity<SimpleMsg> modifyItems(@PathVariable String appId, @PathVariable String env, public ResponseEntity modifyItems(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName, @PathVariable String clusterName, @PathVariable String namespaceName,
@RequestBody NamespaceModifyModel model) { @RequestBody NamespaceTextModel model) {
if (model == null) { if (model == null) {
throw new BadRequestException("request payload shoud not be null"); throw new BadRequestException("request payload shoud not be null");
...@@ -58,18 +55,13 @@ public class ConfigController { ...@@ -58,18 +55,13 @@ public class ConfigController {
throw new BadRequestException("request model is invalid"); throw new BadRequestException("request model is invalid");
} }
TextResolverResult result = configService.resolveConfigText(model); configService.updateConfigItemByText(model);
return ResponseEntity.ok().build();
if (result.isResolveSuccess()) {
return ResponseEntity.ok().body(new SimpleMsg("success"));
} else {
return ResponseEntity.badRequest().body(new SimpleMsg(result.getMsg()));
}
} }
@RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/release", method = RequestMethod.POST, consumes = { @RequestMapping(value = "/apps/{appId}/env/{env}/clusters/{clusterName}/namespaces/{namespaceName}/release", method = RequestMethod.POST, consumes = {
"application/json"}) "application/json"})
public ResponseEntity<SimpleMsg> createRelease(@PathVariable String appId, public ReleaseDTO createRelease(@PathVariable String appId,
@PathVariable String env, @PathVariable String clusterName, @PathVariable String env, @PathVariable String clusterName,
@PathVariable String namespaceName, @RequestBody NamespaceReleaseModel model) { @PathVariable String namespaceName, @RequestBody NamespaceReleaseModel model) {
if (model == null) { if (model == null) {
...@@ -84,14 +76,8 @@ public class ConfigController { ...@@ -84,14 +76,8 @@ public class ConfigController {
throw new BadRequestException("request model is invalid"); throw new BadRequestException("request model is invalid");
} }
ReleaseDTO release = configService.release(model); return configService.createRelease(model);
if (release == null) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new SimpleMsg("oops! some error in server."));
} else {
return ResponseEntity.ok().body(new SimpleMsg("success"));
}
} }
} }
...@@ -4,7 +4,7 @@ package com.ctrip.apollo.portal.entity.form; ...@@ -4,7 +4,7 @@ package com.ctrip.apollo.portal.entity.form;
import com.ctrip.apollo.Apollo; import com.ctrip.apollo.Apollo;
import com.ctrip.apollo.core.utils.StringUtils; import com.ctrip.apollo.core.utils.StringUtils;
public class NamespaceModifyModel implements FormModel{ public class NamespaceTextModel implements FormModel{
private String appId; private String appId;
private String env; private String env;
......
...@@ -11,13 +11,13 @@ import com.ctrip.apollo.core.dto.ItemChangeSets; ...@@ -11,13 +11,13 @@ import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO; import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.dto.NamespaceDTO; import com.ctrip.apollo.core.dto.NamespaceDTO;
import com.ctrip.apollo.core.dto.ReleaseDTO; import com.ctrip.apollo.core.dto.ReleaseDTO;
import com.ctrip.apollo.core.exception.ServiceException;
import com.ctrip.apollo.core.utils.StringUtils; import com.ctrip.apollo.core.utils.StringUtils;
import com.ctrip.apollo.portal.api.AdminServiceAPI; import com.ctrip.apollo.portal.api.AdminServiceAPI;
import com.ctrip.apollo.portal.entity.form.NamespaceModifyModel; import com.ctrip.apollo.portal.entity.form.NamespaceTextModel;
import com.ctrip.apollo.portal.entity.NamespaceVO; import com.ctrip.apollo.portal.entity.NamespaceVO;
import com.ctrip.apollo.portal.entity.form.NamespaceReleaseModel; import com.ctrip.apollo.portal.entity.form.NamespaceReleaseModel;
import com.ctrip.apollo.portal.service.txtresolver.ConfigTextResolver; import com.ctrip.apollo.portal.service.txtresolver.ConfigTextResolver;
import com.ctrip.apollo.portal.service.txtresolver.TextResolverResult;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException; import java.io.IOException;
...@@ -86,20 +86,20 @@ public class ConfigService { ...@@ -86,20 +86,20 @@ public class ConfigService {
String namespaceName = namespace.getNamespaceName(); String namespaceName = namespace.getNamespaceName();
//latest release //latest createRelease
ReleaseDTO release = releaseAPI.loadLatestRelease(appId, env, clusterName, namespaceName); ReleaseDTO release = releaseAPI.loadLatestRelease(appId, env, clusterName, namespaceName);
Map<String, String> releaseItems = new HashMap<>(); Map<String, String> releaseItems = new HashMap<>();
if (release != null) { if (release != null) {
try { try {
releaseItems = objectMapper.readValue(release.getConfigurations(), Map.class); releaseItems = objectMapper.readValue(release.getConfigurations(), Map.class);
} catch (IOException e) { } catch (IOException e) {
logger.error("parse release json error. appId:{},env:{},clusterName:{},namespace:{}", appId, logger.error("parse createRelease json error. appId:{},env:{},clusterName:{},namespace:{}", appId,
env, clusterName, namespaceName); env, clusterName, namespaceName);
return namespaceVO; return namespaceVO;
} }
} }
//not release config items //not createRelease config items
List<ItemDTO> items = itemAPI.findItems(appId, env, clusterName, namespaceName); List<ItemDTO> items = itemAPI.findItems(appId, env, clusterName, namespaceName);
int modifiedItemCnt = 0; int modifiedItemCnt = 0;
for (ItemDTO itemDTO : items) { for (ItemDTO itemDTO : items) {
...@@ -135,7 +135,7 @@ public class ConfigService { ...@@ -135,7 +135,7 @@ public class ConfigService {
* parse config text and update config items * parse config text and update config items
* @return parse result * @return parse result
*/ */
public TextResolverResult resolveConfigText(NamespaceModifyModel model) { public void updateConfigItemByText(NamespaceTextModel model) {
String appId = model.getAppId(); String appId = model.getAppId();
Apollo.Env env = model.getEnv(); Apollo.Env env = model.getEnv();
String clusterName = model.getClusterName(); String clusterName = model.getClusterName();
...@@ -143,36 +143,16 @@ public class ConfigService { ...@@ -143,36 +143,16 @@ public class ConfigService {
long namespaceId = model.getNamespaceId(); long namespaceId = model.getNamespaceId();
String configText = model.getConfigText(); String configText = model.getConfigText();
TextResolverResult result = new TextResolverResult(); ItemChangeSets changeSets =
resolver.resolve(namespaceId, configText, itemAPI.findItems(appId, env, clusterName, namespaceName));
try { try {
result = resolver.resolve( namespaceId, configText, itemAPI.findItems(appId, env, clusterName, namespaceName));
} catch (Exception e) {
logger
.error("resolve config text error. app id:{}, env:{}, clusterName:{}, namespace:{}", appId, env, clusterName,
namespaceName, e);
result.setResolveSuccess(false);
result.setMsg("oops! server resolveConfigText config text error.");
return result;
}
if (result.isResolveSuccess()) {
try {
ItemChangeSets changeSets = result.getChangeSets();
changeSets.setModifyBy(model.getModifyBy()); changeSets.setModifyBy(model.getModifyBy());
enrichChangeSetBaseInfo(changeSets); enrichChangeSetBaseInfo(changeSets);
itemAPI.updateItems(appId, env, clusterName, namespaceName, changeSets); itemAPI.updateItems(appId, env, clusterName, namespaceName, changeSets);
} catch (Exception e) { } catch (Exception e) {
logger.error("resolve config text error. app id:{}, env:{}, clusterName:{}, namespace:{}", appId, env, throw new ServiceException("oops! call admin service config error. ");
clusterName, namespaceName, e);
result.setResolveSuccess(false);
result.setMsg("oops! server update config error.");
return result;
}
} else {
logger.warn("resolve config text error by format error. app id:{}, env:{}, clusterName:{}, namespace:{},cause:{}",
appId,env, clusterName, namespaceName, result.getMsg());
} }
return result;
} }
private void enrichChangeSetBaseInfo(ItemChangeSets changeSets){ private void enrichChangeSetBaseInfo(ItemChangeSets changeSets){
...@@ -182,10 +162,10 @@ public class ConfigService { ...@@ -182,10 +162,10 @@ public class ConfigService {
} }
/** /**
* release config items * createRelease config items
* @return * @return
*/ */
public ReleaseDTO release(NamespaceReleaseModel model){ public ReleaseDTO createRelease(NamespaceReleaseModel model){
return releaseAPI.release(model.getAppId(), model.getEnv(), model.getClusterName(), model.getNamespaceName(), return releaseAPI.release(model.getAppId(), model.getEnv(), model.getClusterName(), model.getNamespaceName(),
model.getReleaseBy(), model.getReleaseComment()); model.getReleaseBy(), model.getReleaseComment());
} }
......
package com.ctrip.apollo.portal.service.txtresolver; package com.ctrip.apollo.portal.service.txtresolver;
import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO; import com.ctrip.apollo.core.dto.ItemDTO;
import java.util.List; import java.util.List;
/** /**
* users can modify config in text mode.so need resolveConfigText text. * users can modify config in text mode.so need updateConfigItemByText text.
*/ */
public interface ConfigTextResolver { public interface ConfigTextResolver {
TextResolverResult resolve(long namespaceId, String configText, List<ItemDTO> baseItems); ItemChangeSets resolve(long namespaceId, String configText, List<ItemDTO> baseItems);
} }
...@@ -2,6 +2,7 @@ package com.ctrip.apollo.portal.service.txtresolver; ...@@ -2,6 +2,7 @@ package com.ctrip.apollo.portal.service.txtresolver;
import com.ctrip.apollo.core.dto.ItemChangeSets; import com.ctrip.apollo.core.dto.ItemChangeSets;
import com.ctrip.apollo.core.dto.ItemDTO; import com.ctrip.apollo.core.dto.ItemDTO;
import com.ctrip.apollo.core.exception.BadRequestException;
import com.ctrip.apollo.core.utils.StringUtils; import com.ctrip.apollo.core.utils.StringUtils;
import com.ctrip.apollo.common.utils.BeanUtils; import com.ctrip.apollo.common.utils.BeanUtils;
...@@ -25,13 +26,10 @@ public class PropertyResolver implements ConfigTextResolver { ...@@ -25,13 +26,10 @@ public class PropertyResolver implements ConfigTextResolver {
private static final String ITEM_SEPARATOR = "\n"; private static final String ITEM_SEPARATOR = "\n";
@Override @Override
public TextResolverResult resolve(long namespaceId, String configText, List<ItemDTO> baseItems) { public ItemChangeSets resolve(long namespaceId, String configText, List<ItemDTO> baseItems) {
TextResolverResult result = new TextResolverResult();
if (StringUtils.isEmpty(configText)){ if (StringUtils.isEmpty(configText)){
result.setResolveSuccess(false); throw new BadRequestException("config text can not be empty");
result.setMsg("config text can not be empty");
return result;
} }
Map<Integer, ItemDTO> oldLineNumMapItem = BeanUtils.mapByKey("lineNum", baseItems); Map<Integer, ItemDTO> oldLineNumMapItem = BeanUtils.mapByKey("lineNum", baseItems);
...@@ -43,13 +41,10 @@ public class PropertyResolver implements ConfigTextResolver { ...@@ -43,13 +41,10 @@ public class PropertyResolver implements ConfigTextResolver {
String[] newItems = configText.split(ITEM_SEPARATOR); String[] newItems = configText.split(ITEM_SEPARATOR);
if (isHasRepeatKey(newItems)){ if (isHasRepeatKey(newItems)){
result.setResolveSuccess(false); throw new BadRequestException("config text has repeat key please check.");
result.setMsg("config text has repeat key please check.");
return result;
} }
ItemChangeSets changeSets = new ItemChangeSets(); ItemChangeSets changeSets = new ItemChangeSets();
result.setChangeSets(changeSets);
Map<Integer, String> newLineNumMapItem = new HashMap();//use for delete blank and comment item Map<Integer, String> newLineNumMapItem = new HashMap();//use for delete blank and comment item
int lineCounter = 1; int lineCounter = 1;
for (String newItem : newItems) { for (String newItem : newItems) {
...@@ -69,9 +64,7 @@ public class PropertyResolver implements ConfigTextResolver { ...@@ -69,9 +64,7 @@ public class PropertyResolver implements ConfigTextResolver {
//normal item //normal item
} else { } else {
if (!handleNormalLine(namespaceId, oldKeyMapItem, newItem, lineCounter, result)) { handleNormalLine(namespaceId, oldKeyMapItem, newItem, lineCounter, changeSets);
return result;
}
} }
lineCounter++; lineCounter++;
...@@ -80,13 +73,12 @@ public class PropertyResolver implements ConfigTextResolver { ...@@ -80,13 +73,12 @@ public class PropertyResolver implements ConfigTextResolver {
deleteCommentAndBlankItem(oldLineNumMapItem, newLineNumMapItem, changeSets); deleteCommentAndBlankItem(oldLineNumMapItem, newLineNumMapItem, changeSets);
deleteNormalKVItem(oldKeyMapItem, changeSets); deleteNormalKVItem(oldKeyMapItem, changeSets);
result.setResolveSuccess(true); return changeSets;
return result;
} }
private boolean isHasRepeatKey(String[] newItems){ private boolean isHasRepeatKey(String[] newItems){
Set<String> keys = new HashSet<>(); Set<String> keys = new HashSet<>();
int lineCounter = 1;
int keyCount = 0; int keyCount = 0;
for (String item: newItems){ for (String item: newItems){
if (!isCommentItem(item) && !isBlankItem(item)){ if (!isCommentItem(item) && !isBlankItem(item)){
...@@ -94,8 +86,11 @@ public class PropertyResolver implements ConfigTextResolver { ...@@ -94,8 +86,11 @@ public class PropertyResolver implements ConfigTextResolver {
String[] kv = parseKeyValueFromItem(item); String[] kv = parseKeyValueFromItem(item);
if (kv != null) { if (kv != null) {
keys.add(kv[0]); keys.add(kv[0]);
}else {
throw new BadRequestException("line:" + lineCounter + " key value must separate by '='");
} }
} }
lineCounter ++;
} }
return keyCount > keys.size(); return keyCount > keys.size();
...@@ -127,17 +122,13 @@ public class PropertyResolver implements ConfigTextResolver { ...@@ -127,17 +122,13 @@ public class PropertyResolver implements ConfigTextResolver {
} }
} }
private boolean handleNormalLine(Long namespaceId, Map<String, ItemDTO> keyMapOldItem, String newItem, private void handleNormalLine(Long namespaceId, Map<String, ItemDTO> keyMapOldItem, String newItem,
int lineCounter, TextResolverResult result) { int lineCounter, ItemChangeSets changeSets) {
ItemChangeSets changeSets = result.getChangeSets();
String[] kv = parseKeyValueFromItem(newItem); String[] kv = parseKeyValueFromItem(newItem);
if (kv == null) { if (kv == null) {
result.setResolveSuccess(false); throw new BadRequestException("line:" + lineCounter + " key value must separate by '='");
result.setMsg(" line:" + lineCounter + " key value must separate by '='");
return false;
} }
String newKey = kv[0]; String newKey = kv[0];
...@@ -153,7 +144,6 @@ public class PropertyResolver implements ConfigTextResolver { ...@@ -153,7 +144,6 @@ public class PropertyResolver implements ConfigTextResolver {
lineCounter)); lineCounter));
} }
keyMapOldItem.remove(newKey); keyMapOldItem.remove(newKey);
return true;
} }
private boolean isCommentItem(ItemDTO item) { private boolean isCommentItem(ItemDTO item) {
......
package com.ctrip.apollo.portal.service.txtresolver;
import com.ctrip.apollo.core.dto.ItemChangeSets;
public class TextResolverResult {
private boolean isResolveSuccess;
/**
* error msg
*/
private String msg = "";
private ItemChangeSets changeSets;
public boolean isResolveSuccess() {
return isResolveSuccess;
}
public void setResolveSuccess(boolean resolveSuccess) {
isResolveSuccess = resolveSuccess;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public ItemChangeSets getChangeSets() {
return changeSets;
}
public void setChangeSets(ItemChangeSets changeSets) {
this.changeSets = changeSets;
}
}
...@@ -141,7 +141,7 @@ application_module.controller("AppConfigController", ...@@ -141,7 +141,7 @@ application_module.controller("AppConfigController",
$scope.toggleTextEditStatus($scope.draft); $scope.toggleTextEditStatus($scope.draft);
}, function (result) { }, function (result) {
toastr.error(result.data.msg, "更新失败"); toastr.error(result.data.message, "更新失败");
} }
); );
...@@ -189,7 +189,7 @@ application_module.controller("AppConfigController", ...@@ -189,7 +189,7 @@ application_module.controller("AppConfigController",
refreshNamespaces(); refreshNamespaces();
}, function (result) { }, function (result) {
toastr.error(result.data.msg, "发布失败"); toastr.error(result.data.message, "发布失败");
} }
); );
......
...@@ -250,7 +250,7 @@ ...@@ -250,7 +250,7 @@
</div> </div>
</div> </div>
<!--release modal--> <!--createRelease modal-->
<div class="modal fade" id="releaseModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel3"> <div class="modal fade" id="releaseModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel3">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment