未验证 提交 92bb474c 编写于 作者: K kezhenxu94 提交者: GitHub

Improve Kubernetes service registry for ALS analysis (#5722)

The current implementation of envoy ALS K8S analysis is based on the hierarchy, pod -> StatefulSet -> deployment, StatefulSet, or others. It's freaky and different from the Istio Kubernetes registry.

The new path is pod -> endpoint -> service, and we should leverage Informer API instead of raw Kubernetes API.
上级 c95a9134
......@@ -28,7 +28,7 @@ env:
ISTIO_VERSION: 1.7.1
TAG: ${{ github.sha }}
SCRIPTS_DIR: test/e2e-mesh/e2e-istio/scripts
SW_OAP_BASE_IMAGE: openjdk:8-jre-alpine
SW_OAP_BASE_IMAGE: openjdk:11-jdk
jobs:
als:
......@@ -62,17 +62,22 @@ jobs:
run: |
git clone https://github.com/apache/skywalking-kubernetes.git
cd skywalking-kubernetes
git reset --hard 419cd1aed8bb4ad972208e5a031527a25d2ae690
git reset --hard dd749f25913830c47a97430618cefc4167612e75
cd chart
helm dep up skywalking
helm -n istio-system install skywalking skywalking \
--set fullnameOverride=skywalking \
--set elasticsearch.replicas=1 \
--set elasticsearch.minimumMasterNodes=1 \
--set elasticsearch.imageTag=7.5.1 \
--set oap.env.SW_ENVOY_METRIC_ALS_HTTP_ANALYSIS=k8s-mesh \
--set oap.envoy.als.enabled=true \
--set oap.replicas=1 \
--set ui.image.repository=skywalking/ui \
--set ui.image.tag=$TAG \
--set oap.image.tag=$TAG \
--set oap.image.repository=skywalking/oap
--set oap.image.repository=skywalking/oap \
--set oap.storageType=elasticsearch7
kubectl -n istio-system get pods
sleep 3
......
......@@ -7,11 +7,12 @@ Release Notes.
#### Project
#### Java Agent
Make the Feign plugin to support Java 14
Make the okhttp3 plugin to support Java 14
* Make the Feign plugin to support Java 14
* Make the okhttp3 plugin to support Java 14
#### OAP-Backend
* Add the `@SuperDataset` annotation for BrowserErrorLog.
* Improve Kubernetes service registry for ALS analysis.
#### UI
......
......@@ -256,6 +256,7 @@ The text of each license is the standard Apache 2.0 license.
Apache: commons-pool 2.4.2: https://github.com/apache/commons-pool, Apache 2.0
Apache: commons-lang 3.6: https://github.com/apache/commons-lang, Apache 2.0
Apache: commons-text 1.8: https://github.com/apache/commons-text, Apache 2.0
Apache: commons-beanutils 1.9.4: https://github.com/apache/commons-beanutils, Apache 2.0
Apache: lucene 6.6.0: https://github.com/apache/lucene-solr/tree/master/lucene, Apache 2.0
Apache: httpasyncclient 4.1.2: https://github.com/apache/httpasyncclient/tree/4.1.2, Apache 2.0
Apache: log4j 1.2.16: http://logging.apache.org/log4j/1.2/, Apache 2.0
......
......@@ -29,6 +29,7 @@
<logger name="org.elasticsearch.common.network.IfConfig" level="INFO"/>
<logger name="io.grpc.netty" level="INFO"/>
<logger name="org.apache.skywalking.oap.server.receiver.istio.telemetry" level="DEBUG"/>
<logger name="org.apache.skywalking.oap.server.receiver.envoy.als.K8SServiceRegistry" level="DEBUG"/>
<Root level="INFO">
<AppenderRef ref="Console"/>
</Root>
......
......@@ -168,6 +168,7 @@ core|default|role|Option values, `Mixed/Receiver/Aggregator`. **Receiver** mode
| envoy-metric| default| Read [receiver doc](backend-receivers.md) for more details | - | - |
| - | - | acceptMetricsService | Open Envoy Metrics Service analysis | SW_ENVOY_METRIC_SERVICE | true|
| - | - | alsHTTPAnalysis | Open Envoy Access Log Service analysis. Value = `k8s-mesh` means open the analysis | SW_ENVOY_METRIC_ALS_HTTP_ANALYSIS | - |
| - | - | k8sServiceNameRule | `k8sServiceNameRule` allows you to customize the service name in ALS via Kubernetes metadata, the available variables are `pod`, `service`, e.g., you can use `${service.metadata.name}-${pod.metadata.labels.version}` to append the version number to the service name. Be careful, when using environment variables to pass this configuration, use single quotes(`''`) to avoid it being evaluated by the shell. | - |
| receiver-oc | default | Read [receiver doc](backend-receivers.md) for more details | - | - |
| - | - | gRPCHost|Binding IP of gRPC service. Services include gRPC data report and internal communication among OAP nodes| SW_OC_RECEIVER_GRPC_HOST | - |
| - | - | gRPCPort| Binding port of gRPC service | SW_OC_RECEIVER_GRPC_PORT | - |
......
......@@ -99,6 +99,7 @@
<zookeeper.image.version>3.5</zookeeper.image.version>
<kafka-clients.version>2.4.1</kafka-clients.version>
<spring-kafka-test.version>2.4.6.RELEASE</spring-kafka-test.version>
<commons-beanutils.version>1.9.4</commons-beanutils.version>
</properties>
<dependencies>
......@@ -537,6 +538,22 @@
<artifactId>mvel2</artifactId>
<version>${mvel.version}</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>${commons-beanutils.version}</version>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
</project>
......@@ -247,6 +247,11 @@ envoy-metric:
default:
acceptMetricsService: ${SW_ENVOY_METRIC_SERVICE:true}
alsHTTPAnalysis: ${SW_ENVOY_METRIC_ALS_HTTP_ANALYSIS:""}
# `k8sServiceNameRule` allows you to customize the service name in ALS via Kubernetes metadata,
# the available variables are `pod`, `service`, f.e., you can use `${service.metadata.name}-${pod.metadata.labels.version}`
# to append the version number to the service name.
# Be careful, when using environment variables to pass this configuration, use single quotes(`''`) to avoid it being evaluated by the shell.
k8sServiceNameRule: ${K8S_SERVICE_NAME_RULE:"${service.metadata.name}"}
prometheus-fetcher:
selector: ${SW_PROMETHEUS_FETCHER:default}
......
......@@ -37,10 +37,6 @@
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
......
......@@ -43,6 +43,12 @@
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
......@@ -56,4 +62,4 @@
<scope>provided</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
</project>
......@@ -30,10 +30,12 @@ public class EnvoyMetricReceiverConfig extends ModuleConfig {
@Getter
private boolean acceptMetricsService = false;
private String alsHTTPAnalysis;
@Getter
private String k8sServiceNameRule;
public List<String> getAlsHTTPAnalysis() {
if (Strings.isNullOrEmpty(alsHTTPAnalysis)) {
return Collections.EMPTY_LIST;
return Collections.emptyList();
}
return Arrays.stream(alsHTTPAnalysis.trim().split(",")).map(String::trim).collect(Collectors.toList());
}
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package org.apache.skywalking.oap.server.receiver.envoy.als;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.models.V1ObjectMeta;
import io.kubernetes.client.openapi.models.V1OwnerReference;
import java.util.Optional;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
interface Fetcher extends Function<V1OwnerReference, Optional<V1ObjectMeta>> {
Logger LOGGER = LoggerFactory.getLogger(Fetcher.class);
V1ObjectMeta go(V1OwnerReference ownerReference) throws ApiException;
default Optional<V1ObjectMeta> apply(V1OwnerReference ownerReference) {
try {
return Optional.ofNullable(go(ownerReference));
} catch (final ApiException e) {
LOGGER.error("code:{} header:{} body:{}", e.getCode(), e.getResponseHeaders(), e.getResponseBody());
return Optional.empty();
} catch (final Throwable th) {
LOGGER.error("other errors", th);
return Optional.empty();
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.receiver.envoy.als.k8s;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.kubernetes.client.informer.ResourceEventHandler;
import io.kubernetes.client.informer.SharedInformerFactory;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1Endpoints;
import io.kubernetes.client.openapi.models.V1EndpointsList;
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.V1Service;
import io.kubernetes.client.openapi.models.V1ServiceList;
import io.kubernetes.client.util.Config;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.receiver.envoy.EnvoyMetricReceiverConfig;
import org.apache.skywalking.oap.server.receiver.envoy.als.ServiceMetaInfo;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.Objects.isNull;
import static java.util.Objects.requireNonNull;
@Slf4j
class K8SServiceRegistry {
final Map<String/* ip */, ServiceMetaInfo> ipServiceMetaInfoMap;
final Map<String/* namespace:serviceName */, V1Service> idServiceMap;
final Map<String/* ip */, V1Pod> ipPodMap;
final Map<String/* ip */, String/* namespace:serviceName */> ipServiceMap;
final ExecutorService executor;
final ServiceNameFormatter serviceNameFormatter;
K8SServiceRegistry(final EnvoyMetricReceiverConfig config) {
serviceNameFormatter = new ServiceNameFormatter(config.getK8sServiceNameRule());
ipServiceMetaInfoMap = new ConcurrentHashMap<>();
idServiceMap = new ConcurrentHashMap<>();
ipPodMap = new ConcurrentHashMap<>();
ipServiceMap = new ConcurrentHashMap<>();
executor = Executors.newCachedThreadPool(
new ThreadFactoryBuilder()
.setNameFormat("K8SServiceRegistry-%d")
.setDaemon(true)
.build()
);
}
void start() throws IOException {
final ApiClient apiClient = Config.defaultClient();
apiClient.setHttpClient(apiClient.getHttpClient()
.newBuilder()
.readTimeout(0, TimeUnit.SECONDS)
.build());
Configuration.setDefaultApiClient(apiClient);
final CoreV1Api coreV1Api = new CoreV1Api();
final SharedInformerFactory factory = new SharedInformerFactory(executor);
// TODO: also listen to the EndpointSlice event after the client supports us to do so
listenServiceEvents(coreV1Api, factory);
listenEndpointsEvents(coreV1Api, factory);
listenPodEvents(coreV1Api, factory);
factory.startAllRegisteredInformers();
}
private void listenServiceEvents(final CoreV1Api coreV1Api, final SharedInformerFactory factory) {
factory.sharedIndexInformerFor(
params -> coreV1Api.listServiceForAllNamespacesCall(
null,
null,
null,
null,
null,
null,
params.resourceVersion,
params.timeoutSeconds,
params.watch,
null
),
V1Service.class,
V1ServiceList.class
).addEventHandler(new ResourceEventHandler<V1Service>() {
@Override
public void onAdd(final V1Service service) {
addService(service);
}
@Override
public void onUpdate(final V1Service oldService, final V1Service newService) {
addService(newService);
}
@Override
public void onDelete(final V1Service service, final boolean deletedFinalStateUnknown) {
removeService(service);
}
});
}
private void listenEndpointsEvents(final CoreV1Api coreV1Api, final SharedInformerFactory factory) {
factory.sharedIndexInformerFor(
params -> coreV1Api.listEndpointsForAllNamespacesCall(
null,
null,
null,
null,
null,
null,
params.resourceVersion,
params.timeoutSeconds,
params.watch,
null
),
V1Endpoints.class,
V1EndpointsList.class
).addEventHandler(new ResourceEventHandler<V1Endpoints>() {
@Override
public void onAdd(final V1Endpoints endpoints) {
addEndpoints(endpoints);
}
@Override
public void onUpdate(final V1Endpoints oldEndpoints, final V1Endpoints newEndpoints) {
addEndpoints(newEndpoints);
}
@Override
public void onDelete(final V1Endpoints endpoints, final boolean deletedFinalStateUnknown) {
removeEndpoints(endpoints);
}
});
}
private void listenPodEvents(final CoreV1Api coreV1Api, final SharedInformerFactory factory) {
factory.sharedIndexInformerFor(
params -> coreV1Api.listPodForAllNamespacesCall(
null,
null,
null,
null,
null,
null,
params.resourceVersion,
params.timeoutSeconds,
params.watch,
null
),
V1Pod.class,
V1PodList.class
).addEventHandler(new ResourceEventHandler<V1Pod>() {
@Override
public void onAdd(final V1Pod pod) {
addPod(pod);
}
@Override
public void onUpdate(final V1Pod oldPod, final V1Pod newPod) {
addPod(newPod);
}
@Override
public void onDelete(final V1Pod pod, final boolean deletedFinalStateUnknown) {
removePod(pod);
}
});
}
private void addService(final V1Service service) {
Optional.ofNullable(service.getMetadata()).ifPresent(
metadata -> idServiceMap.put(metadata.getNamespace() + ":" + metadata.getName(), service)
);
recompose();
}
private void removeService(final V1Service service) {
Optional.ofNullable(service.getMetadata()).ifPresent(
metadata -> idServiceMap.remove(metadata.getUid())
);
}
private void addPod(final V1Pod pod) {
Optional.ofNullable(pod.getStatus()).ifPresent(
status -> ipPodMap.put(status.getPodIP(), pod)
);
recompose();
}
private void removePod(final V1Pod pod) {
Optional.ofNullable(pod.getStatus()).ifPresent(
status -> ipPodMap.remove(status.getPodIP())
);
}
private void addEndpoints(final V1Endpoints endpoints) {
final String namespace = requireNonNull(endpoints.getMetadata()).getNamespace();
final String name = requireNonNull(endpoints.getMetadata()).getName();
requireNonNull(endpoints.getSubsets()).forEach(
subset -> requireNonNull(subset.getAddresses()).forEach(
address -> ipServiceMap.put(address.getIp(), namespace + ":" + name)
)
);
recompose();
}
private void removeEndpoints(final V1Endpoints endpoints) {
requireNonNull(endpoints.getSubsets()).forEach(
subset -> requireNonNull(subset.getAddresses()).forEach(
address -> ipServiceMap.remove(address.getIp())
)
);
}
private List<ServiceMetaInfo.KeyValue> transformLabelsToTags(final Map<String, String> labels) {
if (isNull(labels)) {
return Collections.emptyList();
}
return labels.entrySet()
.stream()
.map(each -> new ServiceMetaInfo.KeyValue(each.getKey(), each.getValue()))
.collect(Collectors.toList());
}
ServiceMetaInfo findService(final String ip) {
final ServiceMetaInfo service = ipServiceMetaInfoMap.get(ip);
if (isNull(service)) {
log.debug("Unknown ip {}, ip -> service is null", ip);
return ServiceMetaInfo.UNKNOWN;
}
return service;
}
private void recompose() {
ipPodMap.forEach((ip, pod) -> {
final String namespaceService = ipServiceMap.get(ip);
final V1Service service;
if (isNullOrEmpty(namespaceService) || isNull(service = idServiceMap.get(namespaceService))) {
return;
}
final Map<String, Object> context = ImmutableMap.of("service", service, "pod", pod);
final V1ObjectMeta podMetadata = requireNonNull(pod.getMetadata());
ipServiceMetaInfoMap.computeIfAbsent(ip, unused -> {
final ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
try {
serviceMetaInfo.setServiceName(serviceNameFormatter.format(context));
} catch (Exception e) {
log.error("Failed to evaluate service name.", e);
serviceMetaInfo.setServiceName(requireNonNull(service.getMetadata()).getName());
}
serviceMetaInfo.setServiceInstanceName(String.format("%s.%s", podMetadata.getName(), podMetadata.getNamespace()));
serviceMetaInfo.setTags(transformLabelsToTags(podMetadata.getLabels()));
return serviceMetaInfo;
});
});
}
boolean isEmpty() {
return ipServiceMetaInfoMap.isEmpty();
}
}
......@@ -14,49 +14,48 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package org.apache.skywalking.oap.server.receiver.envoy.als;
package org.apache.skywalking.oap.server.receiver.envoy.als.k8s;
import io.kubernetes.client.openapi.models.V1ObjectMeta;
import io.kubernetes.client.openapi.models.V1OwnerReference;
import java.util.Optional;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
@RequiredArgsConstructor
class DependencyResource {
@Getter(AccessLevel.PACKAGE)
private final V1ObjectMeta metadata;
class ServiceNameFormatter {
private boolean stop;
private final List<String> properties;
DependencyResource getOwnerResource(final String kind, final Fetcher transform) {
if (stop) {
return this;
}
if (metadata.getOwnerReferences() == null) {
stop = true;
return this;
}
V1OwnerReference ownerReference = null;
for (V1OwnerReference each : metadata.getOwnerReferences()) {
if (each.getKind().equals(kind)) {
ownerReference = each;
break;
}
}
if (ownerReference == null) {
stop = true;
return this;
private final StringBuffer serviceNamePattern;
ServiceNameFormatter(String rule) {
rule = StringUtils.defaultIfBlank(rule, "${service.metadata.name}");
this.properties = new ArrayList<>();
this.serviceNamePattern = new StringBuffer();
final Pattern variablePattern = Pattern.compile("(\\$\\{(?<property>.+?)})");
final Matcher matcher = variablePattern.matcher(rule);
while (matcher.find()) {
properties.add(matcher.group("property"));
matcher.appendReplacement(serviceNamePattern, "%s");
}
Optional<V1ObjectMeta> metaOptional = transform.apply(ownerReference);
if (!metaOptional.isPresent()) {
stop = true;
return this;
}
String format(final Map<String, Object> context) throws Exception {
final Object[] values = new Object[properties.size()];
for (int i = 0; i < properties.size(); i++) {
final Object value = PropertyUtils.getProperty(context, properties.get(i));
values[i] = value;
}
return new DependencyResource(metaOptional.get());
return Strings.lenientFormat(serviceNamePattern.toString(), values);
}
}
......@@ -17,4 +17,4 @@
#
org.apache.skywalking.oap.server.receiver.envoy.als.K8sALSServiceMeshHTTPAnalysis
\ No newline at end of file
org.apache.skywalking.oap.server.receiver.envoy.als.k8s.K8sALSServiceMeshHTTPAnalysis
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package org.apache.skywalking.oap.server.receiver.envoy.als;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.models.V1ObjectMeta;
import io.kubernetes.client.openapi.models.V1OwnerReference;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
@RunWith(Parameterized.class)
public class DependencyResourceTest {
@Parameterized.Parameter
public String resourceName;
@Parameterized.Parameter(1)
public ThrowableFunction function;
@Parameterized.Parameters(name = "{index}: {0}")
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{
"deploy1",
(ThrowableFunction) result -> result
},
{
"pod1",
(ThrowableFunction) result -> {
throw new RuntimeException();
}
},
{
"pod1",
(ThrowableFunction) result -> {
throw new ApiException();
}
},
{
"pod1",
(ThrowableFunction) result -> null
},
{
"rs1",
(ThrowableFunction) result -> {
result.setOwnerReferences(null);
return result;
}
},
{
"rs1",
(ThrowableFunction) result -> {
V1OwnerReference reference1 = new V1OwnerReference();
reference1.setKind("StatefulSet");
reference1.setName("ss1");
result.setOwnerReferences(Collections.singletonList(reference1));
return result;
}
},
});
}
@Test
public void test() {
V1ObjectMeta meta = new V1ObjectMeta();
meta.setName("pod1");
V1OwnerReference reference = new V1OwnerReference();
reference.setKind("ReplicaSet");
reference.setName("rs1");
meta.addOwnerReferencesItem(reference);
DependencyResource dr = new DependencyResource(meta);
DependencyResource drr = dr.getOwnerResource("ReplicaSet", ownerReference -> {
assertThat(ownerReference.getName(), is("rs1"));
V1ObjectMeta result = new V1ObjectMeta();
result.setName("rs1");
V1OwnerReference reference1 = new V1OwnerReference();
reference1.setKind("Deployment");
reference1.setName("deploy1");
result.addOwnerReferencesItem(reference1);
return function.go(result);
}).getOwnerResource("Deployment", ownerReference -> {
assertThat(ownerReference.getName(), is("deploy1"));
V1ObjectMeta result = new V1ObjectMeta();
result.setName("deploy1");
return result;
});
assertThat(drr.getMetadata().getName(), is(resourceName));
}
interface ThrowableFunction {
V1ObjectMeta go(final V1ObjectMeta result) throws ApiException;
}
}
\ No newline at end of file
......@@ -16,9 +16,8 @@
*
*/
package org.apache.skywalking.oap.server.receiver.envoy.als;
package org.apache.skywalking.oap.server.receiver.envoy.als.k8s;
import com.google.common.collect.ImmutableMap;
import com.google.protobuf.util.JsonFormat;
import io.envoyproxy.envoy.service.accesslog.v2.StreamAccessLogsMessage;
import java.io.IOException;
......@@ -30,10 +29,16 @@ import org.apache.skywalking.apm.network.common.v3.DetectPoint;
import org.apache.skywalking.apm.network.servicemesh.v3.ServiceMeshMetric;
import org.apache.skywalking.oap.server.receiver.envoy.EnvoyMetricReceiverConfig;
import org.apache.skywalking.oap.server.receiver.envoy.MetricServiceGRPCHandlerTestMain;
import org.apache.skywalking.oap.server.receiver.envoy.als.Role;
import org.apache.skywalking.oap.server.receiver.envoy.als.ServiceMetaInfo;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class K8sHTTPAnalysisTest {
private MockK8sAnalysis analysis;
......@@ -147,12 +152,12 @@ public class K8sHTTPAnalysisTest {
@Override
public void init(EnvoyMetricReceiverConfig config) {
getIpServiceMap().set(
ImmutableMap.of("10.44.2.56", new ServiceMetaInfo("ingress", "ingress-Inst"), "10.44.2.54",
new ServiceMetaInfo("productpage", "productpage-Inst"), "10.44.6.66",
new ServiceMetaInfo("detail", "detail-Inst"), "10.44.2.55",
new ServiceMetaInfo("review", "detail-Inst")
));
serviceRegistry = mock(K8SServiceRegistry.class);
when(serviceRegistry.findService(anyString())).thenReturn(ServiceMetaInfo.UNKNOWN);
when(serviceRegistry.findService("10.44.2.56")).thenReturn(new ServiceMetaInfo("ingress", "ingress-Inst"));
when(serviceRegistry.findService("10.44.2.54")).thenReturn(new ServiceMetaInfo("productpage", "productpage-Inst"));
when(serviceRegistry.findService("10.44.6.66")).thenReturn(new ServiceMetaInfo("detail", "detail-Inst"));
when(serviceRegistry.findService("10.44.2.55")).thenReturn(new ServiceMetaInfo("review", "detail-Inst"));
}
@Override
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.receiver.envoy.als.k8s;
import com.google.common.collect.ImmutableMap;
import io.kubernetes.client.openapi.models.V1ObjectMeta;
import io.kubernetes.client.openapi.models.V1Pod;
import io.kubernetes.client.openapi.models.V1Service;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static junit.framework.TestCase.assertEquals;
@RequiredArgsConstructor
@RunWith(Parameterized.class)
public class ServiceNameFormatterTest {
private final Case kase;
@Parameterized.Parameters
public static Case[] parameters() {
return new Case[] {
new Case(
null,
ImmutableMap.of("service", service("Clash")),
"Clash"
),
new Case(
null,
ImmutableMap.of("service", service("ClashX"), "pod", pod("version", "v1")),
"ClashX"
),
new Case(
"${service.metadata.name}-${pod.metadata.labels.version}",
ImmutableMap.of("service", service("Clash"), "pod", pod("version", "v1beta")),
"Clash-v1beta"
),
new Case(
"${pod.metadata.labels.app}",
ImmutableMap.of("service", service("Clash"), "pod", pod("app", "ClashX-alpha")),
"ClashX-alpha"
)
};
}
@Test
public void testFormatDefaultRule() throws Exception {
assertEquals(new ServiceNameFormatter(kase.format).format(kase.context), kase.result);
}
static V1Service service(final String name) {
return new V1Service() {
@Override
public V1ObjectMeta getMetadata() {
return new V1ObjectMeta() {
@Override
public String getName() {
return name;
}
};
}
};
}
static V1Pod pod(final String label, final String value) {
return new V1Pod() {
@Override
public V1ObjectMeta getMetadata() {
return new V1ObjectMeta() {
@Override
public Map<String, String> getLabels() {
return ImmutableMap.of(label, value);
}
};
}
};
}
@RequiredArgsConstructor
static class Case {
private final String format;
private final Map<String, Object> context;
private final String result;
}
}
......@@ -21,7 +21,6 @@
set -ex
curl -L https://istio.io/downloadIstio | sh -
sudo mv $PWD/istio-$ISTIO_VERSION/bin/istioctl /usr/local/bin/
istioctl version || (curl -L https://istio.io/downloadIstio | sh - && sudo mv $PWD/istio-$ISTIO_VERSION/bin/istioctl /usr/local/bin/)
istioctl install $@
kubectl label namespace default istio-injection=enabled
......@@ -49,10 +49,10 @@ public @interface RetryableTest {
/**
* @return maximum times to retry, or -1 for infinite retries. {@code -1} by default.
*/
int value() default 300;
int value() default 120;
/**
* @return the interval between any two retries, in millisecond. {@code 1000} by default.
*/
long interval() default 1000;
long interval() default 10000;
}
......@@ -66,7 +66,9 @@ import static org.apache.skywalking.e2e.utils.Yamls.load;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class ALSE2E extends SkyWalkingTestAdapter {
private final String swWebappHost = Optional.ofNullable(Strings.emptyToNull(System.getenv("WEBAPP_HOST"))).orElse("127.0.0.1");
private final String swWebappPort = Optional.ofNullable(Strings.emptyToNull(System.getenv("WEBAPP_PORT"))).orElse("8080");
private final String swWebappPort = Optional.ofNullable(Strings.emptyToNull(System.getenv("WEBAPP_PORT"))).orElse("12800");
protected HostAndPort swWebappHostPort = HostAndPort.builder()
.host(swWebappHost)
.port(Integer.parseInt(swWebappPort))
......@@ -74,10 +76,10 @@ public class ALSE2E extends SkyWalkingTestAdapter {
private final Map<Predicate<Service>, String> serviceEndpointExpectedDataFiles =
ImmutableMap.<Predicate<Service>, String>builder()
.put(service -> IDManager.ServiceID.analysisId(service.getKey()).getName().startsWith("ratings-v1"), "expected/als/endpoints-ratings.yml")
.put(service -> IDManager.ServiceID.analysisId(service.getKey()).getName().startsWith("details-v1"), "expected/als/endpoints-details.yml")
.put(service -> IDManager.ServiceID.analysisId(service.getKey()).getName().startsWith("reviews-v"), "expected/als/endpoints-reviews.yml")
.put(service -> IDManager.ServiceID.analysisId(service.getKey()).getName().startsWith("productpage-v1"), "expected/als/endpoints-productpage.yml")
.put(service -> service.getLabel().startsWith("ratings"), "expected/als/endpoints-ratings.yml")
.put(service -> service.getLabel().startsWith("details"), "expected/als/endpoints-details.yml")
.put(service -> service.getLabel().startsWith("reviews"), "expected/als/endpoints-reviews.yml")
.put(service -> service.getLabel().startsWith("productpage"), "expected/als/endpoints-productpage.yml")
.build();
@BeforeAll
......@@ -151,7 +153,11 @@ public class ALSE2E extends SkyWalkingTestAdapter {
LOGGER.info("instances: {}", instances);
load("expected/als/instances.yml").as(InstancesMatcher.class).verify(instances);
String file = "expected/als/instances.yml";
if (service.getLabel().equals("reviews")) {
file = "expected/als/instances-reviews.yml";
}
load(file).as(InstancesMatcher.class).verify(instances);
return instances;
}
......
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
instances:
- key: not null
label: not null
- key: not null
label: not null
- key: not null
label: not null
......@@ -15,16 +15,12 @@
services:
- key: not null
label: re(ratings-v1.*)
label: re(ratings.*)
- key: not null
label: re(reviews-v1.*)
label: re(reviews.*)
- key: not null
label: re(reviews-v2.*)
label: re(productpage.*)
- key: not null
label: re(reviews-v3.*)
- key: not null
label: re(productpage-v1.*)
- key: not null
label: re(details-v1.*)
label: re(details.*)
- key: not null
label: re(istio-ingressgateway.*)
......@@ -15,30 +15,22 @@
nodes:
- id: not null
name: re(ratings-v1.*)
name: ratings
type: http
isReal: true
- id: not null
name: re(reviews-v1.*)
name: reviews
type: http
isReal: true
- id: not null
name: re(reviews-v2.*)
type: http
name: productpage
isReal: true
- id: not null
name: re(reviews-v3.*)
name: details
type: http
isReal: true
- id: not null
name: re(productpage-v1.*)
isReal: true
- id: not null
name: re(details-v1.*)
type: http
isReal: true
- id: not null
name: re(istio-ingressgateway.*)
name: istio-ingressgateway
type: http
isReal: true
- id: not null
......@@ -46,48 +38,30 @@ nodes:
isReal: true
calls:
- id: not null
source: re(VU5LTk9XTg.*)
target: re(aXN0aW8taW5ncmVzc2dhdGV3YXkt.*)
detectPoints:
- SERVER
- id: not null
source: re(cHJvZHVjdHBhZ2UtdjEt.*)
target: re(cmV2aWV3cy12MS0.*)
source: VU5LTk9XTg==.1
target: aXN0aW8taW5ncmVzc2dhdGV3YXk=.1
detectPoints:
- CLIENT
- SERVER
- id: not null
source: re(cHJvZHVjdHBhZ2UtdjEt.*)
target: re(ZGV0YWlscy12MS.*)
source: aXN0aW8taW5ncmVzc2dhdGV3YXk=.1
target: cHJvZHVjdHBhZ2U=.1
detectPoints:
- CLIENT
- SERVER
- id: not null
source: re(cHJvZHVjdHBhZ2UtdjEt.*)
target: re(cmV2aWV3cy12Mi.*)
source: cHJvZHVjdHBhZ2U=.1
target: cmV2aWV3cw==.1
detectPoints:
- CLIENT
- SERVER
- id: not null
source: re(cmV2aWV3cy12Mi.*)
target: re(cmF0aW5ncy12MS.*)
source: cHJvZHVjdHBhZ2U=.1
target: ZGV0YWlscw==.1
detectPoints:
- CLIENT
- SERVER
- id: not null
source: re(cmV2aWV3cy12My.*)
target: re(cmF0aW5ncy12MS.*)
detectPoints:
- CLIENT
- SERVER
- id: not null
source: re(aXN0aW8taW5ncmVzc2dhdGV3YXkt.*)
target: re(cHJvZHVjdHBhZ2UtdjEt.*)
detectPoints:
- CLIENT
- id: not null
source: re(cHJvZHVjdHBhZ2UtdjEt.*)
target: re(cmV2aWV3cy12My.*)
source: cmV2aWV3cw==.1
target: cmF0aW5ncw==.1
detectPoints:
- CLIENT
- SERVER
......@@ -169,3 +169,4 @@ lz4-java-1.6.0.jar
snappy-java-1.1.7.3.jar
zstd-jni-1.4.3-1.jar
mvel2-2.4.8.Final.jar
commons-beanutils-1.9.4.jar
......@@ -168,3 +168,4 @@ lz4-java-1.6.0.jar
snappy-java-1.1.7.3.jar
zstd-jni-1.4.3-1.jar
mvel2-2.4.8.Final.jar
commons-beanutils-1.9.4.jar
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册