初始化项目代码

This commit is contained in:
dengqichen 2024-08-13 10:11:16 +08:00
parent fa56e48a48
commit 22016b35d3
95 changed files with 3184 additions and 0 deletions

14
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
/vcs.xml
/compiler.xml
/encodings.xml
/jarRepositories.xml
/misc.xml
/uiDesigner.xml

8
README.md Normal file
View File

@ -0,0 +1,8 @@
# 启动参数
````
-DNACOS_CONFIG_SERVER=192.168.105.1:8848
-DTENANT_CODE=longi
-DDEPLOY_ENV=deploy-ease-dev
-DNACOS_USER=nacos
-DNACOS_PWD=nacos
````

27
deploy-ease-api/pom.xml Normal file
View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>deploy-ease-api</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<parent>
<groupId>com.qc.soft</groupId>
<artifactId>deploy-ease</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
</project>

View File

@ -0,0 +1,21 @@
package com.qc.soft.deploy.ease.api.controller;
import com.qc.soft.deploy.ease.api.response.DictionaryResponse;
import com.qc.soft.deploy.ease.api.response.TenantDictionaryResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/deploy-ease/dict")
public interface IDictionaryController {
@GetMapping("/system")
List<DictionaryResponse> systemDicts();
@GetMapping("/tenant")
List<TenantDictionaryResponse> tenantDicts();
}

View File

@ -0,0 +1,11 @@
package com.qc.soft.deploy.ease.api.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/deploy-ease/jenkins")
public interface IJenkinsController {
}

View File

@ -0,0 +1,30 @@
package com.qc.soft.deploy.ease.api.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/deploy-ease/k8s")
public interface IK8sController {
// @GetMapping("namespaces")
// List<K8sNamespaceResponse> namespaces();
//
// @GetMapping("deployments/{namespace}")
// List<K8sDeploymentResponse> deployments(@PathVariable String namespace);
//
// @GetMapping("/pods/{namespace}/{deploymentName}")
// List<K8sPodResponse> pods(@PathVariable String namespace, @PathVariable String deploymentName);
//
// @GetMapping("/pods/{namespace}")
// List<K8sPodResponse> pods(@PathVariable String namespace) ;
//
// @GetMapping(value = "/pod/log/{namespace}/{podName}", produces = "text/plain;charset=UTF-8")
// String getPodLog(@PathVariable String namespace, @PathVariable String podName);
//
//
// @GetMapping("/kube/config")
// String getKubeConfig() ;
}

View File

@ -0,0 +1,9 @@
package com.qc.soft.deploy.ease.api.controller;
public interface INacosController {
void instances();
}

View File

@ -0,0 +1,18 @@
package com.qc.soft.deploy.ease.api.controller;
import com.qc.soft.deploy.ease.api.response.ProjectResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/deploy-ease/project")
public interface IProjectController {
@GetMapping("/list")
List<ProjectResponse> list();
}

View File

@ -0,0 +1,14 @@
package com.qc.soft.deploy.ease.api.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/deploy-ease/test")
public interface ITestController {
@GetMapping("test")
void test();
}

View File

@ -0,0 +1,15 @@
package com.qc.soft.deploy.ease.api.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/deploy-ease/user")
public interface IUserController {
@GetMapping("/login")
boolean login(String userName, String password);
}

View File

@ -0,0 +1,21 @@
package com.qc.soft.deploy.ease.api.response;
import lombok.Data;
import java.io.Serializable;
@Data
public class DictionaryResponse implements Serializable {
private String code;
private String name;
private String value;
private boolean status;
private boolean tenantSharing;
}

View File

@ -0,0 +1,16 @@
package com.qc.soft.deploy.ease.api.response;
import lombok.Data;
import java.io.Serializable;
@Data
public class ProjectResponse implements Serializable {
private String projectCode;
private String projectName;
private String tenantCode;
}

View File

@ -0,0 +1,18 @@
package com.qc.soft.deploy.ease.api.response;
import lombok.Data;
@Data
public class TenantDictionaryResponse {
private String code;
private String name;
private String value;
private boolean status;
private String tenantCode;
}

152
deploy-ease-core/pom.xml Normal file
View File

@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>deploy-ease-core</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- MySQL 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-jdbc</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>${spring-statemachine.version}</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>${reactor-core.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>${transmittable-thread-local.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.mybatis.spring.boot</groupId>-->
<!-- <artifactId>mybatis-spring-boot-starter</artifactId>-->
<!-- <version>2.3.1</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.mybatis</groupId>-->
<!-- <artifactId>mybatis-spring</artifactId>-->
<!-- <version>2.1.1</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>${http5.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>${kubernetes.version}</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson-version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp3.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>com.qc.soft</groupId>
<artifactId>deploy-ease-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
</dependencies>
<parent>
<groupId>com.qc.soft</groupId>
<artifactId>deploy-ease</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
</project>

View File

@ -0,0 +1,20 @@
package com.qc.soft.deploy.ease;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.qc.soft.deploy.ease.*")
//@MapperScan("com.qc.soft.longi.deployment.dao")
//@EnableScheduling
@EnableAsync
public class DeployEaseApplication {
public static void main(String[] args) {
SpringApplication.run(DeployEaseApplication.class, args);
}
}

View File

@ -0,0 +1,54 @@
package com.qc.soft.deploy.ease.config;
import com.qc.soft.deploy.ease.enums.BusinessErrorCode;
import lombok.Builder;
import lombok.ToString;
import java.io.Serializable;
import java.util.StringJoiner;
@Builder
@ToString
public class ApiResponse<T> implements Serializable {
private BusinessErrorCode code;
private String message;
private T data;
public ApiResponse(BusinessErrorCode code, String message) {
this.code = code;
this.message = message;
}
public ApiResponse(BusinessErrorCode code, String message, T data) {
this(code, message);
this.data = data;
}
public BusinessErrorCode getCode() {
return code;
}
public void setCode(BusinessErrorCode code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}

View File

@ -0,0 +1,53 @@
package com.qc.soft.deploy.ease.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid() {
return new DruidDataSource();
}
//配置 Druid 监控管理后台的Servlet
//内置 Servlet 容器时没有web.xml文件所以使用 Spring Boot 的注册 Servlet 方式
@Bean
public ServletRegistrationBean statViewServlet() {
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
// 这些参数可以在 com.alibaba.druid.support.http.StatViewServlet 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到
Map<String, String> initParams = new HashMap<>();
initParams.put("loginUsername", "admin");
initParams.put("loginPassword", "123456");
initParams.put("allow", ""); //默认就是允许所有访问
//denyDruid 后台拒绝谁访问表示禁止此ip访问
// initParams.put("deny","192.168.10.132");
bean.setInitParameters(initParams);
return bean;
}
//2配置一个web监控的filter
@Bean
public FilterRegistrationBean webStatFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String, String> initParams = new HashMap<>();
initParams.put("exclusions", "*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}

View File

@ -0,0 +1,23 @@
package com.qc.soft.deploy.ease.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class GlobalCorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 允许跨域的路径
.allowedOrigins("*") // 允许跨域请求的域名
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法
.allowedHeaders("*") // 允许的请求头
.allowCredentials(true); // 是否允许证书cookies
}
};
}
}

View File

@ -0,0 +1,25 @@
package com.qc.soft.deploy.ease.config;
import com.qc.soft.deploy.ease.enums.ResponseCode;
import com.qc.soft.deploy.ease.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@Autowired
private HttpServletRequest httpServletRequest;
@ExceptionHandler(BusinessException.class)
public ApiResponse parameterBodyMissingExceptionHandler(BusinessException exception) {
String requestURI = httpServletRequest.getRequestURI();
log.error("An exception occurred while requesting an interface{}", requestURI, exception);
return ApiResponse.builder().code(exception.getCode()).message(exception.getMessage()).build();
}
}

View File

@ -0,0 +1,35 @@
package com.qc.soft.deploy.ease.config;
import com.qc.soft.deploy.ease.enums.ResponseCode;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@ControllerAdvice
public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, org.springframework.http.server.ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof ResponseEntity) {
return body;
}
if (body instanceof String) {
return body;
}
if (body == null) {
return ApiResponse.builder().code(ResponseCode.SUCCESS.getCode()).message(ResponseCode.SUCCESS.getMessage()).build();
}
if (body instanceof ApiResponse) {
return body;
}
return ApiResponse.builder().data(body).code(ResponseCode.SUCCESS.getCode()).message(ResponseCode.SUCCESS.getMessage()).build();
}
}

View File

@ -0,0 +1,77 @@
package com.qc.soft.deploy.ease.config;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.util.Config;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import java.util.ArrayList;
import java.util.List;
@Configuration
@Slf4j
@Order(value = 100)
public class K8sRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware {
private ApiClient apiClient;
private ApplicationContext applicationContext;
private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
initK8sApiClient(registry);
// registerDeploymentHolder(registry);
}
private void initK8sApiClient(BeanDefinitionRegistry registry) {
log.info("Start registering the k8s client!!!");
try {
Resource[] resources = resolver.getResources("classpath:/./kube/*");
for (Resource resource : resources) {
if (!resource.isReadable() && StringUtils.isNotEmpty(resource.getFilename())) {
continue;
}
this.apiClient = Config.fromConfig(resource.getInputStream());
BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(ApiClient.class, () -> apiClient).getBeanDefinition();
registry.registerBeanDefinition("k8sApiClient", beanDefinition);
break;
}
} catch (Exception e) {
log.error("k8s client registration failed!!!", e);
throw new RuntimeException(e);
}
}
@Override
public void afterPropertiesSet() {
Environment environment = applicationContext.getEnvironment();
// this.k8sBoundNamespaces = environment.getProperty("devops.k8s.namespaces", List.class);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}

View File

@ -0,0 +1,40 @@
package com.qc.soft.deploy.ease.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.qc.soft.deploy.ease.interceptor.TenantInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.List;
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Resource
private TenantInterceptor tenantInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tenantInterceptor).addPathPatterns("/**");
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
mapper.registerModule(new JavaTimeModule());
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
converters.add(new MappingJackson2HttpMessageConverter(mapper));
super.configureMessageConverters(converters);
}
}

View File

@ -0,0 +1,19 @@
package com.qc.soft.deploy.ease.context;
import com.alibaba.ttl.TransmittableThreadLocal;
public class TenantContext {
private static final TransmittableThreadLocal<String> currentTenant = new TransmittableThreadLocal<>();
public static void setCurrentTenant(String tenant) {
currentTenant.set(tenant);
}
public static String getCurrentTenant() {
return currentTenant.get();
}
public static void clear() {
currentTenant.remove();
}
}

View File

@ -0,0 +1,26 @@
package com.qc.soft.deploy.ease.controller;
import com.qc.soft.deploy.ease.api.controller.INacosController;
import com.qc.soft.deploy.ease.service.INacosService;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/deploy-ease/nacos")
public class NacosController implements INacosController {
@Resource
private INacosService nacosService;
@Override
@GetMapping("/instances")
public void instances() {
nacosService.instances();
}
}

View File

@ -0,0 +1,23 @@
package com.qc.soft.deploy.ease.convert;
import com.qc.soft.deploy.ease.k8s.K8sNamespaceResponse;
import io.kubernetes.client.openapi.models.V1Namespace;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface K8sNamespaceConvert {
K8sNamespaceConvert INSTANCE = Mappers.getMapper(K8sNamespaceConvert.class);
@Mappings({@Mapping(source = "metadata.name", target = "name"),})
K8sNamespaceResponse toK8sNamespaceResponse(V1Namespace namespace);
List<K8sNamespaceResponse> toK8sNamespaceList(List<V1Namespace> namespaces);
}

View File

@ -0,0 +1,29 @@
package com.qc.soft.deploy.ease.convert;
import com.qc.soft.deploy.ease.k8s.K8sPodResponse;
import io.kubernetes.client.openapi.models.V1Pod;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@Mapper
public interface K8sPodConvert {
K8sPodConvert INSTANCE = Mappers.getMapper(K8sPodConvert.class);
@Mappings({
@Mapping(source = "v1Pod.metadata.namespace", target = "namespace"),
@Mapping(source = "v1Pod.metadata.name", target = "name"),
@Mapping(target = "v1Pod.imageName", expression = "java(v1Pod.getSpec().getContainers().get(0).getImage())"),
@Mapping(target = "deploymentName", source = "deploymentName"),
@Mapping(target = "container", expression = "java(v1Pod.getSpec().getContainers().get(0).getName())"),
@Mapping(target = "creationTimestamp", source = "v1Pod.metadata.creationTimestamp"),
@Mapping(target = "restartCount", expression = "java(v1Pod.getStatus().getContainerStatuses() == null ? 0 : v1Pod.getStatus().getContainerStatuses().get(0).getRestartCount())"),
@Mapping(target = "limits", expression = "java(v1Pod.getSpec().getContainers().get(0).getResources().getLimits() == null ? null : v1Pod.getSpec().getContainers().get(0).getResources().getLimits().get(\"memory\").getNumber())"),
@Mapping(target = "requests", expression = "java(v1Pod.getSpec().getContainers().get(0).getResources().getRequests() == null ? null : v1Pod.getSpec().getContainers().get(0).getResources().getRequests().get(\"memory\").getNumber())")
})
K8sPodResponse toK8sPodResponse(V1Pod v1Pod, String deploymentName);
}

View File

@ -0,0 +1,18 @@
package com.qc.soft.deploy.ease.convert.api.response;
import com.qc.soft.deploy.ease.api.response.DictionaryResponse;
import com.qc.soft.deploy.ease.entity.Dictionary;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface DictionaryApiResponseConvert {
DictionaryApiResponseConvert INSTANCE = Mappers.getMapper(DictionaryApiResponseConvert.class);
List<DictionaryResponse> entityToResponse(List<Dictionary> dictionaries);
}

View File

@ -0,0 +1,18 @@
package com.qc.soft.deploy.ease.convert.api.response;
import com.qc.soft.deploy.ease.api.response.ProjectResponse;
import com.qc.soft.deploy.ease.entity.Project;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface ProjectApiResponseConvert {
ProjectApiResponseConvert INSTANCE = Mappers.getMapper(ProjectApiResponseConvert.class);
List<ProjectResponse> entityToResponse(List<Project> projects);
}

View File

