This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch 3.1
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.1 by this push:
new 5482f3b68d Adding support for bootstrap file (#10368)
5482f3b68d is described below
commit 5482f3b68d47542a8d1fa08b28abc3bec5840f34
Author: chenyanlann <[email protected]>
AuthorDate: Mon Aug 1 11:04:24 2022 +0800
Adding support for bootstrap file (#10368)
* init bootstrap config
* Add bootstrap license and test
---
.../registry/xds/XdsInitializationException.java | 28 ++++
.../xds/util/bootstrap/BootstrapInfoImpl.java | 129 +++++++++++++++
.../registry/xds/util/bootstrap/Bootstrapper.java | 75 +++++++++
.../xds/util/bootstrap/BootstrapperImpl.java | 180 +++++++++++++++++++++
.../bootstrap/CertificateProviderInfoImpl.java | 49 ++++++
.../xds/util/bootstrap/ServerInfoImpl.java | 68 ++++++++
.../xds/util/bootstrap/BootstrapperTest.java | 139 ++++++++++++++++
7 files changed, 668 insertions(+)
diff --git
a/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/XdsInitializationException.java
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/XdsInitializationException.java
new file mode 100644
index 0000000000..b79f55c717
--- /dev/null
+++
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/XdsInitializationException.java
@@ -0,0 +1,28 @@
+/*
+ * 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.dubbo.registry.xds;
+
+public final class XdsInitializationException extends Exception {
+
+ public XdsInitializationException(String message) {
+ super(message);
+ }
+
+ public XdsInitializationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git
a/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/BootstrapInfoImpl.java
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/BootstrapInfoImpl.java
new file mode 100644
index 0000000000..4946166265
--- /dev/null
+++
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/BootstrapInfoImpl.java
@@ -0,0 +1,129 @@
+/*
+ * 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.dubbo.registry.xds.util.bootstrap;
+
+import io.envoyproxy.envoy.config.core.v3.Node;
+
+import javax.annotation.Nullable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+final class BootstrapInfoImpl extends Bootstrapper.BootstrapInfo {
+
+ private final List<Bootstrapper.ServerInfo> servers;
+
+ private final String serverListenerResourceNameTemplate;
+
+ private final Map<String, Bootstrapper.CertificateProviderInfo>
certProviders;
+
+ private final Node node;
+
+ BootstrapInfoImpl(List<Bootstrapper.ServerInfo> servers, String
serverListenerResourceNameTemplate, Map<String,
Bootstrapper.CertificateProviderInfo> certProviders, Node node) {
+ this.servers = servers;
+ this.serverListenerResourceNameTemplate =
serverListenerResourceNameTemplate;
+ this.certProviders = certProviders;
+ this.node = node;
+ }
+
+ @Override
+ public List<Bootstrapper.ServerInfo> servers() {
+ return servers;
+ }
+
+ public Map<String, Bootstrapper.CertificateProviderInfo> certProviders() {
+ return certProviders;
+ }
+
+ @Override
+ public Node node() {
+ return node;
+ }
+
+ @Override
+ public String serverListenerResourceNameTemplate() {
+ return serverListenerResourceNameTemplate;
+ }
+
+ @Override
+ public String toString() {
+ return "BootstrapInfo{"
+ + "servers=" + servers + ", "
+ + "serverListenerResourceNameTemplate=" +
serverListenerResourceNameTemplate + ", "
+ + "node=" + node + ", "
+ + "}";
+ }
+
+ public static final class Builder extends
Bootstrapper.BootstrapInfo.Builder {
+ private List<Bootstrapper.ServerInfo> servers;
+ private Node node;
+
+ private Map<String, Bootstrapper.CertificateProviderInfo>
certProviders;
+
+ private String serverListenerResourceNameTemplate;
+ Builder() {
+ }
+ @Override
+ Bootstrapper.BootstrapInfo.Builder
servers(List<Bootstrapper.ServerInfo> servers) {
+ this.servers = new LinkedList<>(servers);
+ return this;
+ }
+
+ @Override
+ Bootstrapper.BootstrapInfo.Builder node(Node node) {
+ if (node == null) {
+ throw new NullPointerException("Null node");
+ }
+ this.node = node;
+ return this;
+ }
+
+ @Override
+ Bootstrapper.BootstrapInfo.Builder certProviders(@Nullable Map<String,
Bootstrapper.CertificateProviderInfo> certProviders) {
+ this.certProviders = certProviders;
+ return this;
+ }
+
+ @Override
+ Bootstrapper.BootstrapInfo.Builder
serverListenerResourceNameTemplate(@Nullable String
serverListenerResourceNameTemplate) {
+ this.serverListenerResourceNameTemplate =
serverListenerResourceNameTemplate;
+ return this;
+ }
+
+ @Override
+ Bootstrapper.BootstrapInfo build() {
+ if (this.servers == null
+ || this.node == null) {
+ StringBuilder missing = new StringBuilder();
+ if (this.servers == null) {
+ missing.append(" servers");
+ }
+ if (this.node == null) {
+ missing.append(" node");
+ }
+ throw new IllegalStateException("Missing required properties:"
+ missing);
+ }
+ return new BootstrapInfoImpl(
+ this.servers,
+ this.serverListenerResourceNameTemplate,
+ this.certProviders,
+ this.node);
+ }
+ }
+
+}
+
diff --git
a/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/Bootstrapper.java
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/Bootstrapper.java
new file mode 100644
index 0000000000..68473be5af
--- /dev/null
+++
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/Bootstrapper.java
@@ -0,0 +1,75 @@
+/*
+ * 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.dubbo.registry.xds.util.bootstrap;
+
+import io.envoyproxy.envoy.config.core.v3.Node;
+import io.grpc.ChannelCredentials;
+import org.apache.dubbo.registry.xds.XdsInitializationException;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Map;
+
+public abstract class Bootstrapper {
+
+ public abstract BootstrapInfo bootstrap() throws
XdsInitializationException;
+
+ BootstrapInfo bootstrap(Map<String, ?> rawData) throws
XdsInitializationException {
+ throw new UnsupportedOperationException();
+ }
+
+ abstract static class ServerInfo {
+ abstract String target();
+
+ abstract ChannelCredentials channelCredentials();
+
+ abstract boolean useProtocolV3();
+
+ abstract boolean ignoreResourceDeletion();
+
+ }
+
+ public abstract static class CertificateProviderInfo {
+ public abstract String pluginName();
+
+ public abstract Map<String, ?> config();
+ }
+
+ public abstract static class BootstrapInfo {
+ abstract List<ServerInfo> servers();
+
+ abstract Map<String, CertificateProviderInfo> certProviders();
+
+ public abstract Node node();
+
+ public abstract String serverListenerResourceNameTemplate();
+
+ abstract static class Builder {
+
+ abstract Builder servers(List<ServerInfo> servers);
+
+ abstract Builder node(Node node);
+
+ abstract Builder certProviders(@Nullable Map<String,
CertificateProviderInfo> certProviders);
+
+ abstract Builder serverListenerResourceNameTemplate(
+ @Nullable String serverListenerResourceNameTemplate);
+
+ abstract BootstrapInfo build();
+ }
+ }
+}
diff --git
a/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/BootstrapperImpl.java
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/BootstrapperImpl.java
new file mode 100644
index 0000000000..ce6490bc3c
--- /dev/null
+++
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/BootstrapperImpl.java
@@ -0,0 +1,180 @@
+/*
+ * 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.dubbo.registry.xds.util.bootstrap;
+
+import io.envoyproxy.envoy.config.core.v3.Node;
+import io.grpc.ChannelCredentials;
+import io.grpc.internal.JsonParser;
+import io.grpc.internal.JsonUtil;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.registry.xds.XdsInitializationException;
+
+import javax.annotation.Nullable;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+class BootstrapperImpl extends Bootstrapper {
+
+ static final String BOOTSTRAP_PATH_SYS_ENV_VAR = "GRPC_XDS_BOOTSTRAP";
+ static String bootstrapPathFromEnvVar =
System.getenv(BOOTSTRAP_PATH_SYS_ENV_VAR);
+
+ private static final Logger logger =
LoggerFactory.getLogger(BootstrapperImpl.class);
+ private FileReader reader = LocalFileReader.INSTANCE;
+
+ private static final String SERVER_FEATURE_XDS_V3 = "xds_v3";
+ private static final String SERVER_FEATURE_IGNORE_RESOURCE_DELETION =
"ignore_resource_deletion";
+
+ public BootstrapInfo bootstrap() throws XdsInitializationException {
+ String filePath = bootstrapPathFromEnvVar;
+ String fileContent = null;
+ if (filePath != null) {
+ try {
+ fileContent = reader.readFile(filePath);
+ } catch (IOException e) {
+ throw new XdsInitializationException("Fail to read bootstrap
file", e);
+ }
+ }
+ if (fileContent == null) throw new XdsInitializationException("Cannot
find bootstrap configuration");
+
+ Map<String, ?> rawBootstrap;
+ try {
+ rawBootstrap = (Map<String, ?>) JsonParser.parse(fileContent);
+ } catch (IOException e) {
+ throw new XdsInitializationException("Failed to parse JSON", e);
+ }
+ return bootstrap(rawBootstrap);
+ }
+
+ @Override
+ BootstrapInfo bootstrap(Map<String, ?> rawData) throws
XdsInitializationException {
+ BootstrapInfo.Builder builder = new BootstrapInfoImpl.Builder();
+
+ List<?> rawServerConfigs = JsonUtil.getList(rawData, "xds_servers");
+ if (rawServerConfigs == null) {
+ throw new XdsInitializationException("Invalid bootstrap:
'xds_servers' does not exist.");
+ }
+ List<ServerInfo> servers = parseServerInfos(rawServerConfigs);
+ builder.servers(servers);
+
+ Node.Builder nodeBuilder = Node.newBuilder();
+ Map<String, ?> rawNode = JsonUtil.getObject(rawData, "node");
+ if (rawNode != null) {
+ String id = JsonUtil.getString(rawNode, "id");
+ if (id != null) {
+ nodeBuilder.setId(id);
+ }
+ String cluster = JsonUtil.getString(rawNode, "cluster");
+ if (cluster != null) {
+ nodeBuilder.setCluster(cluster);
+ }
+ Map<String, ?> metadata = JsonUtil.getObject(rawNode, "metadata");
+ Map<String, ?> rawLocality = JsonUtil.getObject(rawNode,
"locality");
+ }
+ builder.node(nodeBuilder.build());
+
+ Map<String, ?> certProvidersBlob = JsonUtil.getObject(rawData,
"certificate_providers");
+ if (certProvidersBlob != null) {
+ Map<String, CertificateProviderInfo> certProviders = new
HashMap<>(certProvidersBlob.size());
+ for (String name : certProvidersBlob.keySet()) {
+ Map<String, ?> valueMap =
JsonUtil.getObject(certProvidersBlob, name);
+ String pluginName =
+ checkForNull(JsonUtil.getString(valueMap, "plugin_name"),
"plugin_name");
+ Map<String, ?> config =
checkForNull(JsonUtil.getObject(valueMap, "config"), "config");
+ CertificateProviderInfoImpl certificateProviderInfo =
+ new CertificateProviderInfoImpl(pluginName, config);
+ certProviders.put(name, certificateProviderInfo);
+ }
+ builder.certProviders(certProviders);
+ }
+
+ return builder.build();
+ }
+
+ private static List<ServerInfo> parseServerInfos(List<?> rawServerConfigs)
+ throws XdsInitializationException {
+ List<ServerInfo> servers = new LinkedList<>();
+ List<Map<String, ?>> serverConfigList =
JsonUtil.checkObjectList(rawServerConfigs);
+ for (Map<String, ?> serverConfig : serverConfigList) {
+ String serverUri = JsonUtil.getString(serverConfig, "server_uri");
+ if (serverUri == null) {
+ throw new XdsInitializationException("Invalid bootstrap:
missing 'server_uri'");
+ }
+ List<?> rawChannelCredsList = JsonUtil.getList(serverConfig,
"channel_creds");
+ if (rawChannelCredsList == null || rawChannelCredsList.isEmpty()) {
+ throw new XdsInitializationException(
+ "Invalid bootstrap: server " + serverUri + "
'channel_creds' required");
+ }
+ ChannelCredentials channelCredentials =
+
parseChannelCredentials(JsonUtil.checkObjectList(rawChannelCredsList),
serverUri);
+// if (channelCredentials == null) {
+// throw new XdsInitializationException(
+// "Server " + serverUri + ": no supported channel
credentials found");
+// }
+
+ boolean useProtocolV3 = false;
+ boolean ignoreResourceDeletion = false;
+ List<String> serverFeatures =
JsonUtil.getListOfStrings(serverConfig, "server_features");
+ if (serverFeatures != null) {
+ useProtocolV3 = serverFeatures.contains(SERVER_FEATURE_XDS_V3);
+ ignoreResourceDeletion =
serverFeatures.contains(SERVER_FEATURE_IGNORE_RESOURCE_DELETION);
+ }
+ servers.add(
+ new ServerInfoImpl(serverUri, channelCredentials,
useProtocolV3, ignoreResourceDeletion));
+ }
+ return servers;
+ }
+
+ void setFileReader(FileReader reader) {
+ this.reader = reader;
+ }
+
+ /**
+ * Reads the content of the file with the given path in the file system.
+ */
+ interface FileReader {
+ String readFile(String path) throws IOException;
+ }
+
+ private enum LocalFileReader implements FileReader {
+ INSTANCE;
+
+ @Override
+ public String readFile(String path) throws IOException {
+ return new String(Files.readAllBytes(Paths.get(path)),
StandardCharsets.UTF_8);
+ }
+ }
+
+ private static <T> T checkForNull(T value, String fieldName) throws
XdsInitializationException {
+ if (value == null) {
+ throw new XdsInitializationException(
+ "Invalid bootstrap: '" + fieldName + "' does not exist.");
+ }
+ return value;
+ }
+
+ @Nullable
+ private static ChannelCredentials parseChannelCredentials(List<Map<String,
?>> jsonList, String serverUri) throws XdsInitializationException {
+ return null;
+ }
+}
diff --git
a/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/CertificateProviderInfoImpl.java
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/CertificateProviderInfoImpl.java
new file mode 100644
index 0000000000..2c3da740a2
--- /dev/null
+++
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/CertificateProviderInfoImpl.java
@@ -0,0 +1,49 @@
+/*
+ * 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.dubbo.registry.xds.util.bootstrap;
+
+import java.util.Map;
+
+final class CertificateProviderInfoImpl extends
Bootstrapper.CertificateProviderInfo {
+
+ private final String pluginName;
+ private final Map<String, ?> config;
+
+ CertificateProviderInfoImpl(String pluginName, Map<String, ?> config) {
+ this.pluginName = pluginName;
+ this.config = config;
+ }
+
+ @Override
+ public String pluginName() {
+ return pluginName;
+ }
+
+ @Override
+ public Map<String, ?> config() {
+ return config;
+ }
+
+ @Override
+ public String toString() {
+ return "CertificateProviderInfo{"
+ + "pluginName=" + pluginName + ", "
+ + "config=" + config
+ + "}";
+ }
+
+}
diff --git
a/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/ServerInfoImpl.java
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/ServerInfoImpl.java
new file mode 100644
index 0000000000..de0402e965
--- /dev/null
+++
b/dubbo-xds/src/main/java/org/apache/dubbo/registry/xds/util/bootstrap/ServerInfoImpl.java
@@ -0,0 +1,68 @@
+/*
+ * 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.dubbo.registry.xds.util.bootstrap;
+
+import io.grpc.ChannelCredentials;
+
+final class ServerInfoImpl extends Bootstrapper.ServerInfo {
+
+ private final String target;
+
+ private final ChannelCredentials channelCredentials;
+
+ private final boolean useProtocolV3;
+
+ private final boolean ignoreResourceDeletion;
+
+ ServerInfoImpl(String target, ChannelCredentials channelCredentials,
boolean useProtocolV3, boolean ignoreResourceDeletion) {
+ this.target = target;
+ this.channelCredentials = channelCredentials;
+ this.useProtocolV3 = useProtocolV3;
+ this.ignoreResourceDeletion = ignoreResourceDeletion;
+ }
+
+ @Override
+ String target() {
+ return target;
+ }
+
+ @Override
+ ChannelCredentials channelCredentials() {
+ return channelCredentials;
+ }
+
+ @Override
+ boolean useProtocolV3() {
+ return useProtocolV3;
+ }
+
+ @Override
+ boolean ignoreResourceDeletion() {
+ return ignoreResourceDeletion;
+ }
+
+ @Override
+ public String toString() {
+ return "ServerInfo{"
+ + "target=" + target + ", "
+ + "channelCredentials=" + channelCredentials + ", "
+ + "useProtocolV3=" + useProtocolV3 + ", "
+ + "ignoreResourceDeletion=" + ignoreResourceDeletion
+ + "}";
+ }
+
+}
diff --git
a/dubbo-xds/src/test/java/org/apache/dubbo/registry/xds/util/bootstrap/BootstrapperTest.java
b/dubbo-xds/src/test/java/org/apache/dubbo/registry/xds/util/bootstrap/BootstrapperTest.java
new file mode 100644
index 0000000000..e1a871d1e2
--- /dev/null
+++
b/dubbo-xds/src/test/java/org/apache/dubbo/registry/xds/util/bootstrap/BootstrapperTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.dubbo.registry.xds.util.bootstrap;
+
+import org.apache.dubbo.registry.xds.XdsInitializationException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+public class BootstrapperTest {
+ @Test
+ public void testParse() throws XdsInitializationException {
+ String rawData = "{\n" +
+ " \"xds_servers\": [\n" +
+ " {\n" +
+ " \"server_uri\": \"unix:///etc/istio/proxy/XDS\",\n" +
+ " \"channel_creds\": [\n" +
+ " {\n" +
+ " \"type\": \"insecure\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"server_features\": [\n" +
+ " \"xds_v3\"\n" +
+ " ]\n" +
+ " }\n" +
+ " ],\n" +
+ " \"node\": {\n" +
+ " \"id\":
\"sidecar~172.17.0.4~dubbo-demo-consumer-deployment-grpc-agent-58585cb9cd-gp79p.dubbo-demo~dubbo-demo.svc.cluster.local\",\n"
+
+ " \"metadata\": {\n" +
+ " \"ANNOTATIONS\": {\n" +
+ " \"inject.istio.io/templates\": \"grpc-agent\",\n" +
+ " \"kubernetes.io/config.seen\":
\"2022-07-19T12:53:29.742565722Z\",\n" +
+ " \"kubernetes.io/config.source\": \"api\",\n" +
+ " \"prometheus.io/path\": \"/stats/prometheus\",\n" +
+ " \"prometheus.io/port\": \"15020\",\n" +
+ " \"prometheus.io/scrape\": \"true\",\n" +
+ " \"proxy.istio.io/config\":
\"{\\\"holdApplicationUntilProxyStarts\\\": true}\",\n" +
+ " \"proxy.istio.io/overrides\":
\"{\\\"containers\\\":[{\\\"name\\\":\\\"app\\\",\\\"image\\\":\\\"gcr.io/istio-testing/app:latest\\\",\\\"args\\\":[\\\"--metrics=15014\\\",\\\"--port\\\",\\\"18080\\\",\\\"--tcp\\\",\\\"19090\\\",\\\"--xds-grpc-server=17070\\\",\\\"--grpc\\\",\\\"17070\\\",\\\"--grpc\\\",\\\"17171\\\",\\\"--port\\\",\\\"3333\\\",\\\"--port\\\",\\\"8080\\\",\\\"--version\\\",\\\"v1\\\",\\\"--crt=/cert.crt\\\",\\\"--key=/cert.key\\\"],\\\"ports\\\":[{\\\
[...]
+ " \"sidecar.istio.io/rewriteAppHTTPProbers\": \"false\",\n"
+
+ " \"sidecar.istio.io/status\":
\"{\\\"initContainers\\\":null,\\\"containers\\\":[\\\"app\\\",\\\"dubbo-demo-consumer\\\",\\\"istio-proxy\\\"],\\\"volumes\\\":[\\\"workload-socket\\\",\\\"workload-certs\\\",\\\"istio-xds\\\",\\\"istio-data\\\",\\\"istio-podinfo\\\",\\\"istio-token\\\",\\\"istiod-ca-cert\\\"],\\\"imagePullSecrets\\\":null,\\\"revision\\\":\\\"default\\\"}\"\n"
+
+ " },\n" +
+ " \"APP_CONTAINERS\": \"app,dubbo-demo-consumer\",\n" +
+ " \"CLUSTER_ID\": \"Kubernetes\",\n" +
+ " \"ENVOY_PROMETHEUS_PORT\": 15090,\n" +
+ " \"ENVOY_STATUS_PORT\": 15021,\n" +
+ " \"GENERATOR\": \"grpc\",\n" +
+ " \"INSTANCE_IPS\": \"172.17.0.4\",\n" +
+ " \"INTERCEPTION_MODE\": \"REDIRECT\",\n" +
+ " \"ISTIO_PROXY_SHA\":
\"2b6009118109b480e1d5abf3188fd7d9c0c0acf0\",\n" +
+ " \"ISTIO_VERSION\": \"1.14.1\",\n" +
+ " \"LABELS\": {\n" +
+ " \"app\": \"dubbo-demo-consumer-dev\",\n" +
+ " \"pod-template-hash\": \"58585cb9cd\",\n" +
+ " \"service.istio.io/canonical-name\":
\"dubbo-demo-consumer-dev\",\n" +
+ " \"service.istio.io/canonical-revision\": \"v1\",\n" +
+ " \"version\": \"v1\"\n" +
+ " },\n" +
+ " \"MESH_ID\": \"cluster.local\",\n" +
+ " \"NAME\":
\"dubbo-demo-consumer-deployment-grpc-agent-58585cb9cd-gp79p\",\n" +
+ " \"NAMESPACE\": \"dubbo-demo\",\n" +
+ " \"OWNER\":
\"kubernetes://apis/apps/v1/namespaces/dubbo-demo/deployments/dubbo-demo-consumer-deployment-grpc-agent\",\n"
+
+ " \"PILOT_SAN\": [\n" +
+ " \"istiod.istio-system.svc\"\n" +
+ " ],\n" +
+ " \"POD_PORTS\":
\"[{\\\"containerPort\\\":17070,\\\"protocol\\\":\\\"TCP\\\"},{\\\"containerPort\\\":17171,\\\"protocol\\\":\\\"TCP\\\"},{\\\"containerPort\\\":8080,\\\"protocol\\\":\\\"TCP\\\"},{\\\"name\\\":\\\"tcp-health-port\\\",\\\"containerPort\\\":3333,\\\"protocol\\\":\\\"TCP\\\"}]\",\n"
+
+ " \"PROV_CERT\": \"var/run/secrets/istio/root-cert.pem\",\n" +
+ " \"PROXY_CONFIG\": {\n" +
+ " \"binaryPath\": \"/usr/local/bin/envoy\",\n" +
+ " \"concurrency\": 2,\n" +
+ " \"configPath\": \"./etc/istio/proxy\",\n" +
+ " \"controlPlaneAuthPolicy\": \"MUTUAL_TLS\",\n" +
+ " \"discoveryAddress\":
\"istiod.istio-system.svc:15012\",\n" +
+ " \"drainDuration\": \"45s\",\n" +
+ " \"holdApplicationUntilProxyStarts\": true,\n" +
+ " \"parentShutdownDuration\": \"60s\",\n" +
+ " \"proxyAdminPort\": 15000,\n" +
+ " \"serviceCluster\": \"istio-proxy\",\n" +
+ " \"statNameLength\": 189,\n" +
+ " \"statusPort\": 15020,\n" +
+ " \"terminationDrainDuration\": \"5s\",\n" +
+ " \"tracing\": {\n" +
+ " \"zipkin\": {\n" +
+ " \"address\": \"zipkin.istio-system:9411\"\n" +
+ " }\n" +
+ " }\n" +
+ " },\n" +
+ " \"SERVICE_ACCOUNT\": \"default\",\n" +
+ " \"WORKLOAD_NAME\":
\"dubbo-demo-consumer-deployment-grpc-agent\"\n" +
+ " },\n" +
+ " \"locality\": {},\n" +
+ " \"UserAgentVersionType\": null\n" +
+ " },\n" +
+ " \"certificate_providers\": {\n" +
+ " \"default\": {\n" +
+ " \"plugin_name\": \"file_watcher\",\n" +
+ " \"config\": {\n" +
+ " \"certificate_file\":
\"/var/lib/istio/data/cert-chain.pem\",\n" +
+ " \"private_key_file\": \"/var/lib/istio/data/key.pem\",\n"
+
+ " \"ca_certificate_file\":
\"/var/lib/istio/data/root-cert.pem\",\n" +
+ " \"refresh_interval\": \"900s\"\n" +
+ " }\n" +
+ " }\n" +
+ " },\n" +
+ " \"server_listener_resource_name_template\":
\"xds.istio.io/grpc/lds/inbound/%s\"\n" +
+ "}";
+ BootstrapperImpl.bootstrapPathFromEnvVar = "";
+ BootstrapperImpl bootstrapper = new BootstrapperImpl();
+ bootstrapper.setFileReader(createFileReader(rawData));
+ Bootstrapper.BootstrapInfo info = bootstrapper.bootstrap();
+ List<Bootstrapper.ServerInfo> serverInfoList = info.servers();
+ Assertions.assertEquals(serverInfoList.get(0).target(),
"unix:///etc/istio/proxy/XDS");
+ }
+
+ private static BootstrapperImpl.FileReader createFileReader(final String
rawData) {
+ return new BootstrapperImpl.FileReader() {
+ @Override
+ public String readFile(String path) throws IOException {
+ return rawData;
+ }
+ };
+ }
+
+}