Skip to content

Commit 59e0850

Browse files
author
qianjie
committed
1st PR -> feature: add gray operation on Open API
2nd PR -> bugfix: fix and reformat for the code review
1 parent 8d66ee6 commit 59e0850

File tree

12 files changed

+495
-33
lines changed

12 files changed

+495
-33
lines changed

apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ReleaseController.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,35 @@ public void rollback(@PathVariable("releaseId") long releaseId,
176176
Topics.APOLLO_RELEASE_TOPIC);
177177
}
178178

179+
@Transactional
180+
@RequestMapping(path = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/gray-del-releases", method = RequestMethod.POST)
181+
public ReleaseDTO publish(@PathVariable("appId") String appId,
182+
@PathVariable("clusterName") String clusterName,
183+
@PathVariable("namespaceName") String namespaceName,
184+
@RequestParam("operator") String operator,
185+
@RequestParam("releaseName") String releaseName,
186+
@RequestParam(name = "comment", required = false) String releaseComment,
187+
@RequestParam(name = "isEmergencyPublish", defaultValue = "false") boolean isEmergencyPublish,
188+
@RequestParam(name = "grayDelKeys") Set<String> grayDelKeys){
189+
Namespace namespace = namespaceService.findOne(appId, clusterName, namespaceName);
190+
if (namespace == null) {
191+
throw new NotFoundException(String.format("Could not find namespace for %s %s %s", appId,
192+
clusterName, namespaceName));
193+
}
194+
195+
Release release = releaseService.grayDeletionPublish(namespace, releaseName, releaseComment, operator, isEmergencyPublish, grayDelKeys);
196+
197+
//send release message
198+
Namespace parentNamespace = namespaceService.findParentNamespace(namespace);
199+
String messageCluster;
200+
if (parentNamespace != null) {
201+
messageCluster = parentNamespace.getClusterName();
202+
} else {
203+
messageCluster = clusterName;
204+
}
205+
messageSender.sendMessage(ReleaseMessageKeyGenerator.generate(appId, messageCluster, namespaceName),
206+
Topics.APOLLO_RELEASE_TOPIC);
207+
return BeanUtils.transfrom(ReleaseDTO.class, release);
208+
}
209+
179210
}

apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ReleaseService.java

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,49 @@ public Release publish(Namespace namespace, String releaseName, String releaseCo
185185
return release;
186186
}
187187