@ -0,0 +1,18 @@
package com.qc.soft.deploy.ease.convert.api.response;
import com.qc.soft.deploy.ease.api.response.TenantDictionaryResponse;
import com.qc.soft.deploy.ease.entity.TenantDictionary;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface TenantDictionaryApiResponseConvert {
TenantDictionaryApiResponseConvert INSTANCE = Mappers.getMapper(TenantDictionaryApiResponseConvert.class);
List<TenantDictionaryResponse> entityToResponse(List<TenantDictionary> dictionaries);
}

View File

@ -0,0 +1,23 @@
package com.qc.soft.deploy.ease.convert.dto;
import com.qc.soft.deploy.ease.convert.K8sNamespaceConvert;
import com.qc.soft.deploy.ease.entity.Dictionary;
import com.qc.soft.deploy.ease.entity.TenantDictionary;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@Mapper
public interface DictionaryConvert {
DictionaryConvert INSTANCE = Mappers.getMapper(DictionaryConvert.class);
@Mappings(
@Mapping(target = "tenantCode", expression = "java(com.qc.soft.deploy.ease.context.TenantContext.getCurrentTenant())")
)
TenantDictionary systemDictionaryToTenantDictionary(Dictionary dictionary);
}

View File

@ -0,0 +1,28 @@
package com.qc.soft.deploy.ease.entity;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.time.LocalDateTime;
@MappedSuperclass
public abstract class BaseEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, updatable = false)
private LocalDateTime createTime;
@Column(nullable = false)
private LocalDateTime updateTime;
private Boolean isDeleted;
}

View File

@ -0,0 +1,35 @@
package com.qc.soft.deploy.ease.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
@EqualsAndHashCode(callSuper = true)
@Table(name = "dictionary")
@Entity
@Data
public class Dictionary extends BaseEntity {
@Column(name = "dictionary_code")
private String code;
@Column(name = "dictionary_name")
private String name;
@Column(name = "dictionary_value")
private String value;
private boolean status;
@Column(name = "tenant_sharing")
private boolean tenantSharing;
}

View File

@ -0,0 +1,26 @@
package com.qc.soft.deploy.ease.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
@EqualsAndHashCode(callSuper = true)
@Table(name = "project")
@Entity
@Data
public class Project extends BaseEntity {
@Column(name = "project_code")
private String projectCode;
@Column(name = "project_name")
private String projectName;
@Column(name = "tenant_code")
private String tenantCode;
}

View File

@ -0,0 +1,25 @@
package com.qc.soft.deploy.ease.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
@EqualsAndHashCode(callSuper = true)
@Table(name = "tenant")
@Entity
@Data
public class Tenant extends BaseEntity {
@Column(name = "tenant_code")
private String tenantCode;
@Column(name = "tenant_name")
private String tenantName;
private boolean enabled;
}

View File

@ -0,0 +1,31 @@
package com.qc.soft.deploy.ease.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
@EqualsAndHashCode(callSuper = true)
@Table(name = "tenant_dictionary")
@Entity
@Data
public class TenantDictionary extends BaseEntity {
@Column(name = "dictionary_code")
private String code;
@Column(name = "dictionary_name")
private String name;
@Column(name = "dictionary_value")
private String value;
private boolean status;
@Column(name = "tenant_code")
private String tenantCode;
}

View File

@ -0,0 +1,29 @@
package com.qc.soft.deploy.ease.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
@EqualsAndHashCode(callSuper = true)
@Table(name = "user")
@Entity
@Data
public class User extends BaseEntity {
@Column(name = "user_name")
private String username;
private String password;
private String realName;
}

View File

