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;
+            }
+        };
+    }
+
+}

Reply via email to