188+
private Release publishBranchNamespace(Namespace parentNamespace, Namespace childNamespace,
189+
Map<String, String> childNamespaceItems,
190+
String releaseName, String releaseComment,
191+
String operator, boolean isEmergencyPublish, Set<String> grayDelKeys) {
192+
Release parentLatestRelease = findLatestActiveRelease(parentNamespace);
193+
Map<String, String> parentConfigurations = parentLatestRelease != null ?
194+
gson.fromJson(parentLatestRelease.getConfigurations(),
195+
GsonType.CONFIG) : new HashMap<>();
196+
long baseReleaseId = parentLatestRelease == null ? 0 : parentLatestRelease.getId();
197+
198+
Map<String, String> configsToPublish = mergeConfiguration(parentConfigurations, childNamespaceItems);
199+
200+
if(!(grayDelKeys == null || grayDelKeys.size()==0)){
201+
for (String key : grayDelKeys){
202+
configsToPublish.remove(key);
203+
}
204+
}
205+
206+
return branchRelease(parentNamespace, childNamespace, releaseName, releaseComment,
207+
configsToPublish, baseReleaseId, operator,
208+
ReleaseOperation.GRAY_RELEASE, isEmergencyPublish);
209+
210+
}
211+
212+
@Transactional
213+
public Release grayDeletionPublish(Namespace namespace, String releaseName, String releaseComment,
214+
String operator, boolean isEmergencyPublish, Set<String> grayDelKeys) {
215+
216+
checkLock(namespace, isEmergencyPublish, operator);
217+
218+
Map<String, String> operateNamespaceItems = getNamespaceItems(namespace);
219+
220+
Namespace parentNamespace = namespaceService.findParentNamespace(namespace);
221+
222+
//branch release
223+
if (parentNamespace != null) {
224+
return publishBranchNamespace(parentNamespace, namespace, operateNamespaceItems,
225+
releaseName, releaseComment, operator, isEmergencyPublish, grayDelKeys);
226+
}else {
227+
throw new NotFoundException("Parent namespace not found");
228+
}
229+
}
230+
188231
private void checkLock(Namespace namespace, boolean isEmergencyPublish, String operator) {
189232
if (!isEmergencyPublish) {
190233
NamespaceLock lock = namespaceLockService.findLock(namespace.getId());
@@ -222,17 +265,8 @@ private Release publishBranchNamespace(Namespace parentNamespace, Namespace chil
222265
Map<String, String> childNamespaceItems,
223266
String releaseName, String releaseComment,
224267
String operator, boolean isEmergencyPublish) {
225-
Release parentLatestRelease = findLatestActiveRelease(parentNamespace);
226-
Map<String, String> parentConfigurations = parentLatestRelease != null ?
227-
gson.fromJson(parentLatestRelease.getConfigurations(),
228-
GsonType.CONFIG) : new HashMap<>();
229-
long baseReleaseId = parentLatestRelease == null ? 0 : parentLatestRelease.getId();
230-
231-
Map<String, String> childNamespaceToPublishConfigs = mergeConfiguration(parentConfigurations, childNamespaceItems);
232-
233-
return branchRelease(parentNamespace, childNamespace, releaseName, releaseComment,
234-
childNamespaceToPublishConfigs, baseReleaseId, operator,
235-
ReleaseOperation.GRAY_RELEASE, isEmergencyPublish);
268+
return publishBranchNamespace(parentNamespace, childNamespace, childNamespaceItems, releaseName, releaseComment,
269+
operator, isEmergencyPublish, null);
236270

237271
}
238272

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.ctrip.framework.apollo.openapi.dto;
2+
3+
import java.util.Set;
4+
5+
public class NamespaceGrayDelReleaseDTO extends NamespaceReleaseDTO {
6+
private Set<String> grayDelKeys;
7+
8+
public Set<String> getGrayDelKeys() {
9+
return grayDelKeys;
10+
}
11+
12+
public void setGrayDelKeys(Set<String> grayDelKeys) {
13+
this.grayDelKeys = grayDelKeys;
14+
}
15+
16+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.ctrip.framework.apollo.openapi.dto;
2+
3+
import java.util.Set;
4+
5+
public class OpenGrayReleaseRuleDTO extends BaseDTO{
6+
private String appId;
7+
8+
private String clusterName;
9+
10+
private String namespaceName;
11+
12+
private String branchName;
13+
14+
private Set<OpenGrayReleaseRuleItemDTO> ruleItems;
15+
16+
public String getAppId() {
17+
return appId;
18+
}
19+
20+
public void setAppId(String appId) {
21+
this.appId = appId;
22+
}
23+
24+
public String getClusterName() {
25+
return clusterName;
26+
}
27+
28+
public void setClusterName(String clusterName) {
29+
this.clusterName = clusterName;
30+
}
31+
32+
public String getNamespaceName() {
33+
return namespaceName;
34+
}
35+
36+
public void setNamespaceName(String namespaceName) {
37+
this.namespaceName = namespaceName;
38+
}
39+
40+
public String getBranchName() {
41+
return branchName;
42+
}
43+
44+
public void setBranchName(String branchName) {
45+
this.branchName = branchName;
46+
}
47+
48+
public Set<OpenGrayReleaseRuleItemDTO> getRuleItems() {
49+
return ruleItems;
50+
}
51+
52+
public void setRuleItems(Set<OpenGrayReleaseRuleItemDTO> ruleItems) {
53+
this.ruleItems = ruleItems;
54+
}
55+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.ctrip.framework.apollo.openapi.dto;
2+
3+
import java.util.Set;
4+
5+
public class OpenGrayReleaseRuleItemDTO {
6+
private String clientAppId;
7+
private Set<String> clientIpList;
8+
9+
public String getClientAppId() {
10+
return clientAppId;
11+
}
12+
13+
public void setClientAppId(String clientAppId) {
14+
this.clientAppId = clientAppId;
15+
}
16+
17+
public Set<String> getClientIpList() {
18+
return clientIpList;
19+
}
20+
21+
public void setClientIpList(Set<String> clientIpList) {
22+
this.clientIpList = clientIpList;
23+
}
24+
}

apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/util/OpenApiBeanUtils.java

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,20 @@
11
package com.ctrip.framework.apollo.openapi.util;
22

3+
import com.ctrip.framework.apollo.common.dto.*;
4+
import com.ctrip.framework.apollo.openapi.dto.*;
35
import com.google.common.base.Preconditions;
46
import com.google.common.reflect.TypeToken;
57
import com.google.gson.Gson;
68

7-
import com.ctrip.framework.apollo.common.dto.ItemDTO;
8-
import com.ctrip.framework.apollo.common.dto.NamespaceLockDTO;
9-
import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
109
import com.ctrip.framework.apollo.common.entity.AppNamespace;
1110
import com.ctrip.framework.apollo.common.utils.BeanUtils;
12-
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
13-
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
14-
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
15-
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceLockDTO;
16-
import com.ctrip.framework.apollo.openapi.dto.OpenReleaseDTO;
1711
import com.ctrip.framework.apollo.portal.entity.bo.ItemBO;
1812
import com.ctrip.framework.apollo.portal.entity.bo.NamespaceBO;
1913

2014
import org.springframework.util.CollectionUtils;
2115

2216
import java.lang.reflect.Type;
23-
import java.util.Collections;
24-
import java.util.LinkedList;
25-
import java.util.List;
26-
import java.util.Map;
17+
import java.util.*;
2718
import java.util.stream.Collectors;
2819

2920
public class OpenApiBeanUtils {
@@ -116,4 +107,43 @@ public static OpenNamespaceLockDTO transformFromNamespaceLockDTO(String namespac
116107
return lock;
117108
}
118109

110+
public static OpenGrayReleaseRuleDTO transformFromGrayReleaseRuleDTO(GrayReleaseRuleDTO grayReleaseRuleDTO){
111+
OpenGrayReleaseRuleDTO openGrayReleaseRuleDTO = new OpenGrayReleaseRuleDTO();
112+
openGrayReleaseRuleDTO.setAppId(grayReleaseRuleDTO.getAppId());
113+
openGrayReleaseRuleDTO.setBranchName(grayReleaseRuleDTO.getBranchName());
114+
openGrayReleaseRuleDTO.setClusterName(grayReleaseRuleDTO.getClusterName());
115+
openGrayReleaseRuleDTO.setNamespaceName(grayReleaseRuleDTO.getNamespaceName());
116+
117+
Set<GrayReleaseRuleItemDTO> grayReleaseRuleItemDTOSet = grayReleaseRuleDTO.getRuleItems();
118+
Set<OpenGrayReleaseRuleItemDTO> ruleItems = new HashSet<>();
119+
grayReleaseRuleItemDTOSet.forEach(grayReleaseRuleItemDTO -> {
120+
OpenGrayReleaseRuleItemDTO item = new OpenGrayReleaseRuleItemDTO();
121+
item.setClientAppId(grayReleaseRuleItemDTO.getClientAppId());
122+
item.setClientIpList(grayReleaseRuleItemDTO.getClientIpList());
123+
ruleItems.add(item);
124+
});
125+
openGrayReleaseRuleDTO.setRuleItems(ruleItems);
126+
127+
return openGrayReleaseRuleDTO;
128+
}
129+
130+
public static GrayReleaseRuleDTO transformToGrayReleaseRuleDTO(OpenGrayReleaseRuleDTO openGrayReleaseRuleDTO){
131+
String appId = openGrayReleaseRuleDTO.getAppId();
132+
String branchName = openGrayReleaseRuleDTO.getBranchName();
133+
String clusterName = openGrayReleaseRuleDTO.getClusterName();
134+
String namespaceName = openGrayReleaseRuleDTO.getNamespaceName();
135+
136+
GrayReleaseRuleDTO grayReleaseRuleDTO = new GrayReleaseRuleDTO(appId,clusterName,namespaceName,branchName);
137+
138+
Set<OpenGrayReleaseRuleItemDTO> openGrayReleaseRuleItemDTOSet = openGrayReleaseRuleDTO.getRuleItems();
139+
openGrayReleaseRuleItemDTOSet.forEach(openGrayReleaseRuleItemDTO ->{
140+
String clientAppId = openGrayReleaseRuleItemDTO.getClientAppId();
141+
Set<String> clientIpList = openGrayReleaseRuleItemDTO.getClientIpList();
142+
GrayReleaseRuleItemDTO ruleItem = new GrayReleaseRuleItemDTO(clientAppId, clientIpList);
143+
grayReleaseRuleDTO.addRuleItem(ruleItem);
144+
});
145+
146+
return grayReleaseRuleDTO;
147+
}
148+
119149
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package com.ctrip.framework.apollo.openapi.v1.controller;
2+
3+
/**
4+
* Created by qianjie on 8/10/17.
5+
*/
6+
7+
import com.ctrip.framework.apollo.common.dto.GrayReleaseRuleDTO;
8+
import com.ctrip.framework.apollo.common.dto.NamespaceDTO;
9+
import com.ctrip.framework.apollo.common.utils.BeanUtils;
10+
import com.ctrip.framework.apollo.core.enums.Env;
11+
import com.ctrip.framework.apollo.openapi.auth.ConsumerPermissionValidator;
12+
import com.ctrip.framework.apollo.openapi.dto.OpenGrayReleaseRuleDTO;
13+
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
14+
import com.ctrip.framework.apollo.openapi.util.OpenApiBeanUtils;
15+
import com.ctrip.framework.apollo.portal.component.PermissionValidator;
16+
import com.ctrip.framework.apollo.portal.entity.bo.NamespaceBO;
17+
import com.ctrip.framework.apollo.portal.service.NamespaceBranchService;
18+
import com.ctrip.framework.apollo.portal.service.ReleaseService;
19+
import org.springframework.beans.factory.annotation.Autowired;
20+
import org.springframework.security.access.AccessDeniedException;
21+
import org.springframework.security.access.prepost.PreAuthorize;
22+
import org.springframework.web.bind.annotation.*;
23+
24+
import javax.servlet.http.HttpServletRequest;
25+
26+
@RestController("openapiNamespaceBranchController")
27+
@RequestMapping("/openapi/v1/envs/{env}")
28+
public class NamespaceBranchController {
29+
30+
@Autowired
31+
private ConsumerPermissionValidator consumerPermissionValidator;
32+
@Autowired
33+
private ReleaseService releaseService;
34+
@Autowired
35+
private NamespaceBranchService namespaceBranchService;
36+
37+
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches", method = RequestMethod.GET)
38+
public OpenNamespaceDTO findBranch(@PathVariable String appId,
39+
@PathVariable String env,
40+
@PathVariable String clusterName,
41+
@PathVariable String namespaceName) {
42+
NamespaceBO namespaceBO = namespaceBranchService.findBranch(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName);
43+
if (namespaceBO == null) {
44+
return null;
45+
}
46+
return OpenApiBeanUtils.transformFromNamespaceBO(namespaceBO);
47+
}
48+
49+
@PreAuthorize(value = "@consumerPermissionValidator.hasCreateNamespacePermission(#request, #appId)")
50+
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches", method = RequestMethod.POST)
51+
public OpenNamespaceDTO createBranch(@PathVariable String appId,
52+
@PathVariable String env,
53+
@PathVariable String clusterName,
54+
@PathVariable String namespaceName,
55+
@RequestParam("operator") String operator,
56+
HttpServletRequest request) {
57+
NamespaceDTO namespaceDTO = namespaceBranchService.createBranch(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName, operator);
58+
if (namespaceDTO == null) {
59+
return null;
60+
}
61+
return BeanUtils.transfrom(OpenNamespaceDTO.class, namespaceDTO);
62+
}
63+
64+
@PreAuthorize(value = "@consumerPermissionValidator.hasModifyNamespacePermission(#request, #appId, #namespaceName, #env)")
65+
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}", method = RequestMethod.DELETE)
66+
public void deleteBranch(@PathVariable String appId,
67+
@PathVariable String env,
68+
@PathVariable String clusterName,
69+
@PathVariable String namespaceName,
70+
@PathVariable String branchName,
71+
@RequestParam("operator") String operator,
72+
HttpServletRequest request) {
73+
boolean canDelete = consumerPermissionValidator.hasReleaseNamespacePermission(request, appId, namespaceName, env) ||
74+
(consumerPermissionValidator.hasModifyNamespacePermission(request, appId, namespaceName, env) &&
75+
releaseService.loadLatestRelease(appId, Env.valueOf(env), branchName, namespaceName) == null);
76+
77+
if (!canDelete) {
78+
throw new AccessDeniedException("Forbidden operation. "
79+
+ "Caused by: 1.you don't have release permission "
80+
+ "or 2. you don't have modification permission "
81+
+ "or 3. you have modification permission but branch has been released");
82+
}
83+
namespaceBranchService.deleteBranch(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName, branchName, operator);
84+
85+
}
86+
87+
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules", method = RequestMethod.GET)
88+
public OpenGrayReleaseRuleDTO getBranchGrayRules(@PathVariable String appId, @PathVariable String env,
89+
@PathVariable String clusterName,
90+
@PathVariable String namespaceName,
91+
@PathVariable String branchName) {
92+
GrayReleaseRuleDTO grayReleaseRuleDTO = namespaceBranchService.findBranchGrayRules(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName, branchName);
93+
if (grayReleaseRuleDTO == null) {
94+
return null;
95+
}
96+
return OpenApiBeanUtils.transformFromGrayReleaseRuleDTO(grayReleaseRuleDTO);
97+
}
98+
99+
@PreAuthorize(value = "@consumerPermissionValidator.hasModifyNamespacePermission(#request, #appId, #namespaceName, #env)")
100+
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/rules", method = RequestMethod.PUT)
101+
public void updateBranchRules(@PathVariable String appId, @PathVariable String env,
102+
@PathVariable String clusterName, @PathVariable String namespaceName,
103+
@PathVariable String branchName, @RequestBody OpenGrayReleaseRuleDTO rules,
104+
@RequestParam("operator") String operator,
105+
HttpServletRequest request) {
106+
GrayReleaseRuleDTO grayReleaseRuleDTO = OpenApiBeanUtils.transformToGrayReleaseRuleDTO(rules);
107+
namespaceBranchService
108+
.updateBranchGrayRules(appId, Env.valueOf(env.toUpperCase()), clusterName, namespaceName, branchName, grayReleaseRuleDTO, operator);
109+
110+
}
111+
}

0 commit comments

Comments
 (0)