diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java index 9c7a0b32..170ac8ec 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java @@ -6,7 +6,8 @@ import com.gitee.easyopen.annotation.ApiService; import com.gitee.easyopen.doc.annotation.ApiDoc; import com.gitee.easyopen.doc.annotation.ApiDocMethod; import com.gitee.sop.adminserver.api.service.param.ServiceAddParam; -import com.gitee.sop.adminserver.api.service.param.ServiceInstanceGrayParam; +import com.gitee.sop.adminserver.api.service.param.ServiceGrayConfigParam; +import com.gitee.sop.adminserver.api.service.param.ServiceIdParam; import com.gitee.sop.adminserver.api.service.param.ServiceInstanceParam; import com.gitee.sop.adminserver.api.service.param.ServiceSearchParam; import com.gitee.sop.adminserver.api.service.result.RouteServiceInfo; @@ -22,7 +23,11 @@ import com.gitee.sop.adminserver.common.ChannelOperation; import com.gitee.sop.adminserver.common.StatusEnum; import com.gitee.sop.adminserver.common.ZookeeperPathExistException; import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException; +import com.gitee.sop.adminserver.entity.ConfigGray; +import com.gitee.sop.adminserver.entity.ConfigGrayInstance; import com.gitee.sop.adminserver.entity.ConfigGrayUserkey; +import com.gitee.sop.adminserver.mapper.ConfigGrayInstanceMapper; +import com.gitee.sop.adminserver.mapper.ConfigGrayMapper; import com.gitee.sop.adminserver.mapper.ConfigGrayUserkeyMapper; import com.gitee.sop.registryapi.bean.ServiceInfo; import com.gitee.sop.registryapi.bean.ServiceInstance; @@ -57,6 +62,12 @@ public class ServiceApi { @Autowired private ConfigGrayUserkeyMapper configGrayUserkeyMapper; + @Autowired + private ConfigGrayMapper configGrayMapper; + + @Autowired + private ConfigGrayInstanceMapper configGrayInstanceMapper; + @Api(name = "zookeeper.service.list") @ApiDocMethod(description = "zk中的服务列表", elementClass = RouteServiceInfo.class) List listServiceInfo(ServiceSearchParam param) { @@ -189,7 +200,7 @@ public class ServiceApi { } } - @Api(name = "service.instance.env.pre") + @Api(name = "service.instance.env.pre.open") @ApiDocMethod(description = "预发布") void serviceEnvPre(ServiceInstanceParam param) throws IOException { try { @@ -201,35 +212,51 @@ public class ServiceApi { } } - @Api(name = "service.instance.env.gray") - @ApiDocMethod(description = "灰度发布") - void serviceEnvGray(ServiceInstanceGrayParam param) throws IOException { + @Api(name = "service.gray.config.get") + @ApiDocMethod(description = "灰度配置--获取") + ConfigGray serviceEnvGrayConfigGet(ServiceIdParam param) throws IOException { + String serviceId = param.getServiceId(); + return configGrayMapper.getByColumn("service_id", serviceId); + } + + @Api(name = "service.gray.config.save") + @ApiDocMethod(description = "灰度配置--保存") + void serviceEnvGrayConfigSave(ServiceGrayConfigParam param) throws IOException { + String serviceId = param.getServiceId(); + ConfigGray configGray = configGrayMapper.getByColumn("service_id", serviceId); + if (configGray == null) { + configGray = new ConfigGray(); + configGray.setServiceId(serviceId); + configGray.setNameVersionContent(param.getNameVersionContent()); + configGray.setUserKeyContent(param.getUserKeyContent()); + configGrayMapper.save(configGray); + } else { + configGray.setNameVersionContent(param.getNameVersionContent()); + configGray.setUserKeyContent(param.getUserKeyContent()); + configGrayMapper.update(configGray); + } + } + + @Api(name = "service.instance.env.gray.open") + @ApiDocMethod(description = "开启灰度发布") + void serviceEnvGray(ServiceInstanceParam param) throws IOException { try { - Boolean onlyUpdateGrayUserkey = param.getOnlyUpdateGrayUserkey(); - if (onlyUpdateGrayUserkey == null || !onlyUpdateGrayUserkey) { - MetadataEnum envPre = MetadataEnum.ENV_GRAY; - registryService.setMetadata(param.buildServiceInstance(), envPre.getKey(), envPre.getValue()); - } + MetadataEnum envPre = MetadataEnum.ENV_GRAY; + registryService.setMetadata(param.buildServiceInstance(), envPre.getKey(), envPre.getValue()); String serviceId = param.getServiceId(); String instanceId = param.getInstanceId(); - String userKeyContent = param.getUserKeyContent(); - String nameVersionContent = param.getNameVersionContent(); - ConfigGrayUserkey configGrayUserkey = configGrayUserkeyMapper.getByColumn("instance_id", instanceId); - if (configGrayUserkey == null) { - configGrayUserkey = new ConfigGrayUserkey(); - configGrayUserkey.setServiceId(serviceId); - configGrayUserkey.setInstanceId(instanceId); - configGrayUserkey.setUserKeyContent(userKeyContent); - configGrayUserkey.setNameVersionContent(nameVersionContent); - configGrayUserkey.setStatus(StatusEnum.STATUS_ENABLE.getStatus()); - configGrayUserkeyMapper.save(configGrayUserkey); + ConfigGrayInstance configGrayInstance = configGrayInstanceMapper.getByColumn("instance_id", instanceId); + if (configGrayInstance == null) { + configGrayInstance = new ConfigGrayInstance(); + configGrayInstance.setServiceId(serviceId); + configGrayInstance.setInstanceId(instanceId); + configGrayInstance.setStatus(StatusEnum.STATUS_ENABLE.getStatus()); + configGrayInstanceMapper.save(configGrayInstance); } else { - configGrayUserkey.setUserKeyContent(userKeyContent); - configGrayUserkey.setNameVersionContent(nameVersionContent); - configGrayUserkey.setStatus(StatusEnum.STATUS_ENABLE.getStatus()); - configGrayUserkeyMapper.update(configGrayUserkey); + configGrayInstance.setStatus(StatusEnum.STATUS_ENABLE.getStatus()); + configGrayInstanceMapper.update(configGrayInstance); } this.sendUserKeyMsg(instanceId, ChannelOperation.GRAY_USER_KEY_SET); } catch (Exception e) { @@ -245,10 +272,10 @@ public class ServiceApi { MetadataEnum envPre = MetadataEnum.ENV_ONLINE; registryService.setMetadata(param, envPre.getKey(), envPre.getValue()); - ConfigGrayUserkey configGrayUserkey = configGrayUserkeyMapper.getByColumn("instance_id", param.getInstanceId()); - if (configGrayUserkey != null && configGrayUserkey.getStatus() == StatusEnum.STATUS_ENABLE.getStatus()) { - configGrayUserkey.setStatus(StatusEnum.STATUS_DISABLE.getStatus()); - configGrayUserkeyMapper.update(configGrayUserkey); + ConfigGrayInstance configGrayInstance = configGrayInstanceMapper.getByColumn("instance_id", param.getInstanceId()); + if (configGrayInstance != null) { + configGrayInstance.setStatus(StatusEnum.STATUS_DISABLE.getStatus()); + configGrayInstanceMapper.update(configGrayInstance); } this.sendUserKeyMsg(param.getInstanceId(), ChannelOperation.GRAY_USER_KEY_CLEAR); } catch (Exception e) { diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceGrayConfigParam.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceGrayConfigParam.java new file mode 100644 index 00000000..87082a4f --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceGrayConfigParam.java @@ -0,0 +1,25 @@ +package com.gitee.sop.adminserver.api.service.param; + +import com.gitee.easyopen.doc.annotation.ApiDocField; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * @author tanghc + */ +@Data +public class ServiceGrayConfigParam { + @ApiDocField(description = "服务名serviceId") + @NotBlank(message = "serviceId不能为空") + private String serviceId; + + @ApiDocField(description = "灰度发布用户,多个用英文逗号隔开") + @NotBlank(message = "灰度发布用户不能为空") + private String userKeyContent; + + @ApiDocField(description = "灰度发布接口名版本号如:order.get1.0=1.2,多个用英文逗号隔开") + @NotBlank(message = "灰度发布接口名版本号不能为空") + private String nameVersionContent; + +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceIdParam.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceIdParam.java new file mode 100644 index 00000000..16bdbfbe --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceIdParam.java @@ -0,0 +1,16 @@ +package com.gitee.sop.adminserver.api.service.param; + +import com.gitee.easyopen.doc.annotation.ApiDocField; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * @author tanghc + */ +@Data +public class ServiceIdParam { + @ApiDocField(description = "serviceId") + @NotBlank(message = "serviceId不能为空") + private String serviceId; +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigGray.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigGray.java new file mode 100644 index 00000000..cc89f3e6 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigGray.java @@ -0,0 +1,42 @@ +package com.gitee.sop.adminserver.entity; + +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + + +/** + * 表名:config_gray + * 备注:服务灰度配置 + * + * @author tanghc + */ +@Table(name = "config_gray") +@Data +public class ConfigGray { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + /** 数据库字段:id */ + private Long id; + + /** 数据库字段:service_id */ + private String serviceId; + + /** 用户key,多个用引文逗号隔开, 数据库字段:user_key_content */ + private String userKeyContent; + + /** 需要灰度的接口,goods.get1.0=1.2,多个用英文逗号隔开, 数据库字段:name_version_content */ + private String nameVersionContent; + + /** 数据库字段:gmt_create */ + private Date gmtCreate; + + /** 数据库字段:gmt_modified */ + private Date gmtModified; +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigGrayInstance.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigGrayInstance.java new file mode 100644 index 00000000..171ba599 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigGrayInstance.java @@ -0,0 +1,41 @@ +package com.gitee.sop.adminserver.entity; + +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + + +/** + * 表名:config_gray_instance + * + * @author tanghc + */ +@Table(name = "config_gray_instance") +@Data +public class ConfigGrayInstance { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + /** 数据库字段:id */ + private Long id; + + /** instance_id, 数据库字段:instance_id */ + private String instanceId; + + /** service_id, 数据库字段:service_id */ + private String serviceId; + + /** 0:禁用,1:启用, 数据库字段:status */ + private Byte status; + + /** 数据库字段:gmt_create */ + private Date gmtCreate; + + /** 数据库字段:gmt_modified */ + private Date gmtModified; +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigGrayInstanceMapper.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigGrayInstanceMapper.java new file mode 100644 index 00000000..d2071bf7 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigGrayInstanceMapper.java @@ -0,0 +1,12 @@ +package com.gitee.sop.adminserver.mapper; + +import com.gitee.fastmybatis.core.mapper.CrudMapper; + +import com.gitee.sop.adminserver.entity.ConfigGrayInstance; + + +/** + * @author tanghc + */ +public interface ConfigGrayInstanceMapper extends CrudMapper { +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigGrayMapper.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigGrayMapper.java new file mode 100644 index 00000000..d1b35aa2 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigGrayMapper.java @@ -0,0 +1,12 @@ +package com.gitee.sop.adminserver.mapper; + +import com.gitee.fastmybatis.core.mapper.CrudMapper; + +import com.gitee.sop.adminserver.entity.ConfigGray; + + +/** + * @author tanghc + */ +public interface ConfigGrayMapper extends CrudMapper { +} diff --git a/sop-admin/sop-admin-vue/src/views/service/serviceList.vue b/sop-admin/sop-admin-vue/src/views/service/serviceList.vue index a9ea6b71..753f97f5 100644 --- a/sop-admin/sop-admin-vue/src/views/service/serviceList.vue +++ b/sop-admin/sop-admin-vue/src/views/service/serviceList.vue @@ -67,13 +67,14 @@ /> @@ -92,8 +93,8 @@ :rules="grayFormRules" size="mini" > - - {{ grayForm.serviceId + ' (' + grayForm.ipPort + ')' }} + + {{ grayForm.serviceId }} @@ -172,7 +173,7 @@ 取 消 - 确 定 + 确 定 @@ -199,8 +200,6 @@ export default { grayDialogVisible: false, grayForm: { serviceId: '', - instanceId: '', - ipPort: '', userKeyContent: '', onlyUpdateGrayUserkey: false, grayRouteConfigList: [] @@ -280,45 +279,79 @@ export default { }) }) }, - onEnvOnline: function(row) { - this.confirm('确定要上线【' + row.serviceId + '】吗?', function(done) { - this.post('service.instance.env.online', row, function() { - this.tip('上线成功') + doEnvOnline: function(row, callback) { + this.post('service.instance.env.online', row, function() { + callback && callback() + }) + }, + onEnvPreOpen: function(row) { + this.confirm(`确定要开启 ${row.instanceId} 预发布吗?`, function(done) { + this.post('service.instance.env.pre.open', { + serviceId: row.serviceId, + instanceId: row.instanceId + }, function() { + this.tip('预发布成功') done() }) }) }, - onEnvPre: function(row) { - this.confirm('确定要预发布【' + row.serviceId + '】吗?', function(done) { - this.post('service.instance.env.pre', row, function() { - this.tip('预发布成功') + onEnvPreClose: function(row) { + this.confirm(`确定要结束 ${row.instanceId} 预发布吗?`, function(done) { + this.doEnvOnline(row, function() { + this.tip('操作成功') done() }) }) }, - onEnvGray: function(row) { - this.grayForm.onlyUpdateGrayUserkey = false - this.openGrayDialog(row) + onEnvGrayOpen: function(row) { + this.confirm(`确定要开启 ${row.instanceId} 灰度吗?`, function(done) { + this.post('service.instance.env.gray.open', { + serviceId: row.serviceId, + instanceId: row.instanceId + }, function() { + this.tip('开启成功') + done() + }) + }) }, - onUpdateUserkey: function(row) { - this.grayForm.onlyUpdateGrayUserkey = true - this.openGrayDialog(row) + onEnvGrayClose: function(row) { + this.confirm(`确定要结束 ${row.instanceId} 灰度吗?`, function(done) { + this.doEnvOnline(row, function() { + this.tip('操作成功') + done() + }) + }) }, - openGrayDialog: function(row) { + onGrayConfigUpdate: function(row) { const serviceId = row.serviceId this.loadRouteList(serviceId) - this.post('service.instance.gray.userkey.get', { instanceId: row.instanceId }, function(resp) { + this.post('service.gray.config.get', { serviceId: serviceId }, function(resp) { this.grayDialogVisible = true const data = resp.data Object.assign(this.grayForm, { serviceId: serviceId, - instanceId: row.instanceId, - ipPort: row.ipPort, userKeyContent: data.userKeyContent || '', grayRouteConfigList: this.createGrayRouteConfigList(data.nameVersionContent) }) }) }, + onGrayConfigSave: function() { + this.$refs.grayForm.validate((valid) => { + if (valid) { + const nameVersionContents = [] + const grayRouteConfigList = this.grayForm.grayRouteConfigList + for (let i = 0; i < grayRouteConfigList.length; i++) { + const config = grayRouteConfigList[i] + nameVersionContents.push(config.oldRouteId + '=' + config.newVersion) + } + this.grayForm.nameVersionContent = nameVersionContents.join(',') + this.post('service.gray.config.save', this.grayForm, function() { + this.grayDialogVisible = false + this.tip('保存成功') + }) + } + }) + }, createGrayRouteConfigList: function(nameVersionContent) { if (!nameVersionContent) { return [{ @@ -340,23 +373,6 @@ export default { } return list }, - onAddUserKey: function() { - this.$refs.grayForm.validate((valid) => { - if (valid) { - const nameVersionContents = [] - const grayRouteConfigList = this.grayForm.grayRouteConfigList - for (let i = 0; i < grayRouteConfigList.length; i++) { - const config = grayRouteConfigList[i] - nameVersionContents.push(config.oldRouteId + '=' + config.newVersion) - } - this.grayForm.nameVersionContent = nameVersionContents.join(',') - this.post('service.instance.env.gray', this.grayForm, function() { - this.grayDialogVisible = false - this.tip('灰度发布发成功') - }) - } - }) - }, onChangeOldRoute: function(config) { config.newVersion = '' }, diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/loadbalancer/EnvironmentServerChooser.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/loadbalancer/EnvironmentServerChooser.java index b4ac5b44..905bb846 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/loadbalancer/EnvironmentServerChooser.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/loadbalancer/EnvironmentServerChooser.java @@ -60,7 +60,7 @@ public class EnvironmentServerChooser extends BaseServerChooser { } /** - * 能否进入灰度环境,可修改此方法实现自己想要的 + * 能否进入灰度环境 * * @param request request * @return 返回true:可以进入到预发环境 @@ -68,23 +68,12 @@ public class EnvironmentServerChooser extends BaseServerChooser { protected boolean canVisitGray(Server server, HttpServletRequest request) { ApiParam apiParam = ZuulContext.getApiParam(); DbEnvGrayManager userKeyManager = SpringContext.getBean(DbEnvGrayManager.class); - boolean canVisit = false; - /*if (this.isGrayUser(apiParam, userKeyManager, server, request)) { - // 指定灰度版本号 - String instanceId = server.getMetaInfo().getInstanceId(); - String newVersion = userKeyManager.getVersion(instanceId, apiParam.fetchNameVersion()); - if (newVersion != null) { - // 在header中设置新的版本号,然后微服务端先获取这个新版本号 - RequestContext.getCurrentContext().addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, newVersion); - canVisit = true; - } - }*/ return this.isGrayUser(apiParam, userKeyManager, server, request); } /** - * 是否是灰度用户 + * 是否是灰度用户,可修改此方法实现自己想要的 * * @param param 接口参数 * @param userKeyManager userKey管理