@ -0,0 +1,21 @@
package com.qc.soft.deploy.ease.enums;
public enum BusinessErrorCode {
SUCCESS("操作成功"),
FAILURE("操作失败"),
TENANT_DOES_NOT_EXIST("租户不存在"),
TENANT_NOT_ENABLED("%s租户未启用");
private String message;
BusinessErrorCode(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}

View File

@ -0,0 +1,21 @@
package com.qc.soft.deploy.ease.enums;
import lombok.Getter;
@Getter
public enum JenkinsJobStatus {
WAITING_BUILD("等待构建"),
BUILDING("构建中"),
BUILD_END("构建完成");
private final String message;
JenkinsJobStatus(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}

View File

@ -0,0 +1,21 @@
package com.qc.soft.deploy.ease.enums;
import lombok.Getter;
@Getter
public enum ResponseCode {
SUCCESS(BusinessErrorCode.SUCCESS, BusinessErrorCode.SUCCESS.getMessage()),
FAILURE(BusinessErrorCode.FAILURE, BusinessErrorCode.FAILURE.getMessage()),
TENANT_DOES_NOT_EXIST(BusinessErrorCode.TENANT_DOES_NOT_EXIST, BusinessErrorCode.TENANT_DOES_NOT_EXIST.getMessage());
private final BusinessErrorCode code;
private final String message;
ResponseCode(BusinessErrorCode code, String message) {
this.code = code;
this.message = message;
}
}

View File

@ -0,0 +1,21 @@
package com.qc.soft.deploy.ease.event;
import lombok.Getter;
@Getter
public enum JenkinsJobChangeEvent {
SUCCESS("成功"),
FAILURE("失败"),
ABORTED("终止");
private final String message;
JenkinsJobChangeEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}

View File

@ -0,0 +1,27 @@
package com.qc.soft.deploy.ease.exception;
import com.qc.soft.deploy.ease.enums.BusinessErrorCode;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Setter
@Builder
public class BusinessException extends RuntimeException {
@Getter
protected BusinessErrorCode code;
protected String message;
public BusinessException(BusinessErrorCode code, String message, Throwable e) {
super(message, e);
this.code = code;
this.message = message;
}
public BusinessException(BusinessErrorCode code, String message) {
this(code, message, null);
}
}

View File

@ -0,0 +1,29 @@
package com.qc.soft.deploy.ease.fegin.response;
import lombok.Data;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Data
public class JenkinsJobChangeSetDetailResponse {
private String commitId;
private Date timestamp;
private Map<String, String> author;
private String authorEmail;
private String comment;
private Date date;
private String id;
private String msg;
private List<Map<String, String>> paths;
}

View File

@ -0,0 +1,12 @@
package com.qc.soft.deploy.ease.fegin.response;
import lombok.Data;
import java.util.List;
@Data
public class JenkinsJobChangeSetResponse {
private List<JenkinsJobChangeSetDetailResponse> items;
}

View File

@ -0,0 +1,36 @@
package com.qc.soft.deploy.ease.fegin.response;
import com.qc.soft.deploy.ease.enums.JenkinsJobStatus;
import lombok.Data;
import lombok.ToString;
import java.util.Date;
@Data
@ToString
public class JenkinsJobResponse {
private Long id;
private String projectName;
private int number;
private boolean inProgress;
private boolean building;
private JenkinsJobStatus result;
private Date timestamp;
private long duration;
private int queueId;
private JenkinsJobChangeSetResponse changeSet;
}

View File

@ -0,0 +1,166 @@
package com.qc.soft.deploy.ease.holder;
import com.qc.soft.deploy.ease.convert.K8sNamespaceConvert;
import com.qc.soft.deploy.ease.convert.K8sPodConvert;
import com.qc.soft.deploy.ease.k8s.K8sDeploymentResponse;
import com.qc.soft.deploy.ease.k8s.K8sNamespaceResponse;
import com.qc.soft.deploy.ease.k8s.K8sPodResponse;
import io.kubernetes.client.Metrics;
import io.kubernetes.client.custom.PodMetrics;
import io.kubernetes.client.custom.PodMetricsList;
import io.kubernetes.client.custom.Quantity;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.apis.AppsV1Api;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1Deployment;
import io.kubernetes.client.openapi.models.V1DeploymentList;
import io.kubernetes.client.openapi.models.V1DeploymentSpec;
import io.kubernetes.client.openapi.models.V1Namespace;
import io.kubernetes.client.openapi.models.V1NamespaceList;
import io.kubernetes.client.openapi.models.V1ObjectMeta;
import io.kubernetes.client.openapi.models.V1Pod;
import io.kubernetes.client.openapi.models.V1PodList;
import io.kubernetes.client.openapi.models.V1Scale;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@Component
@Slf4j
public class K8sApiHolder {
@Resource
private ApiClient apiClient;
public void resetNamespacedDeploymentScale(String namespace, String deploymentName, Integer clearScaleNumber, Integer scaleNumber) throws ApiException, InterruptedException {
AppsV1Api api = new AppsV1Api(apiClient);
updateNamespacedDeploymentScale(api, namespace, deploymentName, clearScaleNumber);
Thread.sleep(2000);
updateNamespacedDeploymentScale(api, namespace, deploymentName, scaleNumber);
}
private void updateNamespacedDeploymentScale(AppsV1Api api, String namespace, String deploymentName, Integer scaleNumber) throws ApiException {
V1Scale v1Scale = api.readNamespacedDeploymentScale(deploymentName, namespace, null);
if (v1Scale.getSpec() == null) {
log.error("K8s query scale is empty, unable to scale operations, namespace:{}, deployment:{}", namespace, deploymentName);
return;
}
v1Scale.getSpec().setReplicas(scaleNumber);
V1Scale scaleUpdated = api.replaceNamespacedDeploymentScale(deploymentName, namespace, v1Scale, null, null, null, null);
if (scaleUpdated == null) {
return;
}
Integer replicas = Objects.requireNonNull(scaleUpdated.getSpec()).getReplicas();
if (replicas == null && scaleNumber == 0) {
log.info("K8s namespace:{}, deployment:{} pods scaling is complete, scaleNumber:{}", namespace, deploymentName, scaleNumber);
return;
}
if (Objects.equals(replicas, scaleNumber)) {
log.info("K8s namespace:{}, deployment:{} pods scaling is complete, scaleNumber:{}", namespace, deploymentName, scaleNumber);
} else {
log.error("K8s namespace:{}, deployment:{} pods scaling failure, scaleNumber:{}", namespace, deploymentName, scaleNumber);
}
}
public List<K8sDeploymentResponse> deploymentList(String namespace) {
try {
List<K8sDeploymentResponse> responses = new ArrayList<>();
AppsV1Api api = new AppsV1Api(apiClient);
V1DeploymentList deploymentList = api.listNamespacedDeployment(namespace, null, null, null, null, null, null, null, null, null, null, null);
for (V1Deployment deployment : deploymentList.getItems()) {
V1ObjectMeta metadata = deployment.getMetadata();
V1DeploymentSpec spec = deployment.getSpec();
K8sDeploymentResponse response = new K8sDeploymentResponse();
response.setName(Objects.requireNonNull(metadata).getName());
response.setNamespace(metadata.getNamespace());
response.setCreationTimestamp(metadata.getCreationTimestamp());
response.setReplicas(Objects.requireNonNull(spec).getReplicas());
response.setImageName(deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage());
responses.add(response);
}
return responses;
} catch (ApiException e) {
throw new RuntimeException(e);
}
}
public List<K8sPodResponse> podsList(String namespace, String deploymentName) {
try {
CoreV1Api api = new CoreV1Api(apiClient);
V1PodList v1PodList = api.listNamespacedPod(namespace, null, null, null, null, null, null, null, null, null, null, null);
List<K8sPodResponse> results = new ArrayList<>();
List<V1Pod> list = new ArrayList<>();
for (V1Pod pod : v1PodList.getItems()) {
V1ObjectMeta metadata = pod.getMetadata();
if (StringUtils.isEmpty(deploymentName)) {
results.add(K8sPodConvert.INSTANCE.toK8sPodResponse(pod, deploymentName));
} else {
if (metadata.getName().contains(deploymentName)) {
results.add(K8sPodConvert.INSTANCE.toK8sPodResponse(pod, deploymentName));
}
}
}
if (CollectionUtils.isEmpty(results)) {
return new ArrayList<>();
}
Metrics metrics = new Metrics(apiClient);
PodMetricsList podMetrics = metrics.getPodMetrics(namespace);
results.forEach(pod -> {
Optional<PodMetrics> metricsOptional = podMetrics.getItems().stream().filter(item -> item.getMetadata().getName().equals(pod.getName())).findFirst();
if (!metricsOptional.isPresent()) {
return;
}
Map<String, Quantity> usage = metricsOptional.get().getContainers().get(0).getUsage();
pod.setCpuUsage(usage.get("cpu").getNumber());
pod.setMemoryUsage(usage.get("memory").getNumber());
});
return results;
} catch (ApiException e) {
throw new RuntimeException(e);
}
}
public String getPodLog(String namespace, String podName) {
try {
CoreV1Api api = new CoreV1Api(apiClient);
String podLog = api.readNamespacedPodLog(
podName,
namespace,
"backend-longi-scp-meta-group-1",
false,
null,
102400,
"true",
false,
10,
10,
true);
System.out.println(podLog);
return podLog;
} catch (ApiException e) {
throw new RuntimeException(e);
}
}
public List<K8sNamespaceResponse> namespaceList() {
try {
List<V1Namespace> namespaces = new ArrayList<>();
CoreV1Api api = new CoreV1Api(apiClient);
V1NamespaceList v1NamespaceList = api.listNamespace(null, null, null, null, null, null, null, null, null, null, null);
namespaces.addAll(v1NamespaceList.getItems());
return K8sNamespaceConvert.INSTANCE.toK8sNamespaceList(namespaces);
} catch (ApiException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,48 @@
package com.qc.soft.deploy.ease.interceptor;
import com.qc.soft.deploy.ease.context.TenantContext;
import com.qc.soft.deploy.ease.entity.Tenant;
import com.qc.soft.deploy.ease.exception.BusinessException;
import com.qc.soft.deploy.ease.repository.ITenantRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static com.qc.soft.deploy.ease.enums.BusinessErrorCode.TENANT_DOES_NOT_EXIST;
import static com.qc.soft.deploy.ease.enums.BusinessErrorCode.TENANT_NOT_ENABLED;
@Slf4j
@Component
public class TenantInterceptor implements HandlerInterceptor {
@Resource
private ITenantRepository tenantRepository;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String tenantCode = request.getHeader("x-tenant-code");
if (null == tenantCode || StringUtils.isEmpty(tenantCode)) {
throw new BusinessException(TENANT_DOES_NOT_EXIST, "请求头未携带x-tenant-code");
}
Tenant tenant = tenantRepository.findByTenantCode(tenantCode);
if (tenant == null) {
throw new BusinessException(TENANT_DOES_NOT_EXIST, TENANT_DOES_NOT_EXIST.getMessage());
}
if (!tenant.isEnabled()) {
throw new BusinessException(TENANT_NOT_ENABLED, String.format(TENANT_NOT_ENABLED.getMessage(), tenantCode));
}
TenantContext.setCurrentTenant(tenantCode);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
TenantContext.clear();
}
}

View File

@ -0,0 +1,10 @@
package com.qc.soft.deploy.ease.k8s;
import lombok.Data;
import java.time.OffsetDateTime;
@Data
public class K8sAuthentications {
}

View File

@ -0,0 +1,22 @@
package com.qc.soft.deploy.ease.k8s;
import lombok.Data;
import java.time.OffsetDateTime;
@Data
public class K8sDeploymentResponse {
private String namespace;
private String name;
private String realName;
private Integer replicas;
private OffsetDateTime creationTimestamp;
private String imageName;
}

View File

@ -0,0 +1,12 @@
package com.qc.soft.deploy.ease.k8s;
import lombok.Data;
import java.time.OffsetDateTime;
@Data
public class K8sNamespaceResponse {
private String name;
}

View File

@ -0,0 +1,33 @@
package com.qc.soft.deploy.ease.k8s;
import lombok.Data;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
@Data
public class K8sPodResponse {
private String namespace;
private String deploymentName;
private String name;
private String container;
private BigDecimal limits;
private BigDecimal requests;
private Integer restartCount;
private BigDecimal cpuUsage;
private BigDecimal memoryUsage;
private String imageName;
private OffsetDateTime creationTimestamp;
}

View File

@ -0,0 +1,13 @@
package com.qc.soft.deploy.ease.repository;
import com.qc.soft.deploy.ease.entity.Dictionary;
import com.qc.soft.deploy.ease.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface IDictionaryRepository extends JpaRepository<Dictionary, Long> {
List<Dictionary> findAll();
}

View File

@ -0,0 +1,12 @@
package com.qc.soft.deploy.ease.repository;
import com.qc.soft.deploy.ease.entity.Project;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface IProjectRepository extends JpaRepository<Project, Long> {
List<Project> findByTenantCode(String tenantCode);
}

View File

@ -0,0 +1,13 @@
package com.qc.soft.deploy.ease.repository;
import com.qc.soft.deploy.ease.entity.Dictionary;
import com.qc.soft.deploy.ease.entity.TenantDictionary;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ITenantDictionaryRepository extends JpaRepository<TenantDictionary, Long> {
List<TenantDictionary> findAllByTenantCode(String tenantCode);
}

View File

@ -0,0 +1,13 @@
package com.qc.soft.deploy.ease.repository;
import com.qc.soft.deploy.ease.entity.Dictionary;
import com.qc.soft.deploy.ease.entity.Tenant;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ITenantRepository extends JpaRepository<Tenant, Long> {
Tenant findByTenantCode(String tenantCode);
}

View File

@ -0,0 +1,8 @@
package com.qc.soft.deploy.ease.repository;
import com.qc.soft.deploy.ease.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface IUserRepository extends JpaRepository<User, Long> {
User findByUsernameAndPassword(String username, String password);
}

View File

@ -0,0 +1,14 @@
package com.qc.soft.deploy.ease.service;
import com.qc.soft.deploy.ease.api.response.DictionaryResponse;
import com.qc.soft.deploy.ease.api.response.TenantDictionaryResponse;
import java.util.List;
public interface IDictionaryService {
List<DictionaryResponse> findSystemDicts();
List<TenantDictionaryResponse> findDictsByTenantCode();
}

View File

@ -0,0 +1,14 @@
package com.qc.soft.deploy.ease.service;
import com.qc.soft.deploy.ease.fegin.response.JenkinsJobResponse;
import java.util.Map;
public interface IJenkinsService {
JenkinsJobResponse create();
//获取订单列表
Map<Long, JenkinsJobResponse> getJenkinsJobs();
JenkinsJobResponse pay(long id);
}

View File

@ -0,0 +1,21 @@
package com.qc.soft.deploy.ease.service;
import com.qc.soft.deploy.ease.k8s.K8sDeploymentResponse;
import com.qc.soft.deploy.ease.k8s.K8sNamespaceResponse;
import com.qc.soft.deploy.ease.k8s.K8sPodResponse;
import java.util.List;
public interface IK8sService {
List<K8sDeploymentResponse> deployments(String namespace);
String getPodLog(String namespace, String podName);
List<K8sPodResponse> pods(String namespace, String deploymentName);
List<K8sNamespaceResponse> namespaces();
String getKubeConfig();
}

View File

@ -0,0 +1,6 @@
package com.qc.soft.deploy.ease.service;
public interface INacosService {
void instances();
}

View File

@ -0,0 +1,11 @@
package com.qc.soft.deploy.ease.service;
import com.qc.soft.deploy.ease.api.response.ProjectResponse;
import java.util.List;
public interface IProjectService {
List<ProjectResponse> list();
}

View File

@ -0,0 +1,7 @@
package com.qc.soft.deploy.ease.service;
public interface IUserService {
boolean login(String username, String password);
}

View File

@ -0,0 +1,55 @@
package com.qc.soft.deploy.ease.service.impl;
import com.qc.soft.deploy.ease.api.response.DictionaryResponse;
import com.qc.soft.deploy.ease.api.response.TenantDictionaryResponse;
import com.qc.soft.deploy.ease.context.TenantContext;
import com.qc.soft.deploy.ease.convert.api.response.DictionaryApiResponseConvert;
import com.qc.soft.deploy.ease.convert.api.response.TenantDictionaryApiResponseConvert;
import com.qc.soft.deploy.ease.convert.dto.DictionaryConvert;
import com.qc.soft.deploy.ease.entity.Dictionary;
import com.qc.soft.deploy.ease.entity.TenantDictionary;
import com.qc.soft.deploy.ease.repository.IDictionaryRepository;
import com.qc.soft.deploy.ease.repository.ITenantDictionaryRepository;
import com.qc.soft.deploy.ease.service.IDictionaryService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class DictionaryServiceImpl implements IDictionaryService {
@Resource
private IDictionaryRepository dictionaryRepository;
@Resource
private ITenantDictionaryRepository tenantDictionaryRepository;
@Override
public List<DictionaryResponse> findSystemDicts() {
return DictionaryApiResponseConvert.INSTANCE.entityToResponse(dictionaryRepository.findAll());
}
@Override
public List<TenantDictionaryResponse> findDictsByTenantCode() {
String tenantCode = TenantContext.getCurrentTenant();
List<Dictionary> tenantSharingDict = dictionaryRepository.findAll().stream().filter(Dictionary::isTenantSharing).collect(Collectors.toList());
List<TenantDictionary> tenantDict = tenantDictionaryRepository.findAllByTenantCode(tenantCode);
List<TenantDictionary> mergeTenantDict = new ArrayList<>();
tenantSharingDict.forEach(v -> {
String systemDictCode = v.getCode();
Map<String, TenantDictionary> tenantDictMap = tenantDict.stream().collect(Collectors.toMap(TenantDictionary::getCode, tenantDictionary -> tenantDictionary));
TenantDictionary tenantDictionary = tenantDictMap.get(systemDictCode);
if (tenantDictionary == null) {
tenantDictMap.put(systemDictCode, DictionaryConvert.INSTANCE.systemDictionaryToTenantDictionary(v));
}
mergeTenantDict.addAll(tenantDictMap.values());
});
return TenantDictionaryApiResponseConvert.INSTANCE.entityToResponse(mergeTenantDict);
}
}

View File

@ -0,0 +1,81 @@
package com.qc.soft.deploy.ease.service.impl;
import com.qc.soft.deploy.ease.fegin.response.JenkinsJobResponse;
import com.qc.soft.deploy.ease.event.JenkinsJobChangeEvent;
import com.qc.soft.deploy.ease.enums.JenkinsJobStatus;
import com.qc.soft.deploy.ease.service.IJenkinsService;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@Service
public class JenkinsServiceImpl implements IJenkinsService {
@Resource
private StateMachine<JenkinsJobStatus, JenkinsJobChangeEvent> jenkinsStateMachine;
@Resource
private StateMachinePersister<JenkinsJobStatus, JenkinsJobChangeEvent, JenkinsJobResponse> persister;
private int id = 1;
private Map<Long, JenkinsJobResponse> jenkinsJobs = new HashMap<>();
@Override
public JenkinsJobResponse create() {
JenkinsJobResponse jenkinsJob = new JenkinsJobResponse();
jenkinsJob.setResult(JenkinsJobStatus.WAITING_BUILD);//设置订单的初始状态
jenkinsJob.setId((long) id++);//设置订单的编号累加
jenkinsJobs.put(jenkinsJob.getId(), jenkinsJob);//根据编号对应地存储订单对象便于存取
System.out.println("订单创建成功" + jenkinsJob.toString());
return jenkinsJob;//返回创建好的订单对象
}
//获取订单列表
@Override
public Map<Long, JenkinsJobResponse> getJenkinsJobs() {
return jenkinsJobs;
}
private synchronized boolean sendEvent(Message<JenkinsJobChangeEvent> message, JenkinsJobResponse jenkinsJobResponse) {
boolean result = false;
try {
jenkinsStateMachine.start();
//尝试恢复状态机状态
persister.restore(jenkinsStateMachine, jenkinsJobResponse);
//添加延迟用于线程安全测试
Thread.sleep(1000);
result = jenkinsStateMachine.sendEvent(message);
//持久化状态机状态
persister.persist(jenkinsStateMachine, jenkinsJobResponse);
} catch (Exception e) {
e.printStackTrace();
} finally {
jenkinsStateMachine.stop();
}
return result;
}
@Override
public JenkinsJobResponse pay(long id) {
/*根据id获取订单集合的指定订单*/
JenkinsJobResponse jenkinsJobResponse = jenkinsJobs.get(id);
Message message = MessageBuilder.withPayload(JenkinsJobChangeEvent.SUCCESS).setHeader("jenkinsJobResponse", jenkinsJobResponse).build();
if (!sendEvent(message, jenkinsJobResponse)) {
System.out.println("订单支付失败");
}
return jenkinsJobResponse;
}
}

View File

@ -0,0 +1,64 @@
package com.qc.soft.deploy.ease.service.impl;
import com.qc.soft.deploy.ease.k8s.K8sDeploymentResponse;
import com.qc.soft.deploy.ease.k8s.K8sNamespaceResponse;
import com.qc.soft.deploy.ease.k8s.K8sPodResponse;
import com.qc.soft.deploy.ease.holder.K8sApiHolder;
import com.qc.soft.deploy.ease.service.IK8sService;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class K8sServiceImpl implements IK8sService {
@Resource
private K8sApiHolder k8sApiHolder;
private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
@Override
public List<K8sDeploymentResponse> deployments(String namespace) {
return k8sApiHolder.deploymentList(namespace);
}
@Override
public String getPodLog(String namespace, String podName) {
return k8sApiHolder.getPodLog(namespace, podName);
}
@Override
public List<K8sPodResponse> pods(String namespace, String deploymentName) {
return k8sApiHolder.podsList(namespace, deploymentName);
}
@Override
public List<K8sNamespaceResponse> namespaces() {
return k8sApiHolder.namespaceList().stream().filter(namespace -> namespace.getName().contains("ibp")).collect(Collectors.toList());
}
@Override
public String getKubeConfig() {
try {
org.springframework.core.io.Resource[] resources = resolver.getResources("classpath:/./kube/*");
for (org.springframework.core.io.Resource resource : resources) {
if (!resource.isReadable() && StringUtils.isNotEmpty(resource.getFilename())) {
continue;
}
return IOUtils.toString(resource.getInputStream(), StandardCharsets.UTF_8);
}
return null;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,33 @@
package com.qc.soft.deploy.ease.service.impl;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.qc.soft.deploy.ease.service.INacosService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class NacosServiceImpl implements INacosService {
@Resource
private NacosDiscoveryProperties nacosDiscoveryProperties;
private final static String SYNCHRONIZER_SERVICE_NAME = "deploy-ease-synchronizer-longi-%s";
@Override
public void instances() {
try {
NamingService namingService = NamingFactory.createNamingService(nacosDiscoveryProperties.getNacosProperties());
List<Instance> allInstances = namingService.getAllInstances(SYNCHRONIZER_SERVICE_NAME, nacosDiscoveryProperties.getGroup());
System.out.println(allInstances);
} catch (NacosException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,25 @@
package com.qc.soft.deploy.ease.service.impl;
import com.qc.soft.deploy.ease.api.response.ProjectResponse;
import com.qc.soft.deploy.ease.context.TenantContext;
import com.qc.soft.deploy.ease.convert.api.response.ProjectApiResponseConvert;
import com.qc.soft.deploy.ease.repository.IProjectRepository;
import com.qc.soft.deploy.ease.service.IProjectService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class ProjectServiceImpl implements IProjectService {
@Resource
private IProjectRepository projectRepository;
@Override
public List<ProjectResponse> list() {
String tenantCode = TenantContext.getCurrentTenant();
return ProjectApiResponseConvert.INSTANCE.entityToResponse(projectRepository.findByTenantCode(tenantCode));
}
}

View File

@ -0,0 +1,21 @@
package com.qc.soft.deploy.ease.service.impl;
import com.qc.soft.deploy.ease.entity.User;
import com.qc.soft.deploy.ease.repository.IUserRepository;
import com.qc.soft.deploy.ease.service.IUserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserServiceImpl implements IUserService {
@Resource
private IUserRepository userRepository;
@Override
public boolean login(String username, String password) {
User user = userRepository.findByUsernameAndPassword(username, password);
return user != null;
}
}

View File

@ -0,0 +1,55 @@
package com.qc.soft.deploy.ease.statemachine;
import com.qc.soft.deploy.ease.fegin.response.JenkinsJobResponse;
import com.qc.soft.deploy.ease.event.JenkinsJobChangeEvent;
import com.qc.soft.deploy.ease.enums.JenkinsJobStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.StateMachineContext;
import org.springframework.statemachine.StateMachinePersist;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.persist.DefaultStateMachinePersister;
import org.springframework.statemachine.support.DefaultStateMachineContext;
import java.util.EnumSet;
@Configuration
@EnableStateMachine(name = "jenkinsStatemachine")
public class JenkinsJobStatemachineConfig extends StateMachineConfigurerAdapter<JenkinsJobStatus, JenkinsJobChangeEvent> {
@Override
public void configure(StateMachineStateConfigurer<JenkinsJobStatus, JenkinsJobChangeEvent> states) throws Exception {
states.withStates().initial(JenkinsJobStatus.WAITING_BUILD).states(EnumSet.allOf(JenkinsJobStatus.class));
}
public void configure(StateMachineTransitionConfigurer<JenkinsJobStatus, JenkinsJobChangeEvent> transitions) throws Exception {
transitions
.withExternal().source(JenkinsJobStatus.WAITING_BUILD).target(JenkinsJobStatus.BUILDING).event(JenkinsJobChangeEvent.SUCCESS)
.and()
.withExternal().source(JenkinsJobStatus.WAITING_BUILD).target(JenkinsJobStatus.BUILDING).event(JenkinsJobChangeEvent.ABORTED)
.and()
.withExternal().source(JenkinsJobStatus.WAITING_BUILD).target(JenkinsJobStatus.BUILDING).event(JenkinsJobChangeEvent.FAILURE);
}
@Bean
public DefaultStateMachinePersister persister() {
return new DefaultStateMachinePersister<>(new StateMachinePersist<Object, Object, JenkinsJobResponse>() {
@Override
public void write(StateMachineContext<Object, Object> context, JenkinsJobResponse jenkinsJob) throws Exception {
jenkinsJob.setResult(JenkinsJobStatus.BUILD_END);
System.out.println("persister writer" + jenkinsJob.toString());
}
@Override
public StateMachineContext<Object, Object> read(JenkinsJobResponse jenkinsJob) throws Exception {
System.out.println("persister read" + jenkinsJob.toString());
return new DefaultStateMachineContext(jenkinsJob.getResult(), null, null, null);
}
});
}
}

View File

@ -0,0 +1,38 @@
package com.qc.soft.deploy.ease.statemachine.listener;
import com.qc.soft.deploy.ease.fegin.response.JenkinsJobResponse;
import com.qc.soft.deploy.ease.event.JenkinsJobChangeEvent;
import org.springframework.messaging.Message;
import org.springframework.statemachine.annotation.OnTransition;
import org.springframework.statemachine.annotation.WithStateMachine;
import org.springframework.stereotype.Component;
@Component("jenkinsJobStatusListener")
@WithStateMachine(name = "jenkinsStatemachine")
public class JenkinsJobStatusListenerImpl {
@OnTransition(source = "WAITING_BUILD", target = "BUILDING")
public boolean jenkinsBuildingTransition(Message<JenkinsJobChangeEvent> message) {
JenkinsJobResponse jenkinsJobResponse = (JenkinsJobResponse) message.getHeaders().get("jenkinsJobResponse");
jenkinsJobResponse.setResult(jenkinsJobResponse.getResult());
System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
return true;
}
@OnTransition(source = "BUILDING", target = "BUILD_END")
public boolean jenkinsBuildEndTransition(Message<JenkinsJobChangeEvent> message) {
JenkinsJobResponse jenkinsJobResponse = (JenkinsJobResponse) message.getHeaders().get("jenkinsJobResponse");
jenkinsJobResponse.setResult(jenkinsJobResponse.getResult());
System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
return true;
}
// @OnTransition(source = "BUILDING", target = "BUILDING")
// public boolean jenkinsBuildingTransition(Message<JenkinsJobChangeEnum> message) {
// JenkinsJobResponse jenkinsJobResponse = (JenkinsJobResponse) message.getHeaders().get("jenkinsJobResponse");
//// jenkinsJobResponse.setStatus(OrderStatus.WAIT_DELIVER);
// System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
// return true;
// }
}

View File

@ -0,0 +1,13 @@
package com.qc.soft.deploy.ease.utils;
import java.util.Base64;
public class BasicAuthUtils {
public static String encode(String userName, String password) {
String auth = userName + ":" + password;
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
return "Basic " + encodedAuth;
}
}

View File

@ -0,0 +1,62 @@
package com.qc.soft.deploy.ease.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Date;
public class DateUtils {
public static long differenceInMinutes(Date date1, Date date2) {
LocalDateTime currentLocalDateTime = LocalDateTime.ofInstant(date1.toInstant(), ZoneId.systemDefault());
LocalDateTime pulishLocalDateTime = LocalDateTime.ofInstant(date2.toInstant(), ZoneId.systemDefault());
Duration duration = Duration.between(currentLocalDateTime, pulishLocalDateTime);
return duration.toMinutes();
}
public static String formatDate(Date date, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(date);
}
public static boolean betweenDate(String start, String end) {
String format = "HH:mm:ss";
String nowDate = new SimpleDateFormat(format).format(new Date());
try {
Date beginDate = new SimpleDateFormat(format).parse(start);
Date endDate = new SimpleDateFormat(format).parse(end);
LocalDate today = LocalDate.now();
LocalDateTime todayStart = LocalDateTime.of(today, LocalTime.MIN);
LocalDateTime todayEnd = LocalDateTime.of(today, LocalTime.MAX);
LocalDate nextDay = today.plusDays(1);
LocalDateTime nextDayStart = LocalDateTime.of(today, LocalTime.MIN);
LocalDateTime nextDayEnd = LocalDateTime.of(today, LocalTime.MAX);
long todayStartTimestamp = todayStart.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
long todayEndTimestamp = todayEnd.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
//先判断是第一天还是第二天
if (todayStartTimestamp < endDate.getTime() && todayEndTimestamp > beginDate.getTime()) {
System.out.println(1);
}
boolean b = todayStartTimestamp < beginDate.getTime() && todayEndTimestamp > endDate.getTime();
System.out.println(1);
return false;
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
private Date addDay(Date date, int days) {
Calendar calendar = Calendar.getInstance(); // 获取当前日期
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_YEAR, days); // 加一天
return calendar.getTime();
}
}

View File

@ -0,0 +1,59 @@
package com.qc.soft.deploy.ease.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import java.io.IOException;
@Slf4j
public class FileUtils {
private static final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
public static String getJarResourcesFolderPath(String folderPath) {
try {
Resource[] resources = resolver.getResources("classpath*:/" + folderPath);
for (Resource resource : resources) {
if (!resource.exists()) {
continue;
}
return resource.getURI().getRawPath();
}
} catch (IOException e) {
log.error("Resource file not found, folderPath:{}", folderPath);
}
throw new NullPointerException("Folder path not found");
}
public static String getJarResourcesFilePath(String path, String fileName) {
try {
Resource[] resources = resolver.getResources("classpath*:/" + path + "/" + fileName);
for (Resource resource : resources) {
if (!resource.isReadable()) {
continue;
}
return resource.getURI().getRawPath();
}
} catch (IOException e) {
log.error("Resource file not found, path:{}, fileName:{}", path, fileName);
}
throw new NullPointerException("Resource file not found");
}
public static Resource getJarFileResources(String path) {
try {
Resource[] resources = resolver.getResources("classpath*:/" + path);
for (Resource resource : resources) {
if (!resource.isReadable()) {
continue;
}
return resource;
}
} catch (IOException e) {
log.error("Resource file not found, path:{}", path);
}
throw new NullPointerException("Resource file not found");
}
}

View File

@ -0,0 +1,260 @@
package com.qc.soft.deploy.ease.utils;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.hc.client5.http.classic.methods.HttpDelete;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.logging.log4j.util.Strings;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Optional;
@Slf4j
public class HttpUtils<T> {
public static final int fileSize = 10 * 1024;
public static <T> T get(String url, Map<String, String> header, Class<T> cls) {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet(url);
CloseableHttpResponse response = null;
try {
if (!MapUtil.isEmpty(header)) {
header.forEach(get::setHeader);
}
response = httpclient.execute(get);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
EntityUtils.consume(entity);
return JSON.parseObject(result, cls);
} catch (Exception e) {
log.error("http get error, url:{}", url, e);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return null;
}
public static Map<String, Object> get(String url, Map<String, String> header) {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet(url);
CloseableHttpResponse response = null;
try {
if (!MapUtil.isEmpty(header)) {
header.forEach(get::setHeader);
}
response = httpclient.execute(get);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
EntityUtils.consume(entity);
return JSON.parseObject(result, Map.class);
} catch (Exception e) {
log.error("http get error, url:{}", url);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return new HashMap<>();
}
public static void delete(String url, Map<String, String> header) {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpDelete delete = new HttpDelete(url);
CloseableHttpResponse response = null;
try {
if (!MapUtil.isEmpty(header)) {
header.forEach(delete::setHeader);
}
response = httpclient.execute(delete);
log.info("Remove nexus url:{} success", url);
} catch (Exception e) {
log.error("http delete error, url:{}", url, e);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static Map<String, Object> post(String url, IdentityHashMap<String, String> header) {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost post = new HttpPost(url);
CloseableHttpResponse response = null;
Map<String, Object> result = new HashMap<>();
try {
if (!MapUtil.isEmpty(header)) {
header.forEach(post::setHeader);
}
response = httpclient.execute(post);
HttpEntity entity = response.getEntity();
result.put("code", response.getCode());
result.put("message", EntityUtils.toString(response.getEntity()));
EntityUtils.consume(entity);
log.info("Http client post success, response:{}", response);
return result;
} catch (Exception e) {
log.error("http post error, url:{}", url, e);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
result.put("code", 0);
return result;
}
public static <T> T cookieGet(String url, Map<String, String> header, Class<T> cls) {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet(url);
CloseableHttpResponse response = null;
try {
if (!MapUtil.isEmpty(header)) {
header.forEach(get::setHeader);
}
response = httpclient.execute(get);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
Optional<Header> cookieOptional = Arrays.stream(response.getHeaders()).filter(v -> v.getName().equals("Set-Cookie")).findFirst();
if (cookieOptional.isPresent()) {
Header cookie = cookieOptional.get();
String cookieValue = cookie.getValue().substring(0, cookie.getValue().indexOf(";"));
JSONObject tempObject = JSON.parseObject(result);
tempObject.put("cookie", cookieValue);
result = JSON.toJSONString(tempObject);
}
EntityUtils.consume(entity);
log.info("http cookie get result:{}", result);
return JSON.parseObject(result, cls);
} catch (Exception e) {
log.error("http get error, url:{}", url, e);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return null;
}
public static String downloadFile(String url, Map<String, String> header, String downloadBuildFailedFilePath, String fileName) {
String fullFilePath = downloadBuildFailedFilePath + File.separator + fileName;
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet get = new HttpGet(url);
CloseableHttpResponse response = null;
try {
File directory = new File(downloadBuildFailedFilePath);
if (!directory.exists()) {
directory.mkdirs();
}
if (!directory.isDirectory()) {
return null;
}
if (!MapUtil.isEmpty(header)) {
header.forEach(get::setHeader);
}
response = httpclient.execute(get);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
File file = new File(fullFilePath);
if (file.exists()) {
log.info("Download file exists,will be deleted, fileName:{}", fileName);
file.delete();
}
file.createNewFile();
FileOutputStream os = new FileOutputStream(file);
byte[] buffer = new byte[fileSize];
int ch = 0;
while ((ch = is.read(buffer)) != -1) {
os.write(buffer, 0, ch);
}
is.close();
os.flush();
os.close();
EntityUtils.consume(entity);
log.info("Download file success, url:{}, filePath:{}", url, fullFilePath);
return fullFilePath;
} catch (Exception e) {
log.error("Download file failed, url:{}", url);
} finally {
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return null;
}
public static <T> T uploadFile(String url, String filePath, Class<T> cls) {
CloseableHttpResponse response = null;
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(url);
File file = new File(filePath);
if (!file.exists()) {
log.error("Upload file not exists, filePath:{}", filePath);
return null;
}
HttpEntity fileEntity = MultipartEntityBuilder.create().addBinaryBody("file", file).build();
httpPost.setEntity(fileEntity);
response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity);
EntityUtils.consume(entity);
return JSON.parseObject(content, cls);
} catch (Exception e) {
log.error("Upload file failed, url:{}, filePath:{}, response:{}", url, filePath, JSON.toJSONString(response));
} finally {
if (response != null) {
try {
response.close();
} catch (IOException e) {
log.error("Upload file close response failed, url:{}, filePath:{}", url, filePath);
}
}
}
return null;
}
}

View File

@ -0,0 +1,263 @@
package com.qc.soft.deploy.ease.utils;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.apis.AppsV1Api;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1DeploymentList;
import io.kubernetes.client.openapi.models.V1EndpointsList;
import io.kubernetes.client.openapi.models.V1NamespaceList;
import io.kubernetes.client.openapi.models.V1PodList;
import io.kubernetes.client.openapi.models.V1Scale;
import io.kubernetes.client.util.ClientBuilder;
import io.kubernetes.client.util.KubeConfig;
import lombok.extern.slf4j.Slf4j;
import java.io.FileReader;
import java.io.IOException;
@Slf4j
public class K8sClientUtils {
private ApiClient apiClient;
/**
* 构建集群POD内通过SA访问的客户端
* loading the in-cluster config2, including:
* 1. service-account CA
* 2. service-account bearer-token
* 3. service-account namespace
* 4. master endpoints(ip, port) from pre-set environment variables
*/
public K8sClientUtils() {
try {
this.apiClient = ClientBuilder.cluster().build();
} catch (IOException e) {
log.error("构建K8s-Client异常", e);
throw new RuntimeException("构建K8s-Client异常");
}
}
/**
* 构建集群外通过UA访问的客户端
* loading the out-of-cluster config2, a kubeconfig from file-system
*
* @param kubeConfigPath kube连接配置文件
*/
public K8sClientUtils(String kubeConfigPath) {
try {
this.apiClient = ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath))).build();
} catch (IOException e) {
log.error("读取kubeConfigPath异常", e);
throw new RuntimeException("读取kubeConfigPath异常");
} catch (Exception e) {
log.error("构建K8s-Client异常", e);
throw new RuntimeException("构建K8s-Client异常");
}
}
/**
* 获取所有的Pod
*
* @return podList
*/
public V1PodList getAllPodList() {
// new a CoreV1Api
CoreV1Api api = new CoreV1Api(apiClient);
// invokes the CoreV1Api client
try {
V1PodList list = api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null, null, null);
return list;
} catch (ApiException e) {
log.error("获取podlist异常:" + e.getResponseBody(), e);
}
return null;
}
public V1NamespaceList getAllNamespaceList() {
// new a CoreV1Api
CoreV1Api api = new CoreV1Api(apiClient);
// invokes the CoreV1Api client
try {
return api.listNamespace(null, null, null, null, null, null, null, null, null, null, null);
} catch (ApiException e) {
log.error("获取podlist异常:" + e.getResponseBody(), e);
}
return null;
}
public V1DeploymentList getDeploymentList(String namespace) {
try {
AppsV1Api api = new AppsV1Api(apiClient);
return api.listNamespacedDeployment(namespace, null, null, null, null, null, null, null, null, null, null, null);
} catch (ApiException e) {
throw new RuntimeException(e);
}
}
public V1EndpointsList getEndpointsList() {
// new a CoreV1Api
CoreV1Api api = new CoreV1Api(apiClient);
// invokes the CoreV1Api client
try {
return api.listEndpointsForAllNamespaces(null, null, null, null, null, null, null, null, null, null, null);
} catch (ApiException e) {
log.error("获取podlist异常:" + e.getResponseBody(), e);
}
return null;
}
public V1Scale readNamespacedDeploymentScale(String namespace, String name) {
try {
AppsV1Api api = new AppsV1Api(apiClient);
return api.readNamespacedDeploymentScale(name, namespace, null);
} catch (ApiException e) {
throw new RuntimeException(e);
}
}
public V1Scale replaceNamespacedDeploymentScale(String appName, String namespace, V1Scale v1Scale){
try {
AppsV1Api api = new AppsV1Api(apiClient);
return api.replaceNamespacedDeploymentScale(appName, namespace, v1Scale, null, null, null, null);
} catch (ApiException e) {
throw new RuntimeException(e);
}
}
/**
* 创建k8s service
*
* @param namespace 命名空间
* @param serviceName 服务名称
* @param port 服务端口号和目标pod的端口号一致
* @param selector pod标签选择器
* @return 创建成功的service对象
*/
// public V1Service createService(String namespace, String serviceName, Integer port, Map<String, String> selector) {
// //构建service的yaml对象
// V1Service
// .withNewMetadata()
// .withName(serviceName)
// .endMetadata()
// .withNewSpec()
// .addNewPort()
// .withProtocol("TCP")
// .withPort(port)
// .withTargetPort(new IntOrString(port))
// .endPort()
// .withSelector(selector)
// .endSpec()
// .build();
//
//
// // Deployment and StatefulSet is defined in apps/v1, so you should use AppsV1Api instead of CoreV1API
// CoreV1Api api = new CoreV1Api(apiClient);
// V1Service v1Service = null;
// try {
// v1Service = api.createNamespacedService(namespace, svc, null, null, null);
// } catch (ApiException e) {
// log.error("创建service异常:" + e.getResponseBody(), e);
// } catch (Exception e) {
// log.error("创建service系统异常:", e);
// }
// return v1Service;
// }
/**
* 创建k8s V1Ingress
*
* @param namespace 命名空间
* @param ingressName ingress名称
* @param annotations ingress注解
* @param path 匹配的路径
* @param serviceName 路由到的服务名称
* @param servicePort 路由到的服务端口
* @return 创建成功的ingress对象
*/
// public V1Ingress createV1Ingress(String namespace, String ingressName, Map<String, String> annotations, String path,
// String serviceName, Integer servicePort) {
// //构建ingress的yaml对象
// V1Ingress ingress = new V1IngressBuilder()
// .withNewMetadata()
// .withName(ingressName)
// .withAnnotations(annotations)
// .endMetadata()
// .withNewSpec()
// .addNewRule()
// .withHttp(new V1HTTPIngressRuleValueBuilder().addToPaths(new V1HTTPIngressPathBuilder()
// .withPath(path)
// .withPathType("Prefix")
// .withBackend(new V1IngressBackendBuilder()
// .withService(new V1IngressServiceBackendBuilder()
// .withName(serviceName)
// .withPort(new V1ServiceBackendPortBuilder()
// .withNumber(servicePort).build()).build()).build()).build()).build())
// .endRule()
// .endSpec()
// .build();
//
//
// //调用对应的API执行创建ingress的操作
// NetworkingV1Api api = new NetworkingV1Api(apiClient);
// V1Ingress v1Ingress = null;
// try {
// v1Ingress = api.createNamespacedIngress(namespace, ingress, null, null, null);
// } catch (ApiException e) {
// log.error("创建ingress异常:" + e.getResponseBody(), e);
// } catch (Exception e) {
// log.error("创建ingress系统异常:", e);
// }
// return v1Ingress;
// }
/**
* 创建k8s ExtensionIngress
*
* @param namespace 命名空间
* @param ingressName ingress名称
* @param annotations ingress注解
* @param path 匹配的路径
* @param serviceName 路由到的服务名称
* @param servicePort 路由到的服务端口
* @return 创建成功的ingress对象
*/
// public ExtensionsV1beta1Ingress createExtensionIngress(String namespace, String ingressName, Map<String, String> annotations, String path,
// String serviceName, Integer servicePort) {
// //构建ingress的yaml对象
// ExtensionsV1beta1Ingress ingress = new ExtensionsV1beta1IngressBuilder()
// .withNewMetadata()
// .withName(ingressName)
// .withAnnotations(annotations)
// .endMetadata()
// .withNewSpec()
// .addNewRule()
// .withHttp(new ExtensionsV1beta1HTTPIngressRuleValueBuilder().addToPaths(new ExtensionsV1beta1HTTPIngressPathBuilder()
// .withPath(path)
// .withBackend(new ExtensionsV1beta1IngressBackendBuilder()
// .withServiceName(serviceName)
// .withServicePort(new IntOrString(servicePort)).build()).build()).build())
// .endRule()
// .endSpec()
// .build();
//
//
// //调用对应的API执行创建ingress的操作
// ExtensionsV1beta1Api api = new ExtensionsV1beta1Api(apiClient);
// ExtensionsV1beta1Ingress extensionsV1beta1Ingress = null;
// try {
// extensionsV1beta1Ingress = api.createNamespacedIngress(namespace, ingress, null, null, null);
// } catch (ApiException e) {
// log.error("创建ingress异常:" + e.getResponseBody(), e);
// } catch (Exception e) {
// log.error("创建ingress系统异常:", e);
// }
// return extensionsV1beta1Ingress;
// }
}

View File

@ -0,0 +1,22 @@
package com.qc.soft.deploy.ease.utils;
import java.util.Map;
import java.util.HashMap;
import java.lang.reflect.Field;
public class MapUtils {
public static Map<String, Object> toMap(Object object) {
try {
Map<String, Object> map = new HashMap<>();
Class<?> clazz = object.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
Object value = field.get(object) == null ? null : field.get(object).toString();
map.put(field.getName(), value);
}
return map;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,9 @@
package com.qc.soft.deploy.ease.utils;
public class StrUtils {
public static boolean containsChineseCharacters(String str) {
String regex = "[\\u4e00-\\u9fa5]";
return str.matches(".*" + regex + ".*");
}
}

View File

@ -0,0 +1,14 @@
package com.qc.soft.deploy.ease.utils;
import java.util.HashMap;
import java.util.Map;
public class TemplateParamsBuildUtils {
public static Map<String, Object> build(Object templateParams) {
Map<String, Object> params = new HashMap<>();
params.put("templateParams", templateParams);
return params;
}
}

View File

@ -0,0 +1,29 @@
spring:
cloud:
nacos:
server-addr: ${NACOS_CONFIG_SERVER:192.168.105.1:8848}
discovery:
group: ${DEPLOY_ENV}
namespace: ${DEPLOY_ENV}
username: ${NACOS_USER}
password: ${NACOS_PWD}
enabled: true
config:
group: ${DEPLOY_ENV}
namespace: ${DEPLOY_ENV}
username: ${NACOS_USER}
password: ${NACOS_PWD}
extension-configs[0]:
data-id: common.yml
group: common
refresh: false
extension-configs[1]:
data-id: deploy-ease-core.yml
group: business
refresh: false
config:
override-none: false
allow-override: true
override-system-properties: false
main:
allow-bean-definition-overriding: true

View File

@ -0,0 +1,19 @@
apiVersion: v1
clusters:
- cluster:
server: https://10.201.127.46:6443
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ2akNDQXRLZ0F3SUJBZ0lDRHhzd0RRWUpLb1pJaHZjTkFRRUxCUUF3YWpFcU1DZ0dBMVVFQ2hNaFl6TTQKTUdVNFpHWm1ORFZoTXpRME1HSTRaamhrWm1SaE1qSTNaV05qWm1FMk1SQXdEZ1lEVlFRTEV3ZGtaV1poZFd4MApNU293S0FZRFZRUURFeUZqTXpnd1pUaGtabVkwTldFek5EUXdZamhtT0dSbVpHRXlNamRsWTJObVlUWXdIaGNOCk1qTXdOVEU1TURJek16QXdXaGNOTkRNd05URTBNREl6T0RVMldqQnFNU293S0FZRFZRUUtFeUZqTXpnd1pUaGsKWm1ZME5XRXpORFF3WWpobU9HUm1aR0V5TWpkbFkyTm1ZVFl4RURBT0JnTlZCQXNUQjJSbFptRjFiSFF4S2pBbwpCZ05WQkFNVElXTXpPREJsT0dSbVpqUTFZVE0wTkRCaU9HWTRaR1prWVRJeU4yVmpZMlpoTmpDQ0FTSXdEUVlKCktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQU9FTmlzRWtSblNsSDhtRDJFUkFoS2ZWdWkyN0hTUFMKQTViT2lKdDZWNnRxVHhmTWRwR0RIMTVCbFlKL1laMFZyeERGUjVyMkJBREVkcXdsVG10NWozTFVIcXN6MnRoKwp2RzFrY0UyMmhUdFNtR05KQjhjbzA2YWNxaHV6YlhMbEZMQlc5eURNVnNENWc4RFBvZzh4QnFXZGg2NVRqeGx5ClkwZjJLeUVBS2V6YUFzc3RHV0swSDIvU2EvenZlb25GNnBJREtKcHh6SjZOSTZ5dUdlTk5hRkMwYXNTTVRJSjIKZHFGT01uWFpFdmZqTVlhU2QxWk5FdFUweUxkYzEyRDlVRmJUamxMSEZxcG9rYit2a202T0tGNi9iOUhCN0xXNgpsZFZMTFdHUkhrbS81Vmg5NTVnOVJFUUNVYVN4THpiSkwrVzlBU3puWWJlcnc0RUtpWWxjSUkwQ0F3RUFBYU9CCm1UQ0JsakFPQmdOVkhROEJBZjhFQkFNQ0Fxd3dEd1lEVlIwVEFRSC9CQVV3QXdFQi96QThCZ2dyQmdFRkJRY0IKQVFRd01DNHdMQVlJS3dZQkJRVUhNQUdHSUdoMGRIQTZMeTlqWlhKMGN5NWhZM011WVd4cGVYVnVMbU52YlM5dgpZM053TURVR0ExVWRId1F1TUN3d0txQW9vQ2FHSkdoMGRIQTZMeTlqWlhKMGN5NWhZM011WVd4cGVYVnVMbU52CmJTOXliMjkwTG1OeWJEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTVJOVjF0K1F6TUo5ZDlkekNDZzVULzkKQnI2T2piQVFSeHhodkVDV0JmODVOeEZUWDNYRmMzbVpkcytNeWFRRERhcUhjbzRmNGZHZ3hKRjVldmZ6cWlTZApVUVZYYktVRlFGVVgvZklnNHlDM290NWxSakw3QjR1VDJyYnI0dEhNYkUySy92ZGVUTXVBNUo0Z0pHV0IvRzBqCmtWSldYYmNJVVFDbGZzMUVQZDQ5b2VDdzBianRXOG9HSkt3S2NYYTloK1U1QytCVktTN21LNm9veUFqQ0kzRE4KNW9NS0VCdlM0aElqdFBTYjJlOE5HOWNCaGd2TXRTU2pITGRXaHpINUlrZ013dWJTUldMOEJqRDd1SzVFWmJteQpOMzNMSGFldEFIMTZQM0IvT0F0WGJWcmk2aWM2Q2lLbXBseTdhWnlGcitEeW92b2NpdjNxNFRtZVVwaHNRQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: "298101684398995518"
name: 298101684398995518-c380e8dff45a3440b8f8dfda227eccfa6
current-context: 298101684398995518-c380e8dff45a3440b8f8dfda227eccfa6
kind: Config
preferences: {}
users:
- name: "298101684398995518"
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwVENDQXJtZ0F3SUJBZ0lDRDNrd0RRWUpLb1pJaHZjTkFRRUxCUUF3YWpFcU1DZ0dBMVVFQ2hNaFl6TTQKTUdVNFpHWm1ORFZoTXpRME1HSTRaamhrWm1SaE1qSTNaV05qWm1FMk1SQXdEZ1lEVlFRTEV3ZGtaV1poZFd4MApNU293S0FZRFZRUURFeUZqTXpnd1pUaGtabVkwTldFek5EUXdZamhtT0dSbVpHRXlNamRsWTJObVlUWXdIaGNOCk1qTXdOVEkwTURZME16QXdXaGNOTWpZd05USXpNRFkwT0RJMVdqQS9NUlV3RXdZRFZRUUtFd3h6ZVhOMFpXMDYKZFhObGNuTXhDVEFIQmdOVkJBc1RBREViTUJrR0ExVUVBeE1TTWprNE1UQXhOamcwTXprNE9UazFOVEU0TUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBcU85R3YyRWJsUWt5ZFJmR2FTK0NabndVClMyZXFRaUJTL1JxRlVyRTlxR2dsYWtMS0g3aGZmMjdXZXppVTNzQWJQT2RLUEtSQWpSZy9jcnc4WTRXVTV0clAKWUZIb2IwTnoyMjVWcFl1YUlGWnhIVzRLTTlqSzM1Q0dQNmJDK3FCOXBGV0JxcDl1bkJKS0RKbFBSUUJLUDVucQpRRmx6aG0wQ2E1a2haNXovNWczeitpRlVWck1zazlJWGVDc2dFeE5kMjE1ckRHUUhKRVhkSlB2T2RpVmlJTUF4CmdtNmI5SzRHVUZnRXVWa0tROU1lNTVQQ2NuMnVYbnFZRVA1ckZZSU81SUFtVFlhV016NUJCZnZDTDZiRndocEIKMVR5UHVNWjRkWXZjZkNXVmNFQWpuZDdmMEN0aHdEL2FiYTNsT1JGbTB4UFVLSzRxY1FTM1kxYWhHaURBc1FJRApBUUFCbzRHck1JR29NQTRHQTFVZER3RUIvd1FFQXdJSGdEQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFNCkJnTlZIUk1CQWY4RUFqQUFNRHdHQ0NzR0FRVUZCd0VCQkRBd0xqQXNCZ2dyQmdFRkJRY3dBWVlnYUhSMGNEb3YKTDJObGNuUnpMbUZqY3k1aGJHbDVkVzR1WTI5dEwyOWpjM0F3TlFZRFZSMGZCQzR3TERBcW9DaWdKb1lrYUhSMApjRG92TDJObGNuUnpMbUZqY3k1aGJHbDVkVzR1WTI5dEwzSnZiM1F1WTNKc01BMEdDU3FHU0liM0RRRUJDd1VBCkE0SUJBUUNJV0VSZzFUU3IrUEg2bHh1enhTd2lEWHlGbWoxdXJZays1clhKUVZQSnVmYlF5T2ZremRIUThGWWkKSGQ5bUQxQVVKKzNGQWh1Yyt0aUFzaDZXbW5oK0s3Q1k2K0xJRWZNYm5hWlJzckQ1R1M0YjJMYWJRUE5QWXVXQQoyNjVIWWNwV1BOUE5ENFNWV1VWbGRvNi9TZmdoY2RyZG1jUERMcG56SWUzaTdKQ0NYWEJmbDNjZTdWUXU0Vk53CkVzVGQ0ZURGYTdoTlBWZ25yanVmZjBCNzZjU1hySGJkblEzdmFFcnBGUXh4elNCSnFnQTUwY0gwT21xMXRHUWEKWlZlbzBjWkRpS28rTmdnVm9xVUNtanpab0JZZjRkUmVnQXUzZ3g5eEhqVGRpY0hrRTkrdmNmS2xtRy9xZ01oRQpCbzl5WFVtc0IyUTN1b0UrRkxjZ1VTTmRodXk2Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBcU85R3YyRWJsUWt5ZFJmR2FTK0NabndVUzJlcVFpQlMvUnFGVXJFOXFHZ2xha0xLCkg3aGZmMjdXZXppVTNzQWJQT2RLUEtSQWpSZy9jcnc4WTRXVTV0clBZRkhvYjBOejIyNVZwWXVhSUZaeEhXNEsKTTlqSzM1Q0dQNmJDK3FCOXBGV0JxcDl1bkJKS0RKbFBSUUJLUDVucVFGbHpobTBDYTVraFo1ei81ZzN6K2lGVQpWck1zazlJWGVDc2dFeE5kMjE1ckRHUUhKRVhkSlB2T2RpVmlJTUF4Z202YjlLNEdVRmdFdVZrS1E5TWU1NVBDCmNuMnVYbnFZRVA1ckZZSU81SUFtVFlhV016NUJCZnZDTDZiRndocEIxVHlQdU1aNGRZdmNmQ1dWY0VBam5kN2YKMEN0aHdEL2FiYTNsT1JGbTB4UFVLSzRxY1FTM1kxYWhHaURBc1FJREFRQUJBb0lCQUFoL3FSNTlveWFYUk51UgpLNkVsQzdsZUtxTTBmdU0rdnc0T3BJQnBmRUdabzdBNTFmTk1ramxWK1NKUDBXVjNZcWRvdDFwZnBRTzBJWlVECkZVS29lTG80YmRCWnJvalNhdVN5STBybHdBWTZjd3hZK2RocjRxRG1vMnBXV0Y3RmJpeXpSSWV4NTUyZ2FldEMKVnpPUWRTdkg4WG4xUmhPUUxsdjlZeW5VUXlkdW5WZndtY0NsM2ZsVjZqY3BoaHJYNmgrNzZjOVRGQXRpUDFlWAprNXNsOVUrZzl5N3ZlbzFEY2s4eXBENnZSMlF1MldKWlZLRDQycG52Y0YrUzlEYlA4UWRFLytlZ0Y5OEhSRitmClBoMHNaa2ErQ3R5dHVOWnVXaW5hN3hBRnI0cDRndXZ2U1RXVm02enpHU3ZhSkJZRC9CSjVQVThieGQ2NGRMNlAKVXVka0d2VUNnWUVBMEc5V09WbHJ5U0ZrMnhhOXk3T0RMSm13QXlJL0J3VkF3c2VUd0VOUjIxT1MxdmV1ajFYWgozc0p3emlubEpBTCt4dm9Sem0xbWljRnlDMUhqM1VZaytPck1IM1RyOW9sWnZ0VFhSbjNZeWtjUEl3Ny9acXlsCkV1dzhrZWZBSVJFZlV5YVlCUzNvOG5DUUtyVDdyWEV2Z0lOWUJGWVFCL0dpSW93Z1NUZ2RMSnNDZ1lFQXozeGIKQWd1c1I4b0ZPWUJ0bnBNZWNXdHp2WjRqTDVyWDIwQTN2bm9qc3hlS2QxdEJ3aTEzRnZjeUI2TDZuQ1NNS24xQQp6MFVJbENGREVqZzA1SHRDc3MzOGRRNHVIUG16eXdob2NiazRBeWdYcHVqNnA2MDdYS3NuN2xiWG9PMnV6SXlKCkp5QWpid2ozejN1UWNsQmhFOXF5UnpjOXN4MUszUGtQajg5MHJxTUNnWUJwSzRScU00QjdYK292MGUyNlZyMmQKUjM3VVZmZFBaNHNodk9vRVhQTjBvMXE0TlFsVE1aSlpIK3NqVzJoUEgyUEdxbTlKcFZIVHVGUCsramJyYzNVOApVOXpqRW0vdFdhaDY3WkloODJYcnlxY01uWWlwR2Z2QTdJb3paS2hCQnc2ek9nb0Nzd09UTU5ETmU3eHg2Mlo0CmhjMW5nclZjRE1RdWdsM1lGQVJFZVFLQmdHNTJhMUZVZTUwZ3ZkVldQWVllRnlnVkorSjhyWWpyckI0TE8ySksKVG5WTGhDbDFTVFlpMUhOQ21iMGRGTVZLWStFL0crRDloTXF3UnJBTmdvTmQ2QzJmb3RlQy9DUHJBTUNJTW1yUgpURFBLQllXVUpkWmRVT3hPSncwcDZOVEJsYjFLMkw0ZXl4NlRMTE9tdWtsUjU4MFZNckxkZ3hpMzhLSmlhdG1LCmZqbDNBb0dBYTlMVDZtTm9qejc1OVB2eCtwNEJoemhRakpSQm1ITUNLdUNoTnFYTkxwTmx3MXJscHluUDFjcXgKNlhjL09iUVdrSHJEVUpUb2VyamZPS05HTkl4cUdOcDdHMm5GVWorT290UElkVEpKU1ErQVNtWU5HSlJWVUJIWQpWYmNLWENSZE1yQTNoNFB2RUl2V0M4d21iZEtaYnBLYUI0NzdVeEF3S2gxYmpEcnU1OWs9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

View File

@ -0,0 +1,19 @@
apiVersion: v1
clusters:
- cluster:
server: https://10.201.11.56:6443
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ2akNDQXRLZ0F3SUJBZ0lDRU80d0RRWUpLb1pJaHZjTkFRRUxCUUF3YWpFcU1DZ0dBMVVFQ2hNaFkyRmwKWXpFeU56UmtZV0kwTURSaU9EUmlOR1ZoTVRVNE9HWmtNakEwWVdNMU1SQXdEZ1lEVlFRTEV3ZGtaV1poZFd4MApNU293S0FZRFZRUURFeUZqWVdWak1USTNOR1JoWWpRd05HSTROR0kwWldFeE5UZzRabVF5TURSaFl6VXdIaGNOCk1qTXdOekkyTURJeU9EQXdXaGNOTkRNd056SXhNREl6TXpVMFdqQnFNU293S0FZRFZRUUtFeUZqWVdWak1USTMKTkdSaFlqUXdOR0k0TkdJMFpXRXhOVGc0Wm1ReU1EUmhZelV4RURBT0JnTlZCQXNUQjJSbFptRjFiSFF4S2pBbwpCZ05WQkFNVElXTmhaV014TWpjMFpHRmlOREEwWWpnMFlqUmxZVEUxT0RobVpESXdOR0ZqTlRDQ0FTSXdEUVlKCktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQUt4cHVSc3FnMVhTaUZTVk51bzhCRG44Qml0WW5VMzAKWU16RHlaQXhUSWFwSmpxNXI4MHAzM0k3L0lNaFFPbWtNRXJsMDVMZmpXNlFxTFlDUFVtck1LL2RyaDBMd1hRZgpJeUQ0TmpzYm92cnFpMU9ZeXZCUzZFZlg2RWh2am1ZN2d3TnRQbUFqY1IweEd5ZHlqdmtlQ1M3SXJKVDlzSGdOClFrbGJxRStqUFU2NWpzVEd5cnNzZUo3aXBkSXg4NE94VURNWFBsOUN1NHlzWDc0NU4zYkxEaTJFbWJMbWNqYXkKeElEaGp2K2RoL0psQ1lNQnRScWpTWFpuY0kvdHc5OUNmUmU0aDlMNWNjd0pQd3pjdFhPM2FTSFN3bC8wZzZlQQovK2FScEQvNTlleTdZbWNHUDliN3piNitIUUJDUytmekZKUU5WRFJOTUpKUkxGcjFaNFhBbVJFQ0F3RUFBYU9CCm1UQ0JsakFPQmdOVkhROEJBZjhFQkFNQ0Fxd3dEd1lEVlIwVEFRSC9CQVV3QXdFQi96QThCZ2dyQmdFRkJRY0IKQVFRd01DNHdMQVlJS3dZQkJRVUhNQUdHSUdoMGRIQTZMeTlqWlhKMGN5NWhZM011WVd4cGVYVnVMbU52YlM5dgpZM053TURVR0ExVWRId1F1TUN3d0txQW9vQ2FHSkdoMGRIQTZMeTlqWlhKMGN5NWhZM011WVd4cGVYVnVMbU52CmJTOXliMjkwTG1OeWJEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFOSkhCaW9oVjNuekI1SHp5cW1lS3ZXUzAKOWtXVzE4UVBMQkJaMWVERHQ5RjFtSXd5ZjB0RUVJQ2h0eXMxQ1BuSjN6ejZXRkt4aENvZTlINW4yOGZQckwraQo3SHUyN1RGWUs1WGlVK1dYaDR6QWpxdUxNNWZ0V0YyU3JjNHdxeERkZnEyeXRPNHA4UEpHSUVpRTc3WnJpU3BCCkw4OENpbU5WZ1VuVUZJSVE0OUt3SDZCbVVUV3ljV0JvSHBKK3VJT0pCQ205MHc5V2d4aDQrVGZqR09NcDVaM2oKS0pRR21pWVN3cklKMVhpeHB0Um5rRXF2eGljcWNPNlhWNjRIUjJuekpDMlpqT002UWx3ZTJTbnphaS9TQjN0SwpyU3krdnJKSmI5emtuQWpQSmovUURxeDVlVldjTTVtc0xGSVBQc3F2enNVM0Y1dGIvVllHOXA1NTRLcXEyUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: "282060690334189826"
name: 282060690334189826-caec1274dab404b84b4ea1588fd204ac5
current-context: 282060690334189826-caec1274dab404b84b4ea1588fd204ac5
kind: Config
preferences: {}
users:
- name: "282060690334189826"
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwVENDQXJtZ0F3SUJBZ0lDRVBBd0RRWUpLb1pJaHZjTkFRRUxCUUF3YWpFcU1DZ0dBMVVFQ2hNaFkyRmwKWXpFeU56UmtZV0kwTURSaU9EUmlOR1ZoTVRVNE9HWmtNakEwWVdNMU1SQXdEZ1lEVlFRTEV3ZGtaV1poZFd4MApNU293S0FZRFZRUURFeUZqWVdWak1USTNOR1JoWWpRd05HSTROR0kwWldFeE5UZzRabVF5TURSaFl6VXdIaGNOCk1qTXdOekkzTURZeE5UQXdXaGNOTWpZd056STJNRFl5TURFNVdqQS9NUlV3RXdZRFZRUUtFd3h6ZVhOMFpXMDYKZFhObGNuTXhDVEFIQmdOVkJBc1RBREViTUJrR0ExVUVBeE1TTWpneU1EWXdOamt3TXpNME1UZzVPREkyTUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBcEo3b20wTk1LeFpOUkU1RDVuWXQwcGNWCjdTL3BmNG95TDZLdkNuVHU3andmbTNydDFTNlRLWHNSV0dRMC81MTA0UUd3Q2dCY29qWk00cnF3M0FDSXVlVVEKalhIUktLd0dCNDN6VnVrbDQ5RTZsWW1wdWI5LzJqVVczNmFwd0ZYYXUyZzNmTlNpUGZxWWJwVUh0QjB6SGtCawpoRkxKM0xXYjJSU0pRbjkzaExYczM3SmhTUU02WWExTk1RY2FlUkxyM2FoTTIwTTFQalU5c3BCMTVlclFnMC9EClFJQVExWmgwUGtkTVB6eFJlSHpTdjMzZUZHY1FDZVJNNHoyZW9jNUh2d2NjeUZnUU84VVhaeURMSm1BY1E5S2oKY3FnZUd3QzBGM1p4cEVPWEtJR3BHZmg3eFg4MnhGWUhodEhDeE5PZnQ3QlIvdnRZNW9GcWpTdEgrd3dWandJRApBUUFCbzRHck1JR29NQTRHQTFVZER3RUIvd1FFQXdJSGdEQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFNCkJnTlZIUk1CQWY4RUFqQUFNRHdHQ0NzR0FRVUZCd0VCQkRBd0xqQXNCZ2dyQmdFRkJRY3dBWVlnYUhSMGNEb3YKTDJObGNuUnpMbUZqY3k1aGJHbDVkVzR1WTI5dEwyOWpjM0F3TlFZRFZSMGZCQzR3TERBcW9DaWdKb1lrYUhSMApjRG92TDJObGNuUnpMbUZqY3k1aGJHbDVkVzR1WTI5dEwzSnZiM1F1WTNKc01BMEdDU3FHU0liM0RRRUJDd1VBCkE0SUJBUUJXdTNUMzNlQVVOSHZKeTdxYnBKUTlpSUNmWVJ0S2pTVlJKK21oMXE0SzJ0SmtJS3ZiOFh5cTZmbUEKNWI1Qk95QjFyZDFFVUI5ZDJSVFVoMjJxa21EaWFEcFE5bk8wSjNKRnhMQU5xbHFjNjl3RDhYU0k5bE5qVTVZZQorTDdJSVk3MHcwMTlNM0g0elUwd1kzVWVreFRCZC8reCtxRHEyaHJoWUpPbGgrdHBlSmRmMGc1QTR2aWQzY21tCmV1QjlmbDV5SjNyby9BNmd6bm5heGpNY21waHN3UElZVGYrdGJnR0J5S21scGlhU01IdXB6allWbm4zUEVsYjQKUFZOZ1NqVzU1Y0NHVlNoRTVjaDRmbytzKy9UVm9ZV3pmVmNzdW12djZGZG90YUpRQ1dIQU02azlKTlZiYmdDNQpoL0tsVGFrcUZMTk5idXBheEVQSnpwRmNtaUxxCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBcEo3b20wTk1LeFpOUkU1RDVuWXQwcGNWN1MvcGY0b3lMNkt2Q25UdTdqd2ZtM3J0CjFTNlRLWHNSV0dRMC81MTA0UUd3Q2dCY29qWk00cnF3M0FDSXVlVVFqWEhSS0t3R0I0M3pWdWtsNDlFNmxZbXAKdWI5LzJqVVczNmFwd0ZYYXUyZzNmTlNpUGZxWWJwVUh0QjB6SGtCa2hGTEozTFdiMlJTSlFuOTNoTFhzMzdKaApTUU02WWExTk1RY2FlUkxyM2FoTTIwTTFQalU5c3BCMTVlclFnMC9EUUlBUTFaaDBQa2RNUHp4UmVIelN2MzNlCkZHY1FDZVJNNHoyZW9jNUh2d2NjeUZnUU84VVhaeURMSm1BY1E5S2pjcWdlR3dDMEYzWnhwRU9YS0lHcEdmaDcKeFg4MnhGWUhodEhDeE5PZnQ3QlIvdnRZNW9GcWpTdEgrd3dWandJREFRQUJBb0lCQUFMU0lrUSswL2hOQ29mbwpHMnZBaktwMklrOE5LaUFnV3huTDNObitCUFlhRzZTTFo3WG1kV2taamNPSS9BdUJSRFp5MC9SbjZ5NXdaY0xnCjFoVC9BVmpHSHhGOWFNc2NuNEhUb2Q3VVllelVjZitMKzFlT2UzOWV0NFNmazNzVFBZdEdqdVRacytvQitFaTAKend2OEVCc3RtVXRYSzlSWFhGTk04Y2tzNi94ZkpxVU9RVHhxVXhuZHhwMndDSUM2RWZlMkw5T1Q2QjVhMGw1UQo1aWh5ZmhQQlJBeVpFbFRhOGIvL2h4aGRhdU14N1BySUZ3Wk1tT0M2TDg4SDlSSmtKb0hOZHc1eENHUko4a09DCnNUOHlaZUhjcGw5Tm15YzBVUFQzTm5NdFpUR1pjaGRLanliNllodnhwK2p5bzdnK1FodHl3TXZIWWM4MWhVQzcKMGFZZklORUNnWUVBMDQrd0RtUjcwNFk3VUhFZHltdy9YSEd6bkZPRkNyWVdXaEFEditTci9XRE9td3RsUTJFaApmWXVWYTE2d1pzVW5MY0VsNDFwYVZzOXdOVERJakN1eWZhQ3hOOEZ2VVBEeHp5OGs4Y3I1MW8remEzbVNhUkxZCkRWSE16WTcvakhWdWIyYTFkY0trN2MwQmszUDFVbkhYTFh6cTVnUlpvdXQ4dHhUYktSamdxT2tDZ1lFQXh6TVUKdU4zS1RmZEkyQ3VXdjFtRXdXVVU3L1QvTkVaQTZ5QlNzMnNaVWRNWWtWUVViNDAvNHh0RCt1T2ZBZ3AxU285UApsc3FNa2JlVzJTK3BRRzRVU2o1Qm8yVkR2ZG5vVzBOa1QzZEtxOFZUWGtmMjFCUG4zN0swQ0V3Qy9RWG9OaHpqCkxjZ2xDVXBjZHlDa05VOGRwZ3Nvd2N5TEFqWnc0SXhiYm5TU1A3Y0NnWUJnTG93cER1L295N2I5ckYrUjNzS3oKb1pHNXVaTGJ1c3JRcVVVN0laZzd1cDVUaU12QjVVL1hodlVvZWtVU2hBRjY0THY3NytEd1pLQ3IzZ0RmRVNLMQowSytoSEpVaUpGaWJDK0RzK0kyN1NWdVZ1aENoS29zRkN6SmtKZVh5a3BUaG1yMVd5MlkySXFUYng3VTVoVDRCCmxUQXA0TUpydWtuWjVtWjQrYkZ4dVFLQmdRQ2lEY2haN1BWY0lFUyt1QmRYYkRnNExVZXZQeDB2SmNoQ2dIVkgKU1dXN3o0UTVGckhaWG93TzhtdUhmQTRyMXQ0ODNnSGRwc0pjK1lKYkJnOG5QMlo2VDlPT1hoK1NIK2lMOW5Odwp3cGVZemx0WVpDdEZ0VHY2SEtPaDdGU3lDMUF5VmFYcjVOdGNoNFpaMDlCREhpMzhteTk1R2pJc2hxV2x5QW5KCi9rUE1XUUtCZ0dvL0xuT2hzd1pUV2hQUDVGR0NWbmdHNWhWOW1PWjRsTEI1MitTcG10VFMwQ1NKbVhCN1hMRTIKbDFXb2ZtSGx1azlQSy95dFphZ2hLMXd1QVVuVnovRmk5UnByS0tKQWZ4S0liaWVCTVZ6TC93b3F0MzYyOGRXRApYVGh5VXRRRS96MVNpbmRsdHZDMXR2cWQ1ZzRYN0JWaSs2NDlHV3NLcm9zVnNYMVFmUjlrCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

View File

@ -0,0 +1,19 @@
apiVersion: v1
clusters:
- cluster:
server: https://10.201.127.46:6443
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ2akNDQXRLZ0F3SUJBZ0lDRHhzd0RRWUpLb1pJaHZjTkFRRUxCUUF3YWpFcU1DZ0dBMVVFQ2hNaFl6TTQKTUdVNFpHWm1ORFZoTXpRME1HSTRaamhrWm1SaE1qSTNaV05qWm1FMk1SQXdEZ1lEVlFRTEV3ZGtaV1poZFd4MApNU293S0FZRFZRUURFeUZqTXpnd1pUaGtabVkwTldFek5EUXdZamhtT0dSbVpHRXlNamRsWTJObVlUWXdIaGNOCk1qTXdOVEU1TURJek16QXdXaGNOTkRNd05URTBNREl6T0RVMldqQnFNU293S0FZRFZRUUtFeUZqTXpnd1pUaGsKWm1ZME5XRXpORFF3WWpobU9HUm1aR0V5TWpkbFkyTm1ZVFl4RURBT0JnTlZCQXNUQjJSbFptRjFiSFF4S2pBbwpCZ05WQkFNVElXTXpPREJsT0dSbVpqUTFZVE0wTkRCaU9HWTRaR1prWVRJeU4yVmpZMlpoTmpDQ0FTSXdEUVlKCktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQU9FTmlzRWtSblNsSDhtRDJFUkFoS2ZWdWkyN0hTUFMKQTViT2lKdDZWNnRxVHhmTWRwR0RIMTVCbFlKL1laMFZyeERGUjVyMkJBREVkcXdsVG10NWozTFVIcXN6MnRoKwp2RzFrY0UyMmhUdFNtR05KQjhjbzA2YWNxaHV6YlhMbEZMQlc5eURNVnNENWc4RFBvZzh4QnFXZGg2NVRqeGx5ClkwZjJLeUVBS2V6YUFzc3RHV0swSDIvU2EvenZlb25GNnBJREtKcHh6SjZOSTZ5dUdlTk5hRkMwYXNTTVRJSjIKZHFGT01uWFpFdmZqTVlhU2QxWk5FdFUweUxkYzEyRDlVRmJUamxMSEZxcG9rYit2a202T0tGNi9iOUhCN0xXNgpsZFZMTFdHUkhrbS81Vmg5NTVnOVJFUUNVYVN4THpiSkwrVzlBU3puWWJlcnc0RUtpWWxjSUkwQ0F3RUFBYU9CCm1UQ0JsakFPQmdOVkhROEJBZjhFQkFNQ0Fxd3dEd1lEVlIwVEFRSC9CQVV3QXdFQi96QThCZ2dyQmdFRkJRY0IKQVFRd01DNHdMQVlJS3dZQkJRVUhNQUdHSUdoMGRIQTZMeTlqWlhKMGN5NWhZM011WVd4cGVYVnVMbU52YlM5dgpZM053TURVR0ExVWRId1F1TUN3d0txQW9vQ2FHSkdoMGRIQTZMeTlqWlhKMGN5NWhZM011WVd4cGVYVnVMbU52CmJTOXliMjkwTG1OeWJEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTVJOVjF0K1F6TUo5ZDlkekNDZzVULzkKQnI2T2piQVFSeHhodkVDV0JmODVOeEZUWDNYRmMzbVpkcytNeWFRRERhcUhjbzRmNGZHZ3hKRjVldmZ6cWlTZApVUVZYYktVRlFGVVgvZklnNHlDM290NWxSakw3QjR1VDJyYnI0dEhNYkUySy92ZGVUTXVBNUo0Z0pHV0IvRzBqCmtWSldYYmNJVVFDbGZzMUVQZDQ5b2VDdzBianRXOG9HSkt3S2NYYTloK1U1QytCVktTN21LNm9veUFqQ0kzRE4KNW9NS0VCdlM0aElqdFBTYjJlOE5HOWNCaGd2TXRTU2pITGRXaHpINUlrZ013dWJTUldMOEJqRDd1SzVFWmJteQpOMzNMSGFldEFIMTZQM0IvT0F0WGJWcmk2aWM2Q2lLbXBseTdhWnlGcitEeW92b2NpdjNxNFRtZVVwaHNRQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: "298101684398995518"
name: 298101684398995518-c380e8dff45a3440b8f8dfda227eccfa6
current-context: 298101684398995518-c380e8dff45a3440b8f8dfda227eccfa6
kind: Config
preferences: {}
users:
- name: "298101684398995518"
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwVENDQXJtZ0F3SUJBZ0lDRDNrd0RRWUpLb1pJaHZjTkFRRUxCUUF3YWpFcU1DZ0dBMVVFQ2hNaFl6TTQKTUdVNFpHWm1ORFZoTXpRME1HSTRaamhrWm1SaE1qSTNaV05qWm1FMk1SQXdEZ1lEVlFRTEV3ZGtaV1poZFd4MApNU293S0FZRFZRUURFeUZqTXpnd1pUaGtabVkwTldFek5EUXdZamhtT0dSbVpHRXlNamRsWTJObVlUWXdIaGNOCk1qTXdOVEkwTURZME16QXdXaGNOTWpZd05USXpNRFkwT0RJMVdqQS9NUlV3RXdZRFZRUUtFd3h6ZVhOMFpXMDYKZFhObGNuTXhDVEFIQmdOVkJBc1RBREViTUJrR0ExVUVBeE1TTWprNE1UQXhOamcwTXprNE9UazFOVEU0TUlJQgpJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBcU85R3YyRWJsUWt5ZFJmR2FTK0NabndVClMyZXFRaUJTL1JxRlVyRTlxR2dsYWtMS0g3aGZmMjdXZXppVTNzQWJQT2RLUEtSQWpSZy9jcnc4WTRXVTV0clAKWUZIb2IwTnoyMjVWcFl1YUlGWnhIVzRLTTlqSzM1Q0dQNmJDK3FCOXBGV0JxcDl1bkJKS0RKbFBSUUJLUDVucQpRRmx6aG0wQ2E1a2haNXovNWczeitpRlVWck1zazlJWGVDc2dFeE5kMjE1ckRHUUhKRVhkSlB2T2RpVmlJTUF4CmdtNmI5SzRHVUZnRXVWa0tROU1lNTVQQ2NuMnVYbnFZRVA1ckZZSU81SUFtVFlhV016NUJCZnZDTDZiRndocEIKMVR5UHVNWjRkWXZjZkNXVmNFQWpuZDdmMEN0aHdEL2FiYTNsT1JGbTB4UFVLSzRxY1FTM1kxYWhHaURBc1FJRApBUUFCbzRHck1JR29NQTRHQTFVZER3RUIvd1FFQXdJSGdEQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFNCkJnTlZIUk1CQWY4RUFqQUFNRHdHQ0NzR0FRVUZCd0VCQkRBd0xqQXNCZ2dyQmdFRkJRY3dBWVlnYUhSMGNEb3YKTDJObGNuUnpMbUZqY3k1aGJHbDVkVzR1WTI5dEwyOWpjM0F3TlFZRFZSMGZCQzR3TERBcW9DaWdKb1lrYUhSMApjRG92TDJObGNuUnpMbUZqY3k1aGJHbDVkVzR1WTI5dEwzSnZiM1F1WTNKc01BMEdDU3FHU0liM0RRRUJDd1VBCkE0SUJBUUNJV0VSZzFUU3IrUEg2bHh1enhTd2lEWHlGbWoxdXJZays1clhKUVZQSnVmYlF5T2ZremRIUThGWWkKSGQ5bUQxQVVKKzNGQWh1Yyt0aUFzaDZXbW5oK0s3Q1k2K0xJRWZNYm5hWlJzckQ1R1M0YjJMYWJRUE5QWXVXQQoyNjVIWWNwV1BOUE5ENFNWV1VWbGRvNi9TZmdoY2RyZG1jUERMcG56SWUzaTdKQ0NYWEJmbDNjZTdWUXU0Vk53CkVzVGQ0ZURGYTdoTlBWZ25yanVmZjBCNzZjU1hySGJkblEzdmFFcnBGUXh4elNCSnFnQTUwY0gwT21xMXRHUWEKWlZlbzBjWkRpS28rTmdnVm9xVUNtanpab0JZZjRkUmVnQXUzZ3g5eEhqVGRpY0hrRTkrdmNmS2xtRy9xZ01oRQpCbzl5WFVtc0IyUTN1b0UrRkxjZ1VTTmRodXk2Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBcU85R3YyRWJsUWt5ZFJmR2FTK0NabndVUzJlcVFpQlMvUnFGVXJFOXFHZ2xha0xLCkg3aGZmMjdXZXppVTNzQWJQT2RLUEtSQWpSZy9jcnc4WTRXVTV0clBZRkhvYjBOejIyNVZwWXVhSUZaeEhXNEsKTTlqSzM1Q0dQNmJDK3FCOXBGV0JxcDl1bkJKS0RKbFBSUUJLUDVucVFGbHpobTBDYTVraFo1ei81ZzN6K2lGVQpWck1zazlJWGVDc2dFeE5kMjE1ckRHUUhKRVhkSlB2T2RpVmlJTUF4Z202YjlLNEdVRmdFdVZrS1E5TWU1NVBDCmNuMnVYbnFZRVA1ckZZSU81SUFtVFlhV016NUJCZnZDTDZiRndocEIxVHlQdU1aNGRZdmNmQ1dWY0VBam5kN2YKMEN0aHdEL2FiYTNsT1JGbTB4UFVLSzRxY1FTM1kxYWhHaURBc1FJREFRQUJBb0lCQUFoL3FSNTlveWFYUk51UgpLNkVsQzdsZUtxTTBmdU0rdnc0T3BJQnBmRUdabzdBNTFmTk1ramxWK1NKUDBXVjNZcWRvdDFwZnBRTzBJWlVECkZVS29lTG80YmRCWnJvalNhdVN5STBybHdBWTZjd3hZK2RocjRxRG1vMnBXV0Y3RmJpeXpSSWV4NTUyZ2FldEMKVnpPUWRTdkg4WG4xUmhPUUxsdjlZeW5VUXlkdW5WZndtY0NsM2ZsVjZqY3BoaHJYNmgrNzZjOVRGQXRpUDFlWAprNXNsOVUrZzl5N3ZlbzFEY2s4eXBENnZSMlF1MldKWlZLRDQycG52Y0YrUzlEYlA4UWRFLytlZ0Y5OEhSRitmClBoMHNaa2ErQ3R5dHVOWnVXaW5hN3hBRnI0cDRndXZ2U1RXVm02enpHU3ZhSkJZRC9CSjVQVThieGQ2NGRMNlAKVXVka0d2VUNnWUVBMEc5V09WbHJ5U0ZrMnhhOXk3T0RMSm13QXlJL0J3VkF3c2VUd0VOUjIxT1MxdmV1ajFYWgozc0p3emlubEpBTCt4dm9Sem0xbWljRnlDMUhqM1VZaytPck1IM1RyOW9sWnZ0VFhSbjNZeWtjUEl3Ny9acXlsCkV1dzhrZWZBSVJFZlV5YVlCUzNvOG5DUUtyVDdyWEV2Z0lOWUJGWVFCL0dpSW93Z1NUZ2RMSnNDZ1lFQXozeGIKQWd1c1I4b0ZPWUJ0bnBNZWNXdHp2WjRqTDVyWDIwQTN2bm9qc3hlS2QxdEJ3aTEzRnZjeUI2TDZuQ1NNS24xQQp6MFVJbENGREVqZzA1SHRDc3MzOGRRNHVIUG16eXdob2NiazRBeWdYcHVqNnA2MDdYS3NuN2xiWG9PMnV6SXlKCkp5QWpid2ozejN1UWNsQmhFOXF5UnpjOXN4MUszUGtQajg5MHJxTUNnWUJwSzRScU00QjdYK292MGUyNlZyMmQKUjM3VVZmZFBaNHNodk9vRVhQTjBvMXE0TlFsVE1aSlpIK3NqVzJoUEgyUEdxbTlKcFZIVHVGUCsramJyYzNVOApVOXpqRW0vdFdhaDY3WkloODJYcnlxY01uWWlwR2Z2QTdJb3paS2hCQnc2ek9nb0Nzd09UTU5ETmU3eHg2Mlo0CmhjMW5nclZjRE1RdWdsM1lGQVJFZVFLQmdHNTJhMUZVZTUwZ3ZkVldQWVllRnlnVkorSjhyWWpyckI0TE8ySksKVG5WTGhDbDFTVFlpMUhOQ21iMGRGTVZLWStFL0crRDloTXF3UnJBTmdvTmQ2QzJmb3RlQy9DUHJBTUNJTW1yUgpURFBLQllXVUpkWmRVT3hPSncwcDZOVEJsYjFLMkw0ZXl4NlRMTE9tdWtsUjU4MFZNckxkZ3hpMzhLSmlhdG1LCmZqbDNBb0dBYTlMVDZtTm9qejc1OVB2eCtwNEJoemhRakpSQm1ITUNLdUNoTnFYTkxwTmx3MXJscHluUDFjcXgKNlhjL09iUVdrSHJEVUpUb2VyamZPS05HTkl4cUdOcDdHMm5GVWorT290UElkVEpKU1ErQVNtWU5HSlJWVUJIWQpWYmNLWENSZE1yQTNoNFB2RUl2V0M4d21iZEtaYnBLYUI0NzdVeEF3S2gxYmpEcnU1OWs9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

View File

@ -0,0 +1,15 @@
USE deploy_ease_dev;
DROP TABLE IF EXISTS dictionary;
CREATE TABLE dictionary
(
id INT AUTO_INCREMENT PRIMARY KEY,
dictionary_code VARCHAR(50) NOT NULL,
dictionary_name VARCHAR(50) NOT NULL,
dictionary_value TEXT,
status TINYINT NOT NULL DEFAULT 1 COMMENT '1、有效 0、无效',
tenant_sharing TINYINT NOT NULL DEFAULT 1 COMMENT '1、共享 0、不共享',
create_time DATETIME NOT NULL DEFAULT NOW(),
update_time DATETIME NOT NULL DEFAULT NOW(),
is_deleted TINYINT NOT NULL DEFAULT 0
);
INSERT INTO dictionary ( dictionary_code, dictionary_name, dictionary_value) VALUE ('JENKINS_BASE_API', 'Jenkins地址', 'http://jenkins-rd.longi.com:8080');

View File

@ -0,0 +1,16 @@
USE deploy_ease_dev;
DROP TABLE IF EXISTS project;
CREATE TABLE project
(
id INT AUTO_INCREMENT PRIMARY KEY,
project_code VARCHAR(50) NOT NULL,
project_name VARCHAR(50) NOT NULL,
tenant_code VARCHAR(50) NOT NULL,
create_time DATETIME NOT NULL DEFAULT NOW(),
update_time DATETIME NOT NULL DEFAULT NOW(),
is_deleted TINYINT NOT NULL DEFAULT 0
);
INSERT INTO project (project_code, project_name, tenant_code)
VALUES ('scp', '计划产品', 'longi');
INSERT INTO project (project_code, project_name, tenant_code)
VALUES ('oms', '订单', 'longi');

View File

@ -0,0 +1,20 @@
USE deploy_ease_dev;
DROP TABLE IF EXISTS project_environment;
CREATE TABLE project_environment
(
id INT AUTO_INCREMENT PRIMARY KEY,
environment_code VARCHAR(50) NOT NULL,
environment_name VARCHAR(50) NOT NULL,
environment_type TINYINT NOT NULL COMMENT '1、K8S 2、Docker 3、单点部署',
project_code VARCHAR(50) NOT NULL,
is_vpn TINYINT NOT NULL,
create_time DATETIME NOT NULL DEFAULT NOW(),
update_time DATETIME NOT NULL DEFAULT NOW(),
is_deleted TINYINT NOT NULL DEFAULT 0
);
INSERT INTO project_environment (environment_code, environment_name, environment_type, is_vpn, project_code)
VALUES ('dev', '开发环境', 1, 1, 'scp');
INSERT INTO project_environment (environment_code, environment_name, environment_type, is_vpn, project_code)
VALUES ('uat', '测试环境', 1, 1, 'scp');
INSERT INTO project_environment (environment_code, environment_name, environment_type, is_vpn, project_code)
VALUES ('prod', '生产环境', 1, 1, 'scp');

View File

@ -0,0 +1,13 @@
USE deploy_ease_dev;
DROP TABLE IF EXISTS tenant;
CREATE TABLE tenant
(
id INT AUTO_INCREMENT PRIMARY KEY,
tenant_code VARCHAR(50) NOT NULL,
tenant_name VARCHAR(50) NOT NULL,
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '1、有效 2、无效',
create_time DATETIME NOT NULL DEFAULT NOW(),
update_time DATETIME NOT NULL DEFAULT NOW(),
is_deleted TINYINT NOT NULL DEFAULT 0
);
INSERT INTO tenant (tenant_code, tenant_name, enabled) VALUES ('longi', '隆基', 1);

View File

@ -0,0 +1,16 @@
USE deploy_ease_dev;
DROP TABLE IF EXISTS tenant_dictionary;
CREATE TABLE tenant_dictionary
(
id INT AUTO_INCREMENT PRIMARY KEY,
dictionary_code VARCHAR(50) NOT NULL,
dictionary_name VARCHAR(50) NOT NULL,
dictionary_value TEXT,
status TINYINT NOT NULL DEFAULT 1 COMMENT '1、有效 0、无效',
tenant_code VARCHAR(50) NOT NULL,
create_time DATETIME NOT NULL DEFAULT NOW(),
update_time DATETIME NOT NULL DEFAULT NOW(),
is_deleted TINYINT NOT NULL DEFAULT 0
);
INSERT INTO tenant_dictionary (dictionary_code, dictionary_name, dictionary_value, tenant_code)
VALUES ('JENKINS_BASE_API', 'Jenkins地址', 'http://jenkins-rd.longi.com:8080', 'longi');

View File

@ -0,0 +1,13 @@
USE deploy_ease_dev;
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id INT AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(50) NOT NULL,
password VARCHAR(200) NOT NULL,
real_name VARCHAR(50) NOT NULL,
create_time DATETIME NOT NULL DEFAULT NOW(),
update_time DATETIME NOT NULL DEFAULT NOW(),
is_deleted TINYINT NOT NULL DEFAULT 0
);
INSERT INTO user(user_name, password, real_name)VALUES ('admin', '123456', '管理员');

View File

@ -0,0 +1,13 @@
USE deploy_ease_dev;
DROP TABLE IF EXISTS user_online;
CREATE TABLE user_online
(
id INT AUTO_INCREMENT PRIMARY KEY,
user_code VARCHAR(50) NOT NULL,
ip_address VARCHAR(200) NOT NULL,
last_time DATETIME NOT NULL,
quit_time DATETIME NOT NULL,
create_time DATETIME NOT NULL DEFAULT NOW(),
update_time DATETIME NOT NULL DEFAULT NOW(),
is_deleted TINYINT NOT NULL DEFAULT 0
)

View File

@ -0,0 +1,12 @@
USE deploy_ease_dev;
DROP TABLE IF EXISTS user_tenant;
CREATE TABLE user_tenant
(
id INT AUTO_INCREMENT PRIMARY KEY,
user_id VARCHAR(50) NOT NULL,
tenant_code VARCHAR(50) NOT NULL,
create_time DATETIME NOT NULL DEFAULT NOW(),
update_time DATETIME NOT NULL DEFAULT NOW(),
is_deleted TINYINT NOT NULL DEFAULT 0
);
INSERT INTO user_tenant (user_id, tenant_code) VALUES ('1', 'longi')

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>deploy-ease-synchronizer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version> <!-- 检查最新版本 -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>${transmittable-thread-local.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>${http5.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>${kubernetes.version}</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson-version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp3.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>com.qc.soft</groupId>
<artifactId>deploy-ease-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
</dependencies>
<parent>
<groupId>com.qc.soft</groupId>
<artifactId>deploy-ease</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
</project>

View File

@ -0,0 +1,18 @@
package com.qc.soft.deploy.ease.synchronizer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootConfiguration
@EnableAutoConfiguration
@EnableScheduling
@EnableAsync
public class DeployEaseSynchronizerApplication {
public static void main(String[] args) {
SpringApplication.run(DeployEaseSynchronizerApplication.class, args);
}
}

View File

@ -0,0 +1,27 @@
spring:
cloud:
nacos:
server-addr: ${NACOS_CONFIG_SERVER}
username: ${NACOS_USER}
password: ${NACOS_PWD}
discovery:
group: ${DEPLOY_ENV}
namespace: ${DEPLOY_ENV}
enabled: true
config:
group: ${DEPLOY_ENV}
namespace: ${DEPLOY_ENV}
extension-configs[0]:
data-id: common.yml
group: common
refresh: false
extension-configs[1]:
data-id: deploy-ease-synchronizer.yml
group: business
refresh: false
config:
override-none: false
allow-override: true
override-system-properties: false
main:
allow-bean-definition-overriding: true

88
pom.xml Normal file
View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qc.soft</groupId>
<artifactId>deploy-ease</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.boot.version>2.3.0.RELEASE</spring.boot.version>
<freemarker.version>2.3.31</freemarker.version>
<fastjson-version>2.0.51</fastjson-version>
<mapstruct.version>1.6.0.RC1</mapstruct.version>
<lombok.version>1.18.22</lombok.version>
<mysql.version>8.0.23</mysql.version>
<druid.version>1.1.10</druid.version>
<spring-statemachine.version>3.2.1</spring-statemachine.version>
<reactor-core.version>3.6.2</reactor-core.version>
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
<http5.version>5.3.1</http5.version>
<commons-lang3.version>3.10</commons-lang3.version>
<hutool.version>5.8.16</hutool.version>
<kubernetes.version>19.0.1</kubernetes.version>
<okhttp3.version>4.9.1</okhttp3.version>
<nacos-client.version>2.3.0</nacos-client.version>
<nacos-cloud.version>2.2.9.RELEASE</nacos-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version> <!-- 检查最新版本 -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${nacos-cloud.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${nacos-cloud.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos-client.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>deploy-ease-core</module>
<module>deploy-ease-api</module>
<module>deploy-ease-synchronizer</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.0</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>