package com.ctrip.framework.apollo.portal.controller;
import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.utils.RequestPrecondition;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
import com.ctrip.framework.apollo.portal.entity.model.NamespaceReleaseModel;
import com.ctrip.framework.apollo.portal.entity.vo.ReleaseCompareResult;
import com.ctrip.framework.apollo.portal.entity.bo.ReleaseBO;
import com.ctrip.framework.apollo.portal.listener.ConfigPublishEvent;
import com.ctrip.framework.apollo.portal.service.ReleaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.access.prepost.PreAuthorize;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import static com.ctrip.framework.apollo.common.utils.RequestPrecondition.checkModel;
@RestController
public class ReleaseController {
@Autowired
private ReleaseService releaseService;
@Autowired
private ApplicationEventPublisher publisher;
@Autowired
private PortalConfig portalConfig;
@PreAuthorize(value = "@permissionValidator.hasReleaseNamespacePermission(#appId, #namespaceName)")
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/releases", method = RequestMethod.POST)
public ReleaseDTO createRelease(@PathVariable String appId,
@PathVariable String env, @PathVariable String clusterName,
@PathVariable String namespaceName, @RequestBody NamespaceReleaseModel model) {
checkModel(model != null);
model.setAppId(appId);
model.setEnv(env);
model.setClusterName(clusterName);
model.setNamespaceName(namespaceName);
if (model.isEmergencyPublish() && !portalConfig.isEmergencyPublishAllowed(Env.valueOf(env))) {
throw new BadRequestException(String.format("Env: %s is not supported emergency publish now", env));
}
ReleaseDTO createdRelease = releaseService.publish(model);
ConfigPublishEvent event = ConfigPublishEvent.instance();
event.withAppId(appId)
.withCluster(clusterName)
.withNamespace(namespaceName)
.withReleaseId(createdRelease.getId())
.setNormalPublishEvent(true)
.setEnv(Env.valueOf(env));
publisher.publishEvent(event);
return createdRelease;
}
@PreAuthorize(value = "@permissionValidator.hasReleaseNamespacePermission(#appId, #namespaceName)")
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/releases",
method = RequestMethod.POST)
public ReleaseDTO createGrayRelease(@PathVariable String appId,
@PathVariable String env, @PathVariable String clusterName,
@PathVariable String namespaceName, @PathVariable String branchName,
@RequestBody NamespaceReleaseModel model) {
checkModel(model != null);
model.setAppId(appId);
model.setEnv(env);
model.setClusterName(branchName);
model.setNamespaceName(namespaceName);
if (model.isEmergencyPublish() && !portalConfig.isEmergencyPublishAllowed(Env.valueOf(env))) {
throw new BadRequestException(String.format("Env: %s is not supported emergency publish now", env));
}
ReleaseDTO createdRelease = releaseService.publish(model);
ConfigPublishEvent event = ConfigPublishEvent.instance();
event.withAppId(appId)
.withCluster(clusterName)
.withNamespace(namespaceName)
.withReleaseId(createdRelease.getId())
.setGrayPublishEvent(true)
.setEnv(Env.valueOf(env));
publisher.publishEvent(event);
return createdRelease;
}
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/releases/all", method = RequestMethod.GET)
public List<ReleaseBO> findAllReleases(@PathVariable String appId,
@PathVariable String env,
@PathVariable String clusterName,
@PathVariable String namespaceName,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "5") int size) {
RequestPrecondition.checkNumberPositive(size);
RequestPrecondition.checkNumberNotNegative(page);
return releaseService.findAllReleases(appId, Env.valueOf(env), clusterName, namespaceName, page, size);
}
@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/releases/active", method = RequestMethod.GET)
public List<ReleaseDTO> findActiveReleases(@PathVariable String appId,
@PathVariable String env,
@PathVariable String clusterName,
@PathVariable String namespaceName,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "5") int size) {
RequestPrecondition.checkNumberPositive(size);
RequestPrecondition.checkNumberNotNegative(page);
return releaseService.findActiveReleases(appId, Env.valueOf(env), clusterName, namespaceName, page, size);
}
@RequestMapping(value = "/envs/{env}/releases/compare", method = RequestMethod.GET)
public ReleaseCompareResult compareRelease(@PathVariable String env,
@RequestParam long baseReleaseId,
@RequestParam long toCompareReleaseId) {
return releaseService.compare(Env.valueOf(env), baseReleaseId, toCompareReleaseId);
}
@RequestMapping(path = "/envs/{env}/releases/{releaseId}/rollback", method = RequestMethod.PUT)
public void rollback(@PathVariable String env,
@PathVariable long releaseId) {
releaseService.rollback(Env.valueOf(env), releaseId);
ReleaseDTO release = releaseService.findReleaseById(Env.valueOf(env), releaseId);
if (release == null) {
return;
}
ConfigPublishEvent event = ConfigPublishEvent.instance();
event.withAppId(release.getAppId())
.withCluster(release.getClusterName())
.withNamespace(release.getNamespaceName())
.withPreviousReleaseId(releaseId)
.setRollbackEvent(true)
.setEnv(Env.valueOf(env));
publisher.publishEvent(event);
}
}