This commit is contained in:
chenjianxing 2020-06-08 13:23:17 +08:00
commit 5ab8c54f93
24 changed files with 9 additions and 797 deletions

View File

@ -18,16 +18,9 @@
<shiro.version>1.5.1</shiro.version>
<java.version>1.8</java.version>
<jmeter.version>5.2.1</jmeter.version>
<kubernetes-client.version>4.9.0</kubernetes-client.version>
</properties>
<dependencies>
<!-- kubernetes client-->
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
<version>${kubernetes-client.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

View File

@ -1,10 +1,6 @@
package io.metersphere.commons.constants;
public enum ResourcePoolTypeEnum {
/**
* k8s 资源池
*/
K8S,
/**
* node controller 资源池
*/

View File

@ -57,7 +57,7 @@ public abstract class AbstractEngine implements Engine {
if (resourcePool == null) {
MSException.throwException("Resource Pool is empty");
}
if (!ResourcePoolTypeEnum.K8S.name().equals(resourcePool.getType()) && !ResourcePoolTypeEnum.NODE.name().equals(resourcePool.getType())) {
if (!ResourcePoolTypeEnum.NODE.name().equals(resourcePool.getType())) {
MSException.throwException("Invalid Resource Pool type.");
}
this.resourceList = testResourceService.getResourcesByPoolId(resourcePool.getId());

View File

@ -12,7 +12,6 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.config.KafkaProperties;
import io.metersphere.i18n.Translator;
import io.metersphere.performance.engine.docker.DockerTestEngine;
import io.metersphere.performance.engine.kubernetes.KubernetesTestEngine;
import io.metersphere.performance.parse.EngineSourceParser;
import io.metersphere.performance.parse.EngineSourceParserFactory;
import io.metersphere.service.FileService;
@ -47,11 +46,8 @@ public class EngineFactory {
final ResourcePoolTypeEnum type = ResourcePoolTypeEnum.valueOf(resourcePool.getType());
switch (type) {
case NODE:
return new DockerTestEngine(loadTest);
case K8S:
return new KubernetesTestEngine(loadTest);
if (type == ResourcePoolTypeEnum.NODE) {
return new DockerTestEngine(loadTest);
}
return null;
}

View File

@ -1,148 +0,0 @@
package io.metersphere.performance.engine.kubernetes;
import com.alibaba.fastjson.JSON;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.metersphere.base.domain.LoadTestWithBLOBs;
import io.metersphere.commons.constants.FileType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.i18n.Translator;
import io.metersphere.performance.engine.AbstractEngine;
import io.metersphere.performance.engine.EngineContext;
import io.metersphere.performance.engine.EngineFactory;
import io.metersphere.performance.engine.kubernetes.crds.jmeter.Jmeter;
import io.metersphere.performance.engine.kubernetes.crds.jmeter.JmeterSpec;
import io.metersphere.performance.engine.kubernetes.provider.ClientCredential;
import io.metersphere.performance.engine.kubernetes.provider.KubernetesProvider;
import org.apache.commons.collections.MapUtils;
import java.util.HashMap;
import java.util.Map;
public class KubernetesTestEngine extends AbstractEngine {
public KubernetesTestEngine(LoadTestWithBLOBs loadTest) {
this.init(loadTest);
}
@Override
public void init(LoadTestWithBLOBs loadTest) {
super.init(loadTest);
}
@Override
public void start() {
Integer sumThreadNum = getRunningThreadNum();
// resourceList size 1
resourceList.forEach(r -> {
String configuration = r.getConfiguration();
ClientCredential clientCredential = JSON.parseObject(configuration, ClientCredential.class);
// 最大并发数
Integer maxConcurrency = clientCredential.getMaxConcurrency();
// 当前测试需要的并发数大于剩余的并发数报错
if (threadNum > maxConcurrency - sumThreadNum) {
MSException.throwException(Translator.get("max_thread_insufficient"));
}
try {
EngineContext context = EngineFactory.createContext(loadTest, r.getId(), threadNum, this.getStartTime(), this.getReportId());
runTest(context, clientCredential);
} catch (Exception e) {
MSException.throwException(e);
}
});
}
private void runTest(EngineContext context, ClientCredential credential) {
KubernetesProvider kubernetesProvider = new KubernetesProvider(JSON.toJSONString(credential));
// create namespace
kubernetesProvider.confirmNamespace(context.getNamespace());
// create cm
try (KubernetesClient client = kubernetesProvider.getKubernetesClient()) {
String configMapName = "jmeter-" + context.getTestId() + "-files";
ConfigMap configMap = client.configMaps().inNamespace(context.getNamespace()).withName(configMapName).get();
if (configMap == null) {
ConfigMap item = new ConfigMap();
item.setMetadata(new ObjectMeta() {{
setName(configMapName);
}});
item.setData(new HashMap<String, String>() {{
put(context.getTestId() + FileType.JMX.suffix(), context.getContent());
if (MapUtils.isNotEmpty(context.getTestData())) {
putAll(context.getTestData());
}
}});
client.configMaps().inNamespace(context.getNamespace()).create(item);
}
}
// create jmeter
// todo image
try {
Jmeter jmeter = new Jmeter();
jmeter.setMetadata(new ObjectMeta() {{
setNamespace(context.getNamespace());
setName(context.getTestId());
}});
jmeter.setSpec(new JmeterSpec() {{
setReplicas(1);
setImage(JMETER_IMAGE);
setEnv(context.getEnv());
}});
LogUtil.info("Load test started. " + context.getTestId());
kubernetesProvider.applyCustomResource(jmeter);
} catch (Exception e) {
MSException.throwException(e);
}
}
@Override
public void stop() {
resourceList.forEach(r -> {
try {
String configuration = r.getConfiguration();
ClientCredential clientCredential = JSON.parseObject(configuration, ClientCredential.class);
KubernetesProvider provider = new KubernetesProvider(JSON.toJSONString(clientCredential));
provider.confirmNamespace(loadTest.getProjectId());
Jmeter jmeter = new Jmeter();
jmeter.setMetadata(new ObjectMeta() {{
setName(loadTest.getId());
setNamespace(loadTest.getProjectId());
}});
jmeter.setSpec(new JmeterSpec() {{
setReplicas(1);
setImage(JMETER_IMAGE);
}});
provider.deleteCustomResource(jmeter);
} catch (Exception e) {
MSException.throwException(e);
}
});
}
@Override
public Map<String, String> log() {
Map<String, String> logs = new HashMap<>();
resourceList.forEach(r -> {
try {
String configuration = r.getConfiguration();
ClientCredential clientCredential = JSON.parseObject(configuration, ClientCredential.class);
KubernetesProvider provider = new KubernetesProvider(JSON.toJSONString(clientCredential));
provider.confirmNamespace(loadTest.getProjectId());
try (KubernetesClient client = provider.getKubernetesClient()) {
String joblog = client.batch().jobs().inNamespace(loadTest.getProjectId()).withName("job-" + loadTest.getId()).getLog();
logs.put(clientCredential.getMasterUrl(), joblog);
}
} catch (Exception e) {
MSException.throwException(e);
}
});
return logs;
}
}

View File

@ -1,36 +0,0 @@
package io.metersphere.performance.engine.kubernetes.crds;
import io.fabric8.kubernetes.client.CustomResource;
public class MeterSphereCustomResource extends CustomResource {
private String crd;
private Object spec;
private Object status;
public String getCrd() {
return crd;
}
public void setCrd(String crd) {
this.crd = crd;
}
public Object getSpec() {
return spec;
}
public void setSpec(Object spec) {
this.spec = spec;
}
public Object getStatus() {
return status;
}
public void setStatus(Object status) {
this.status = status;
}
}

View File

@ -1,10 +0,0 @@
package io.metersphere.performance.engine.kubernetes.crds;
import io.fabric8.kubernetes.api.builder.Function;
import io.fabric8.kubernetes.client.CustomResourceDoneable;
public class MeterSphereCustomResourceDoneable<T extends MeterSphereCustomResource> extends CustomResourceDoneable<T> {
public MeterSphereCustomResourceDoneable(T resource, Function<T, T> function) {
super(resource, function);
}
}

View File

@ -1,6 +0,0 @@
package io.metersphere.performance.engine.kubernetes.crds;
import io.fabric8.kubernetes.client.CustomResourceList;
public class MeterSphereCustomResourceList<T extends MeterSphereCustomResource> extends CustomResourceList<T> {
}

View File

@ -1,33 +0,0 @@
package io.metersphere.performance.engine.kubernetes.crds.jmeter;
import io.metersphere.performance.engine.kubernetes.crds.MeterSphereCustomResource;
public class Jmeter extends MeterSphereCustomResource {
public static final String CRD = "jmeters.metersphere.io";
public static final String KIND = "Jmeter";
private JmeterSpec spec;
private JmeterStatus status;
public Jmeter() {
this.setCrd(CRD);
this.setKind(KIND);
}
@Override
public JmeterSpec getSpec() {
return spec;
}
public void setSpec(JmeterSpec spec) {
this.spec = spec;
}
@Override
public JmeterStatus getStatus() {
return status;
}
public void setStatus(JmeterStatus status) {
this.status = status;
}
}

View File

@ -1,10 +0,0 @@
package io.metersphere.performance.engine.kubernetes.crds.jmeter;
import io.fabric8.kubernetes.api.builder.Function;
import io.fabric8.kubernetes.client.CustomResourceDoneable;
public class JmeterDoneable extends CustomResourceDoneable<Jmeter> {
public JmeterDoneable(Jmeter resource, Function<Jmeter, Jmeter> function) {
super(resource, function);
}
}

View File

@ -1,40 +0,0 @@
package io.metersphere.performance.engine.kubernetes.crds.jmeter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import io.fabric8.kubernetes.api.model.KubernetesResource;
import java.util.HashMap;
import java.util.Map;
@JsonDeserialize
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class JmeterSpec implements KubernetesResource {
private int replicas = 1;
private String image;
private Map<String, String> env = new HashMap<>();
public int getReplicas() {
return replicas;
}
public void setReplicas(int replicas) {
this.replicas = replicas;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public Map<String, String> getEnv() {
return env;
}
public void setEnv(Map<String, String> env) {
this.env = env;
}
}

View File

@ -1,36 +0,0 @@
package io.metersphere.performance.engine.kubernetes.crds.jmeter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import io.fabric8.kubernetes.api.model.KubernetesResource;
@JsonDeserialize
@JsonInclude(JsonInclude.Include.NON_NULL)
public class JmeterStatus implements KubernetesResource {
private String phase;
private String reason;
public String getPhase() {
return phase;
}
public void setPhase(String phase) {
this.phase = phase;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
@Override
public String toString() {
return "JmeterStatus{" +
"phase='" + phase + '\'' +
", reason='" + reason + '\'' +
'}';
}
}

View File

@ -1,267 +0,0 @@
package io.metersphere.performance.engine.kubernetes.provider;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.kubernetes.api.model.*;
import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinition;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.dsl.*;
import io.metersphere.performance.engine.kubernetes.crds.MeterSphereCustomResource;
import io.metersphere.performance.engine.kubernetes.crds.MeterSphereCustomResourceDoneable;
import io.metersphere.performance.engine.kubernetes.crds.MeterSphereCustomResourceList;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.regex.Pattern;
public abstract class AbstractClientProvider {
private static ObjectMapper objectMapper = new ObjectMapper();
private String credential;
public AbstractClientProvider(String credential) {
setCredential(credential);
}
public String getCredential() {
return credential;
}
public void setCredential(String credential) {
this.credential = credential;
}
/**
* OpenShiftClient继承自KubernetesClientOpenShiftClient对OpenShift和kubernetes的共有资源也是用KubernetesClient代理的
* 所以可以在把client提取到抽象类
*/
public KubernetesClient getKubernetesClient() {
ClientCredential providerCredential = JSONObject.parseObject(getCredential(), ClientCredential.class);
io.fabric8.kubernetes.client.ConfigBuilder configBuilder = new ConfigBuilder();
configBuilder.withMasterUrl(providerCredential.getMasterUrl());
configBuilder.withOauthToken(providerCredential.getToken());
configBuilder.withTrustCerts(true);
//设置默认的 namespace null
configBuilder.withNamespace(null);
return new DefaultKubernetesClient(configBuilder.build());
}
public void validateCredential() {
try (KubernetesClient client = getKubernetesClient()) {
client.namespaces().list();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 确保指定的namespace存在不存在直接创建一个
*
* @param namespace namespace标识
* @return
*/
public synchronized String confirmNamespace(String namespace) {
KubernetesClient kubernetesClient = getKubernetesClient();
Namespace currentNamespace = kubernetesClient.namespaces().withName(namespace).get();
if (currentNamespace == null) {
Map<String, String> annotations = new HashMap<>();
Namespace newNamespace = new NamespaceBuilder()
.withNewMetadata()
.withName(namespace)
.withAnnotations(annotations)
.endMetadata()
.build();
currentNamespace = kubernetesClient.namespaces().createOrReplace(newNamespace);
}
return currentNamespace.getMetadata().getName();
}
/**
* 获取集群UUID当前集群UUID等于default namespace的UID
*
* @return
*/
public String getClusterUUID() {
KubernetesClient kubernetesClient = getKubernetesClient();
Namespace defaultNamespace = kubernetesClient.namespaces().withName("kube-system").get();
if (defaultNamespace == null) {
throw new RuntimeException("无法获取集群的kube-system namespace");
} else {
return defaultNamespace.getMetadata().getUid();
}
}
/**
* 确保docker registry存在
* 不存在 创建一个harbor-secret并修改serviceaccount default
*
* @param registry
*/
public void dockerRegistry(DockerRegistry registry) {
if (StringUtils.isEmpty(registry.getUsername()) ||
StringUtils.isEmpty(registry.getPassword()) ||
StringUtils.isEmpty(registry.getUrl())
) {
throw new RuntimeException("Please set the docker registry information");
}
String secretName = "docker-registry-ms-secret";
KubernetesClient kubernetesClient = getKubernetesClient();
Secret secretRegistry = new SecretBuilder()
.withNewMetadata().withName(secretName).endMetadata()
.addToData(".dockerconfigjson", DockerRegistryUtil.getDockerConfig(registry))
.withType("kubernetes.io/dockerconfigjson")
.build();
kubernetesClient.secrets().inNamespace(registry.getNamespace()).createOrReplace(secretRegistry);
//sa
ServiceAccount serviceAccount = kubernetesClient.serviceAccounts().inNamespace(registry.getNamespace())
.withName("default").get();
List<LocalObjectReference> imagePullSecrets = serviceAccount.getImagePullSecrets();
for (LocalObjectReference pullSecret : imagePullSecrets) {
if (secretName.equals(pullSecret.getName())) {
return;
}
}
LocalObjectReference localObjectReference = new LocalObjectReference(secretName);
imagePullSecrets.add(localObjectReference);
serviceAccount.setImagePullSecrets(imagePullSecrets);
kubernetesClient.serviceAccounts().inNamespace(registry.getNamespace())
.createOrReplace(serviceAccount);
}
public <T> T applyCustomResource(MeterSphereCustomResource customResource) throws Exception {
try (KubernetesClient kubernetesClient = getKubernetesClient()) {
CustomResourceDefinition crd = kubernetesClient.customResourceDefinitions().withName(customResource.getCrd()).get();
if (crd == null) {
throw new Exception("CRD does not exists.");
}
MixedOperation<MeterSphereCustomResource, MeterSphereCustomResourceList, MeterSphereCustomResourceDoneable, Resource<MeterSphereCustomResource, MeterSphereCustomResourceDoneable>>
operation = kubernetesClient.customResources(crd, MeterSphereCustomResource.class, MeterSphereCustomResourceList.class, MeterSphereCustomResourceDoneable.class);
MeterSphereCustomResource replace = operation.inNamespace(customResource.getMetadata().getNamespace()).createOrReplace(customResource);
return (T) objectMapper.readValue(objectMapper.writeValueAsString(replace), customResource.getClass());
}
}
public boolean deleteCustomResource(MeterSphereCustomResource customResource) {
try (KubernetesClient kubernetesClient = getKubernetesClient()) {
CustomResourceDefinition crd = kubernetesClient.customResourceDefinitions().withName(customResource.getCrd()).get();
MixedOperation<MeterSphereCustomResource, MeterSphereCustomResourceList, MeterSphereCustomResourceDoneable, Resource<MeterSphereCustomResource, MeterSphereCustomResourceDoneable>>
operation = kubernetesClient.customResources(crd, MeterSphereCustomResource.class, MeterSphereCustomResourceList.class, MeterSphereCustomResourceDoneable.class);
Boolean result = operation.inNamespace(customResource.getMetadata().getNamespace()).withName(customResource.getMetadata().getName()).cascading(true).delete();
return result == null ? false : result;
}
}
public <T> T getCustomResource(MeterSphereCustomResource customResource) throws Exception {
try (KubernetesClient kubernetesClient = getKubernetesClient()) {
CustomResourceDefinition crd = kubernetesClient.customResourceDefinitions().withName(customResource.getCrd()).get();
MixedOperation<MeterSphereCustomResource, MeterSphereCustomResourceList, MeterSphereCustomResourceDoneable, Resource<MeterSphereCustomResource, MeterSphereCustomResourceDoneable>>
operation = kubernetesClient.customResources(crd, MeterSphereCustomResource.class, MeterSphereCustomResourceList.class, MeterSphereCustomResourceDoneable.class);
MeterSphereCustomResource meterSphereCustomResource = operation.inNamespace(customResource.getMetadata().getNamespace()).withName(customResource.getMetadata().getName()).get();
if (meterSphereCustomResource == null) {
return null;
}
return (T) objectMapper.readValue(objectMapper.writeValueAsString(meterSphereCustomResource), customResource.getClass());
}
}
public <T> List<T> listCustomResource(MeterSphereCustomResource customResource) throws Exception {
try (KubernetesClient kubernetesClient = getKubernetesClient()) {
CustomResourceDefinition crd = kubernetesClient.customResourceDefinitions().withName(customResource.getCrd()).get();
MixedOperation<MeterSphereCustomResource, MeterSphereCustomResourceList, MeterSphereCustomResourceDoneable, Resource<MeterSphereCustomResource, MeterSphereCustomResourceDoneable>>
operation = kubernetesClient.customResources(crd, MeterSphereCustomResource.class, MeterSphereCustomResourceList.class, MeterSphereCustomResourceDoneable.class);
MeterSphereCustomResourceList list;
if (StringUtils.isNotEmpty(customResource.getMetadata().getNamespace())) {
list = operation.inNamespace(customResource.getMetadata().getNamespace()).list();
} else {
list = operation.inAnyNamespace().list();
}
List<T> resultList = new ArrayList<>();
for (Object cr : list.getItems()) {
resultList.add((T) objectMapper.readValue(objectMapper.writeValueAsString(cr), customResource.getClass()));
}
return resultList;
}
}
public boolean checkPVCNotExists(String namespace, String statefulsetName) {
KubernetesClient kubernetesClient = getKubernetesClient();
NonNamespaceOperation<PersistentVolumeClaim, PersistentVolumeClaimList, DoneablePersistentVolumeClaim, Resource<PersistentVolumeClaim, DoneablePersistentVolumeClaim>> operation = kubernetesClient.persistentVolumeClaims()
.inNamespace(namespace);
PersistentVolumeClaimList pvcList = operation.list(100, null);
Pattern compile = Pattern.compile(statefulsetName + "-\\d+");
return checkPVCNotExists(pvcList, compile, operation);
}
private boolean checkPVCNotExists(PersistentVolumeClaimList pvcList, Pattern compile, NonNamespaceOperation<PersistentVolumeClaim, PersistentVolumeClaimList, DoneablePersistentVolumeClaim, Resource<PersistentVolumeClaim, DoneablePersistentVolumeClaim>> operation) {
if (pvcList == null || CollectionUtils.isEmpty(pvcList.getItems())) {
return true;
}
Optional<PersistentVolumeClaim> claimOptional = pvcList.getItems().stream().filter(pvc -> compile.matcher(pvc.getMetadata().getName()).matches()).findAny();
if (claimOptional.isPresent()) {
return false;
} else if (StringUtils.isNotEmpty(pvcList.getMetadata().getContinue())) {
return checkPVCNotExists(operation.list(100, pvcList.getMetadata().getContinue()), compile, operation);
} else {
return true;
}
}
public boolean deletePVC(HasMetadata hasMetadata) {
KubernetesClient kubernetesClient = getKubernetesClient();
NonNamespaceOperation<PersistentVolumeClaim, PersistentVolumeClaimList, DoneablePersistentVolumeClaim, Resource<PersistentVolumeClaim, DoneablePersistentVolumeClaim>> operation = kubernetesClient.persistentVolumeClaims()
.inNamespace(hasMetadata.getMetadata().getNamespace());
if (MapUtils.isNotEmpty(hasMetadata.getMetadata().getLabels())) {
operation.withLabelSelector(new LabelSelector(null, hasMetadata.getMetadata().getLabels()));
}
if (StringUtils.isNotEmpty(hasMetadata.getMetadata().getName())) {
operation.withName(hasMetadata.getMetadata().getName());
}
Boolean delete = operation.delete();
return delete == null ? false : delete;
}
public boolean deleteNamespace(String namespace) {
KubernetesClient kubernetesClient = getKubernetesClient();
Boolean delete = kubernetesClient.namespaces().withName(namespace).delete();
return delete == null ? false : delete;
}
public String getLog(String namespace, String pod, String container, int tailingLines) {
try (KubernetesClient client = getKubernetesClient()) {
PrettyLoggable<String, LogWatch> loggable;
if (tailingLines > 0) {
loggable = client.pods().inNamespace(namespace).withName(pod).inContainer(container).tailingLines(tailingLines);
} else {
loggable = client.pods().inNamespace(namespace).withName(pod).inContainer(container);
}
return loggable.getLog();
}
}
}

View File

@ -1,32 +0,0 @@
package io.metersphere.performance.engine.kubernetes.provider;
public class ClientCredential {
private String masterUrl;
private String token;
private Integer maxConcurrency;
public String getMasterUrl() {
return masterUrl;
}
public void setMasterUrl(String masterUrl) {
this.masterUrl = masterUrl;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public Integer getMaxConcurrency() {
return maxConcurrency;
}
public void setMaxConcurrency(Integer maxConcurrency) {
this.maxConcurrency = maxConcurrency;
}
}

View File

@ -1,50 +0,0 @@
package io.metersphere.performance.engine.kubernetes.provider;
public class DockerRegistry {
private String url;
private String username;
private String password;
private String email;
private String namespace;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
}

View File

@ -1,24 +0,0 @@
package io.metersphere.performance.engine.kubernetes.provider;
import com.alibaba.fastjson.JSONObject;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class DockerRegistryUtil {
public static String getDockerConfig(DockerRegistry registry) {
Map<String, String> config = new HashMap<>();
config.put("username", registry.getUsername());
config.put("password", registry.getPassword());
config.put("auth", Base64.getEncoder().encodeToString((registry.getUsername() + ":" + registry.getPassword()).getBytes()));
JSONObject jb = new JSONObject();
jb.put(registry.getUrl(), config);
JSONObject result = new JSONObject();
result.put("auths", jb);
return Base64.getEncoder().encodeToString(result.toJSONString().getBytes());
}
}

View File

@ -1,7 +0,0 @@
package io.metersphere.performance.engine.kubernetes.provider;
public class KubernetesProvider extends AbstractClientProvider {
public KubernetesProvider(String credential) {
super(credential);
}
}

View File

@ -199,7 +199,7 @@ public class PerformanceTestService {
}
LogUtil.info("Load test started " + loadTest.getName());
// engine type (NODE|K8S)
// engine type (NODE)
final Engine engine = EngineFactory.createEngine(loadTest);
if (engine == null) {
MSException.throwException(String.format("Test cannot be runtest ID%s", request.getId()));

View File

@ -1,10 +1,12 @@
package io.metersphere.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.base.domain.*;
import io.metersphere.base.domain.TestResource;
import io.metersphere.base.domain.TestResourceExample;
import io.metersphere.base.domain.TestResourcePool;
import io.metersphere.base.domain.TestResourcePoolExample;
import io.metersphere.base.mapper.TestResourceMapper;
import io.metersphere.base.mapper.TestResourcePoolMapper;
import io.metersphere.commons.constants.ResourcePoolTypeEnum;
import io.metersphere.commons.constants.ResourceStatusEnum;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
@ -12,7 +14,6 @@ import io.metersphere.controller.request.resourcepool.QueryResourcePoolRequest;
import io.metersphere.dto.NodeDTO;
import io.metersphere.dto.TestResourcePoolDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.performance.engine.kubernetes.provider.KubernetesProvider;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@ -145,9 +146,6 @@ public class TestResourcePoolService {
}
private boolean validateTestResourcePool(TestResourcePoolDTO testResourcePool) {
if (StringUtils.equalsIgnoreCase(testResourcePool.getType(), ResourcePoolTypeEnum.K8S.name())) {
return validateK8s(testResourcePool);
}
return validateNodes(testResourcePool);
}
@ -194,31 +192,6 @@ public class TestResourcePoolService {
}
}
private boolean validateK8s(TestResourcePoolDTO testResourcePool) {
if (CollectionUtils.isEmpty(testResourcePool.getResources()) || testResourcePool.getResources().size() != 1) {
throw new RuntimeException(Translator.get("only_one_k8s"));
}
TestResource testResource = testResourcePool.getResources().get(0);
testResource.setTestResourcePoolId(testResourcePool.getId());
boolean isValid;
try {
KubernetesProvider provider = new KubernetesProvider(testResource.getConfiguration());
provider.validateCredential();
testResource.setStatus(VALID.name());
testResourcePool.setStatus(VALID.name());
isValid = true;
} catch (Exception e) {
testResource.setStatus(ResourceStatusEnum.INVALID.name());
testResourcePool.setStatus(ResourceStatusEnum.INVALID.name());
isValid = false;
}
deleteTestResource(testResourcePool.getId());
updateTestResource(testResource);
return isValid;
}
private void updateTestResource(TestResource testResource) {
testResource.setUpdateTime(System.currentTimeMillis());
testResource.setCreateTime(System.currentTimeMillis());

View File

@ -10,10 +10,10 @@ import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.exception.ExcelException;
import io.metersphere.i18n.Translator;
import io.metersphere.track.dto.TestCaseDTO;
import io.metersphere.track.dto.TestCaseNodeDTO;
import io.metersphere.exception.ExcelException;
import io.metersphere.track.request.testcase.DragNodeRequest;
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
import org.apache.commons.lang3.StringUtils;
@ -22,7 +22,6 @@ import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yaml.snakeyaml.nodes.NodeId;
import javax.annotation.Resource;
import java.util.*;

View File

@ -37,7 +37,6 @@ test_not_running=Test is not running
load_test_already_exists=Duplicate load test name
no_nodes_message=No node message
duplicate_node_ip=Duplicate IPs
only_one_k8s=Only one K8s can be added
max_thread_insufficient=The number of concurrent users exceeds
#workspace
workspace_name_is_null=Workspace name cannot be null

View File

@ -37,7 +37,6 @@ test_not_running=测试未运行
load_test_already_exists=测试名称不能重复
no_nodes_message=没有节点信息
duplicate_node_ip=节点 IP 重复
only_one_k8s=只能添加一个 K8s
max_thread_insufficient=并发用户数超额
#workspace
workspace_name_is_null=工作空间名不能为空

View File

@ -37,7 +37,6 @@ test_not_running=測試未運行
load_test_already_exists=測試名稱不能重復
no_nodes_message=沒有節點信息
duplicate_node_ip=節點 IP 重復
only_one_k8s=只能添加壹個 K8s
max_thread_insufficient=並發用戶數超額
#workspace
workspace_name_is_null=工作空間名不能為空

View File

@ -11,7 +11,6 @@
<el-table-column prop="type" :label="$t('test_resource_pool.type')">
<template v-slot:default="scope">
<span v-if="scope.row.type === 'NODE'">Node</span>
<span v-if="scope.row.type === 'K8S'">Kubernetes</span>
</template>
</el-table-column>
<el-table-column prop="status" :label="$t('test_resource_pool.enable_disable')">
@ -61,31 +60,10 @@
<el-form-item :label="$t('test_resource_pool.type')" prop="type">
<el-select v-model="form.type" :placeholder="$t('test_resource_pool.select_pool_type')"
@change="changeResourceType()">
<el-option key="K8S" value="K8S" label="Kubernetes">Kubernetes</el-option>
<el-option key="NODE" value="NODE" label="Node">Node</el-option>
</el-select>
</el-form-item>
<div v-for="(item,index) in infoList " :key="index">
<div class="node-line" v-if="form.type === 'K8S'">
<el-row>
<el-col :span="9">
<el-form-item prop="masterUrl" label="Master URL">
<el-input v-model="item.masterUrl" autocomplete="new-password"/>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item prop="password" label="Token" style="padding-left: 20px">
<el-input v-model="item.token" autocomplete="new-password"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"
style="padding-left: 20px">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="9999"></el-input-number>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="node-line" v-if="form.type === 'NODE'">
<el-row>
<el-col :span="8">
@ -144,31 +122,10 @@
<el-form-item :label="$t('test_resource_pool.type')" prop="type">
<el-select v-model="form.type" :placeholder="$t('test_resource_pool.select_pool_type')"
@change="changeResourceType()">
<el-option key="K8S" value="K8S" label="Kubernetes">Kubernetes</el-option>
<el-option key="NODE" value="NODE" label="Node">Node</el-option>
</el-select>
</el-form-item>
<div v-for="(item,index) in infoList " :key="index">
<div class="node-line" v-if="form.type === 'K8S'">
<el-row>
<el-col :span="9">
<el-form-item prop="masterUrl" label="Master URL">
<el-input v-model="item.masterUrl" autocomplete="off"/>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item prop="password" label="Token" style="padding-left: 20px">
<el-input v-model="item.token" show-password autocomplete="off"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"
style="padding-left: 20px">
<el-input-number v-model="item.maxConcurrency" :min="1" :max="9999"></el-input-number>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="node-line" v-if="form.type === 'NODE'">
<el-row>
<el-col :span="8">