You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by jo...@apache.org on 2023/09/21 01:55:03 UTC

[shenyu] branch master updated: [type:feature] init context path plugin shenyu ingress controller (#5167)

This is an automated email from the ASF dual-hosted git repository.

jooks pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new bdc59e4e61 [type:feature] init context path plugin shenyu ingress controller (#5167)
bdc59e4e61 is described below

commit bdc59e4e61bd4cd2ec9f16ef29bd310a5d096944
Author: Runqi Zhao <40...@users.noreply.github.com>
AuthorDate: Thu Sep 21 09:54:58 2023 +0800

    [type:feature] init context path plugin shenyu ingress controller (#5167)
    
    * [type:feature] init context path plugin shenyu ingress controller
    
    * [type:feature] init context path plugin shenyu ingress controller
    
    ---------
    
    Co-authored-by: yunlongn <yu...@outlook.com>
    Co-authored-by: dragon-zhang <zh...@apache.org>
    Co-authored-by: zhengpeng <84...@qq.com>
---
 .../apache/shenyu/k8s/common/IngressConstants.java |  15 +-
 .../shenyu/k8s/parser/ContextPathParser.java       | 198 +++++++++++++++++++++
 .../apache/shenyu/k8s/parser/IngressParser.java    |  56 ++++--
 .../shenyu/k8s/parser/K8sResourceListParser.java   |  41 +++++
 .../shenyu/k8s/reconciler/IngressReconciler.java   | 189 +++++++++++++-------
 5 files changed, 417 insertions(+), 82 deletions(-)

diff --git a/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/common/IngressConstants.java b/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/common/IngressConstants.java
index 30a975e72b..14778f6870 100644
--- a/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/common/IngressConstants.java
+++ b/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/common/IngressConstants.java
@@ -117,7 +117,7 @@ public class IngressConstants {
     // The configuration key to specify the SpringCloud path for the plugin, in string
     public static final String PLUGIN_SPRING_CLOUD_PATH = "shenyu.apache.org/plugin-spring-cloud-path";
 
-    // he configuration key to specify the SpringCloud context path for the plugin, in string
+    // The configuration key to specify the SpringCloud context path for the plugin, in string
     public static final String PLUGIN_SPRING_CLOUD_CONTEXT_PATH = "shenyu.apache.org/plugin-spring-cloud-context-path";
 
     // The configuration key to specify the SpringCloud load balance for the plugin, in string
@@ -141,10 +141,21 @@ public class IngressConstants {
     // The configuration key to specify the SpringCloud gray for the plugin, in string
     public static final String PLUGIN_SPRING_CLOUD_GRAY = "shenyu.apache.org/plugin-spring-cloud-gray";
 
-    // // Determining whether to use the WebSocket plugin, in String
+    //Determining whether to use the WebSocket plugin, in String
     public static final String PLUGIN_WEB_SOCKET_ENABLED = "shenyu.apache.org/plugin-web-socket-enabled";
 
     // Upstream protocol, in string
     public static final String UPSTREAMS_PROTOCOL_ANNOTATION_KEY = "shenyu.apache.org/upstreams-protocol";
 
+    //The configuration key to specify the Context path for the plugin, in string
+    public static final String PLUGIN_CONTEXT_PATH_PATH = "shenyu.apache.org/plugin-context-path-path";
+
+    //The configuration key to specify the Context path add prefix for the plugin, in string
+    public static final String PLUGIN_CONTEXT_PATH_ADD_PREFIX = "shenyu.apache.org/plugin-context-path-add-prefix";
+
+    public static final String PLUGIN_CONTEXT_PATH_ADD_PREFIXED = "shenyu.apache.org/plugin-context-path-add-prefixed";
+
+
+
+
 }
diff --git a/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/parser/ContextPathParser.java b/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/parser/ContextPathParser.java
new file mode 100644
index 0000000000..c35432e3a9
--- /dev/null
+++ b/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/parser/ContextPathParser.java
@@ -0,0 +1,198 @@
+/*
+ * 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.shenyu.k8s.parser;
+
+import io.kubernetes.client.informer.cache.Lister;
+import io.kubernetes.client.openapi.apis.CoreV1Api;
+import io.kubernetes.client.openapi.models.V1Endpoints;
+import io.kubernetes.client.openapi.models.V1HTTPIngressPath;
+import io.kubernetes.client.openapi.models.V1Ingress;
+import io.kubernetes.client.openapi.models.V1IngressRule;
+import io.kubernetes.client.openapi.models.V1Service;
+import org.apache.shenyu.common.dto.ConditionData;
+import org.apache.shenyu.common.dto.RuleData;
+import org.apache.shenyu.common.dto.SelectorData;
+import org.apache.shenyu.common.dto.convert.rule.impl.ContextMappingRuleHandle;
+import org.apache.shenyu.common.enums.MatchModeEnum;
+import org.apache.shenyu.common.enums.OperatorEnum;
+import org.apache.shenyu.common.enums.ParamTypeEnum;
+import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.enums.SelectorTypeEnum;
+import org.apache.shenyu.common.utils.GsonUtils;
+import org.apache.shenyu.k8s.common.IngressConfiguration;
+import org.apache.shenyu.k8s.common.IngressConstants;
+import org.apache.shenyu.k8s.common.ShenyuMemoryConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Parser of Ingress ContextPath Annotations.
+ */
+public class ContextPathParser implements K8sResourceParser<V1Ingress> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ContextPathParser.class);
+
+    private final Lister<V1Service> serviceLister;
+
+    private final Lister<V1Endpoints> endpointsLister;
+
+    /**
+     * IngressParser Constructor.
+     *
+     * @param serviceLister serviceLister
+     * @param endpointsLister endpointsLister
+     */
+    public ContextPathParser(final Lister<V1Service> serviceLister, final Lister<V1Endpoints> endpointsLister) {
+        this.serviceLister = serviceLister;
+        this.endpointsLister = endpointsLister;
+    }
+
+    /**
+     * Parse ingress to ShenyuMemoryConfig.
+     *
+     * @param ingress ingress resource
+     * @param coreV1Api coreV1Api
+     * @return ShenyuMemoryConfig
+     */
+    @Override
+    public ShenyuMemoryConfig parse(final V1Ingress ingress, final CoreV1Api coreV1Api) {
+        ShenyuMemoryConfig res = new ShenyuMemoryConfig();
+
+        if (Objects.nonNull(ingress.getSpec())) {
+            // if rules is null, context path Plugin will not execute the
+            List<V1IngressRule> rules = ingress.getSpec().getRules();
+            if (Objects.nonNull(rules)) {
+                List<IngressConfiguration> routeList = new ArrayList<>(rules.size());
+                for (V1IngressRule ingressRule : rules) {
+                    List<IngressConfiguration> routes = parseIngressRule(ingressRule, ingress.getMetadata().getAnnotations());
+                    routeList.addAll(routes);
+                }
+                res.setRouteConfigList(routeList);
+            }
+        }
+        return res;
+    }
+
+    private List<IngressConfiguration> parseIngressRule(final V1IngressRule ingressRule, final Map<String, String> annotations) {
+        List<IngressConfiguration> res = new ArrayList<>();
+        ConditionData hostCondition = Objects.nonNull(ingressRule.getHost()) ? createHostCondition(ingressRule.getHost()) : null;
+        if (Objects.nonNull(ingressRule.getHttp())) {
+            List<V1HTTPIngressPath> paths = ingressRule.getHttp().getPaths();
+            if (Objects.nonNull(paths)) {
+                for (V1HTTPIngressPath path : paths) {
+                    if (path.getPath() == null) {
+                        continue;
+                    }
+                    OperatorEnum operator = getOperator(path.getPathType());
+                    ConditionData pathCondition = createPathCondition(path.getPath(), operator);
+                    List<ConditionData> conditionList = new ArrayList<>(2);
+                    if (Objects.nonNull(hostCondition)) {
+                        conditionList.add(hostCondition);
+                    }
+                    conditionList.add(pathCondition);
+                    SelectorData selectorData = createSelectorData(path.getPath(), conditionList);
+                    ContextMappingRuleHandle contextMappingRuleHandle = createContextMappingRuleHandle(annotations);
+                    List<RuleData> ruleDataList = new ArrayList<>();
+                    List<ConditionData> ruleConditionList = getRuleConditionList(annotations);
+                    RuleData ruleData = createRuleData(annotations, contextMappingRuleHandle, ruleConditionList);
+                    ruleDataList.add(ruleData);
+                    res.add(new IngressConfiguration(selectorData, ruleDataList, null));
+                }
+            }
+        }
+        return res;
+    }
+
+    private ConditionData createHostCondition(final String host) {
+        ConditionData hostCondition = new ConditionData();
+        hostCondition.setParamType(ParamTypeEnum.DOMAIN.getName());
+        hostCondition.setOperator(OperatorEnum.EQ.getAlias());
+        hostCondition.setParamValue(host);
+        return hostCondition;
+    }
+
+    private OperatorEnum getOperator(final String pathType) {
+        if ("ImplementationSpecific".equals(pathType)) {
+            return OperatorEnum.MATCH;
+        } else if ("Prefix".equals(pathType)) {
+            return OperatorEnum.STARTS_WITH;
+        } else if ("Exact".equals(pathType)) {
+            return OperatorEnum.EQ;
+        } else {
+            LOG.info("Invalid path type, set it with match operator");
+            return OperatorEnum.MATCH;
+        }
+    }
+
+    private ConditionData createPathCondition(final String path, final OperatorEnum operator) {
+        ConditionData pathCondition = new ConditionData();
+        pathCondition.setOperator(operator.getAlias());
+        pathCondition.setParamType(ParamTypeEnum.URI.getName());
+        pathCondition.setParamValue(path);
+        return pathCondition;
+    }
+
+    private SelectorData createSelectorData(final String path, final List<ConditionData> conditionList) {
+        return SelectorData.builder()
+                .pluginId(String.valueOf(PluginEnum.CONTEXT_PATH.getCode()))
+                .pluginName(PluginEnum.CONTEXT_PATH.getName())
+                .name(path)
+                .matchMode(MatchModeEnum.AND.getCode())
+                .type(SelectorTypeEnum.CUSTOM_FLOW.getCode())
+                .enabled(true)
+                .logged(false)
+                .continued(true)
+                .conditionList(conditionList)
+                .build();
+    }
+
+    private ContextMappingRuleHandle createContextMappingRuleHandle(final Map<String, String> annotations) {
+        ContextMappingRuleHandle ruleHandle = new ContextMappingRuleHandle();
+        ruleHandle.setContextPath(annotations.get(IngressConstants.PLUGIN_CONTEXT_PATH_PATH));
+        ruleHandle.setAddPrefix(annotations.get(IngressConstants.PLUGIN_CONTEXT_PATH_ADD_PREFIX));
+        ruleHandle.setAddPrefixed(Boolean.parseBoolean(annotations.getOrDefault(IngressConstants.PLUGIN_CONTEXT_PATH_ADD_PREFIXED, "false")));
+        return ruleHandle;
+    }
+
+    private RuleData createRuleData(final Map<String, String> annotations, final ContextMappingRuleHandle ruleHandle, final List<ConditionData> ruleConditionList) {
+        return RuleData.builder()
+                .name(annotations.get(IngressConstants.PLUGIN_CONTEXT_PATH_PATH))
+                .pluginName(PluginEnum.CONTEXT_PATH.getName())
+                .matchMode(MatchModeEnum.AND.getCode())
+                .conditionDataList(ruleConditionList)
+                .handle(GsonUtils.getInstance().toJson(ruleHandle))
+                .loged(true)
+                .enabled(true)
+                .build();
+    }
+
+    private List<ConditionData> getRuleConditionList(final Map<String, String> annotations) {
+        final List<ConditionData> ruleConditionList = new ArrayList<>();
+        ConditionData ruleCondition = new ConditionData();
+        ruleCondition.setOperator(OperatorEnum.PATH_PATTERN.getAlias());
+        ruleCondition.setParamType(ParamTypeEnum.URI.getName());
+        ruleCondition.setParamValue(annotations.get(IngressConstants.PLUGIN_CONTEXT_PATH_PATH) + "/**");
+        ruleConditionList.add(ruleCondition);
+        return ruleConditionList;
+    }
+}
diff --git a/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/parser/IngressParser.java b/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/parser/IngressParser.java
index faab0f7608..97d547c257 100644
--- a/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/parser/IngressParser.java
+++ b/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/parser/IngressParser.java
@@ -21,19 +21,22 @@ import io.kubernetes.client.informer.SharedIndexInformer;
 import io.kubernetes.client.informer.cache.Lister;
 import io.kubernetes.client.openapi.apis.CoreV1Api;
 import io.kubernetes.client.openapi.models.V1Endpoints;
+import io.kubernetes.client.openapi.models.V1HTTPIngressPath;
 import io.kubernetes.client.openapi.models.V1Ingress;
+import io.kubernetes.client.openapi.models.V1IngressRule;
 import io.kubernetes.client.openapi.models.V1Service;
 import org.apache.shenyu.k8s.common.IngressConstants;
 import org.apache.shenyu.k8s.common.ShenyuMemoryConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Objects;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Parser of Ingress.
  */
-public class IngressParser implements K8sResourceParser<V1Ingress> {
+public class IngressParser implements K8sResourceListParser<V1Ingress> {
 
     private static final Logger LOG = LoggerFactory.getLogger(IngressParser.class);
 
@@ -60,25 +63,54 @@ public class IngressParser implements K8sResourceParser<V1Ingress> {
      * @return ShenyuMemoryConfig
      */
     @Override
-    public ShenyuMemoryConfig parse(final V1Ingress ingress, final CoreV1Api coreV1Api) {
-        if (Objects.equals(ingress.getMetadata().getAnnotations().get(IngressConstants.PLUGIN_DUBBO_ENABLED), "true")) {
+    public List<ShenyuMemoryConfig> parse(final V1Ingress ingress, final CoreV1Api coreV1Api) {
+        List<ShenyuMemoryConfig> shenyuMemoryConfigList = new ArrayList<>();
+        boolean dubboEnabled = getBooleanAnnotation(ingress, IngressConstants.PLUGIN_DUBBO_ENABLED);
+        boolean motanEnabled = getBooleanAnnotation(ingress, IngressConstants.PLUGIN_MOTAN_ENABLED);
+        boolean springCloudEnabled = getBooleanAnnotation(ingress, IngressConstants.PLUGIN_SPRING_CLOUD_ENABLED);
+        boolean webSocketEnabled = getBooleanAnnotation(ingress, IngressConstants.PLUGIN_WEB_SOCKET_ENABLED);
+
+        if (!dubboEnabled || !motanEnabled) {
+            contextPathParse(ingress, shenyuMemoryConfigList, coreV1Api);
+        }
+        if (dubboEnabled) {
             DubboIngressParser dubboIngressParser = new DubboIngressParser(serviceLister, endpointsLister);
-            return dubboIngressParser.parse(ingress, coreV1Api);
-        } else if (Objects.equals(ingress.getMetadata().getAnnotations().get(IngressConstants.PLUGIN_MOTAN_ENABLED), "true")) {
+            shenyuMemoryConfigList.add(dubboIngressParser.parse(ingress, coreV1Api));
+        } else if (motanEnabled) {
             MotanIngressParser motanIngressParser = new MotanIngressParser(serviceLister, endpointsLister);
-            return motanIngressParser.parse(ingress, coreV1Api);
-        } else if (Objects.equals(ingress.getMetadata().getAnnotations().get(IngressConstants.PLUGIN_SPRING_CLOUD_ENABLED), "true")) {
+            shenyuMemoryConfigList.add(motanIngressParser.parse(ingress, coreV1Api));
+        } else if (springCloudEnabled) {
             SpringCloudParser springCloudParser = new SpringCloudParser(serviceLister, endpointsLister);
-            return springCloudParser.parse(ingress, coreV1Api);
-        } else if (Objects.equals(ingress.getMetadata().getAnnotations().get(IngressConstants.PLUGIN_WEB_SOCKET_ENABLED), "true")) {
+            shenyuMemoryConfigList.add(springCloudParser.parse(ingress, coreV1Api));
+        } else if (webSocketEnabled) {
             WebSocketParser webSocketParser = new WebSocketParser(serviceLister, endpointsLister);
-            return webSocketParser.parse(ingress, coreV1Api);
+            shenyuMemoryConfigList.add(webSocketParser.parse(ingress, coreV1Api));
         } else {
             DivideIngressParser divideIngressParser = new DivideIngressParser(serviceLister, endpointsLister);
-            return divideIngressParser.parse(ingress, coreV1Api);
+            shenyuMemoryConfigList.add(divideIngressParser.parse(ingress, coreV1Api));
+        }
+        return shenyuMemoryConfigList;
+    }
+
+    private boolean getBooleanAnnotation(final V1Ingress ingress, final String annotationKey) {
+        String annotationValue = ingress.getMetadata().getAnnotations().get(annotationKey);
+        return annotationValue != null && Boolean.parseBoolean(annotationValue);
+    }
+
+    private void contextPathParse(final V1Ingress ingress, final List<ShenyuMemoryConfig> shenyuMemoryConfigList, final CoreV1Api coreV1Api) {
+        List<V1IngressRule> rules = ingress.getSpec().getRules();
+        for (V1IngressRule rule : rules) {
+            List<V1HTTPIngressPath> paths = rule.getHttp().getPaths();
+            for (V1HTTPIngressPath path : paths) {
+                if ("Prefix".equals(path.getPathType())) {
+                    ContextPathParser contextPathParser = new ContextPathParser(serviceLister, endpointsLister);
+                    shenyuMemoryConfigList.add(contextPathParser.parse(ingress, coreV1Api));
+                }
+            }
         }
     }
 
+
     /**
      * get endpointsLister.
      * @return endpointsLister
diff --git a/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/parser/K8sResourceListParser.java b/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/parser/K8sResourceListParser.java
new file mode 100644
index 0000000000..867ef63eb8
--- /dev/null
+++ b/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/parser/K8sResourceListParser.java
@@ -0,0 +1,41 @@
+/*
+ * 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.shenyu.k8s.parser;
+
+import io.kubernetes.client.openapi.apis.CoreV1Api;
+import org.apache.shenyu.k8s.common.ShenyuMemoryConfig;
+
+import java.util.List;
+
+/**
+ * Parser of Kubernetes resource list.
+ * Such as ingress, gateway, or even custom api resource.
+ *
+ * @param <T> resource type
+ */
+public interface K8sResourceListParser<T> {
+
+    /**
+     * Parse resource list to ShenyuMemoryConfig.
+     *
+     * @param resource resource
+     * @param coreV1Api coreV1Api
+     * @return ShenyuMemoryConfig
+     */
+    List<ShenyuMemoryConfig> parse(T resource, CoreV1Api coreV1Api);
+}
diff --git a/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/reconciler/IngressReconciler.java b/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/reconciler/IngressReconciler.java
index 9258353793..ece8ba4b36 100644
--- a/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/reconciler/IngressReconciler.java
+++ b/shenyu-kubernetes-controller/src/main/java/org/apache/shenyu/k8s/reconciler/IngressReconciler.java
@@ -408,82 +408,135 @@ public class IngressReconciler implements Reconciler {
 
     private void addNewIngressConfigToShenyu(final V1Ingress v1Ingress, final CoreV1Api apiClient) throws IOException {
         V1Ingress ingressCopy = new V1IngressBuilder(v1Ingress).build();
-        ShenyuMemoryConfig shenyuMemoryConfig = ingressParser.parse(ingressCopy, apiClient);
+        List<ShenyuMemoryConfig> shenyuMemoryConfigList = ingressParser.parse(ingressCopy, apiClient);
         String pluginName = getPluginName(ingressCopy);
-        if (Objects.nonNull(shenyuMemoryConfig)) {
-            List<IngressConfiguration> routeConfigList = shenyuMemoryConfig.getRouteConfigList();
-            if (Objects.isNull(routeConfigList)) {
-                return;
+
+        for (ShenyuMemoryConfig shenyuMemoryConfig : shenyuMemoryConfigList) {
+            if (Objects.nonNull(shenyuMemoryConfig)) {
+                processShenyuMemoryConfig(shenyuMemoryConfig, v1Ingress, pluginName);
             }
-            routeConfigList.forEach(routeConfig -> {
-                SelectorData selectorData = routeConfig.getSelectorData();
-                if (Objects.isNull(selectorData)) {
-                    return;
-                }
-                selectorData.setId(IngressSelectorCache.getInstance().generateSelectorId());
-                selectorData.setSort(100);
-                shenyuCacheRepository.saveOrUpdateSelectorData(selectorData);
-                List<RuleData> ruleDataList = routeConfig.getRuleDataList();
-                ruleDataList.forEach(ruleData -> {
-                    if (Objects.isNull(ruleData)) {
-                        shenyuCacheRepository.deleteSelectorData(selectorData.getPluginName(), selectorData.getId());
-                        return;
-                    }
-                    ruleData.setId(IngressSelectorCache.getInstance().generateRuleId());
-                    ruleData.setSelectorId(selectorData.getId());
-                    ruleData.setSort(100);
-                    shenyuCacheRepository.saveOrUpdateRuleData(ruleData);
-                    IngressSelectorCache.getInstance().put(Objects.requireNonNull(v1Ingress.getMetadata()).getNamespace(),
-                            v1Ingress.getMetadata().getName(), pluginName, selectorData.getId());
-                });
-                List<MetaData> metaDataList = routeConfig.getMetaDataList();
-                if (Objects.nonNull(metaDataList)) {
-                    metaDataList.forEach(metaData -> {
-                        if (Objects.nonNull(metaData)) {
-                            metaData.setId(IngressSelectorCache.getInstance().generateMetaDataId());
-                            shenyuCacheRepository.saveOrUpdateMetaData(metaData);
-                        }
-                    });
+        }
+    }
+
+    private void processShenyuMemoryConfig(final ShenyuMemoryConfig shenyuMemoryConfig, final V1Ingress v1Ingress, final String pluginName) throws IOException {
+        List<IngressConfiguration> routeConfigList = shenyuMemoryConfig.getRouteConfigList();
+
+        if (routeConfigList == null) {
+            return;
+        }
+
+        for (IngressConfiguration routeConfig : routeConfigList) {
+            SelectorData selectorData = routeConfig.getSelectorData();
+
+            if (selectorData != null) {
+                processSelectorData(routeConfig, selectorData, v1Ingress, pluginName);
+            }
+
+            List<MetaData> metaDataList = routeConfig.getMetaDataList();
+
+            if (metaDataList != null) {
+                processMetaDataList(metaDataList);
+            }
+        }
+
+        // Process global default backend if present
+        processGlobalDefaultBackend(shenyuMemoryConfig, v1Ingress, pluginName);
+
+        // Process TLS configurations
+        processTlsConfigurations(shenyuMemoryConfig, v1Ingress);
+    }
+
+    private void processSelectorData(final IngressConfiguration routeConfig, final SelectorData selectorData, final V1Ingress v1Ingress, final String pluginName) {
+        selectorData.setId(IngressSelectorCache.getInstance().generateSelectorId());
+        selectorData.setSort(100);
+        shenyuCacheRepository.saveOrUpdateSelectorData(selectorData);
+
+        List<RuleData> ruleDataList = routeConfig.getRuleDataList();
+
+        if (ruleDataList != null) {
+            processRuleDataList(ruleDataList, selectorData);
+        }
+
+        IngressSelectorCache.getInstance().put(
+                Objects.requireNonNull(v1Ingress.getMetadata()).getNamespace(),
+                v1Ingress.getMetadata().getName(),
+                pluginName,
+                selectorData.getId()
+        );
+    }
+
+    private void processRuleDataList(final List<RuleData> ruleDataList, final SelectorData selectorData) {
+        for (RuleData ruleData : ruleDataList) {
+            if (ruleData != null) {
+                ruleData.setId(IngressSelectorCache.getInstance().generateRuleId());
+                ruleData.setSelectorId(selectorData.getId());
+                ruleData.setSort(100);
+                shenyuCacheRepository.saveOrUpdateRuleData(ruleData);
+            }
+        }
+    }
+
+    private void processMetaDataList(final List<MetaData> metaDataList) {
+        for (MetaData metaData : metaDataList) {
+            if (metaData != null) {
+                metaData.setId(IngressSelectorCache.getInstance().generateMetaDataId());
+                shenyuCacheRepository.saveOrUpdateMetaData(metaData);
+            }
+        }
+    }
+
+    private void processGlobalDefaultBackend(final ShenyuMemoryConfig shenyuMemoryConfig, final V1Ingress v1Ingress, final String pluginName) {
+        if (shenyuMemoryConfig.getGlobalDefaultBackend() != null) {
+            synchronized (IngressReconciler.class) {
+                if (Objects.isNull(globalDefaultBackend)) {
+                    // Add a default backend
+                    IngressConfiguration ingressConfiguration = shenyuMemoryConfig.getGlobalDefaultBackend().getRight();
+                    SelectorData selectorData = ingressConfiguration.getSelectorData();
+                    shenyuCacheRepository.saveOrUpdateSelectorData(selectorData);
+                    ingressConfiguration.getRuleDataList().forEach(shenyuCacheRepository::saveOrUpdateRuleData);
+                    ingressConfiguration.getMetaDataList().forEach(shenyuCacheRepository::saveOrUpdateMetaData);
+                    globalDefaultBackend = shenyuMemoryConfig.getGlobalDefaultBackend();
+                    IngressSelectorCache.getInstance().put(
+                            Objects.requireNonNull(v1Ingress.getMetadata()).getNamespace(),
+                            v1Ingress.getMetadata().getName(),
+                            pluginName,
+                            selectorData.getId()
+                    );
                 }
-            });
-            if (Objects.nonNull(shenyuMemoryConfig.getGlobalDefaultBackend())) {
-                synchronized (IngressReconciler.class) {
-                    if (globalDefaultBackend == null) {
-                        // Add a default backend
-                        shenyuCacheRepository.saveOrUpdateSelectorData(shenyuMemoryConfig.getGlobalDefaultBackend().getRight().getSelectorData());
-                        shenyuMemoryConfig.getGlobalDefaultBackend().getRight().getRuleDataList().forEach(shenyuCacheRepository::saveOrUpdateRuleData);
-                        shenyuMemoryConfig.getGlobalDefaultBackend().getRight().getMetaDataList().forEach(shenyuCacheRepository::saveOrUpdateMetaData);
-                        globalDefaultBackend = shenyuMemoryConfig.getGlobalDefaultBackend();
-                        IngressSelectorCache.getInstance().put(Objects.requireNonNull(v1Ingress.getMetadata()).getNamespace(),
-                                v1Ingress.getMetadata().getName(), pluginName, shenyuMemoryConfig.getGlobalDefaultBackend().getRight().getSelectorData().getId());
+            }
+        }
+    }
+
+    private void processTlsConfigurations(final ShenyuMemoryConfig shenyuMemoryConfig, final V1Ingress v1Ingress) throws IOException {
+        List<SslCrtAndKeyStream> tlsConfigList = shenyuMemoryConfig.getTlsConfigList();
+
+        if (tlsConfigList != null) {
+            final String namespace = Objects.requireNonNull(v1Ingress.getMetadata()).getNamespace();
+            final String ingressName = v1Ingress.getMetadata().getName();
+            Set<String> oldDomainSet = Optional.ofNullable(IngressSecretCache.getInstance().removeDomainByIngress(namespace, ingressName)).orElse(new HashSet<>());
+            Set<String> newDomainSet = new HashSet<>();
+
+            for (SslCrtAndKeyStream sslCrtAndKeyStream : tlsConfigList) {
+                final String domain = sslCrtAndKeyStream.getDomain();
+                if (!oldDomainSet.contains(domain)) {
+                    if (IngressSecretCache.getInstance().getAndIncrementDomainNums(domain) == 0) {
+                        shenyuSniAsyncMapping.addSslCertificate(sslCrtAndKeyStream);
+                        LOG.info("Add ssl config for domain {}", domain);
                     }
                 }
+                newDomainSet.add(domain);
             }
-            List<SslCrtAndKeyStream> tlsConfigList = shenyuMemoryConfig.getTlsConfigList();
-            if (Objects.nonNull(tlsConfigList)) {
-                final String namespace = Objects.requireNonNull(v1Ingress.getMetadata()).getNamespace();
-                final String ingressName = v1Ingress.getMetadata().getName();
-                Set<String> oldDomainSet = Optional.ofNullable(IngressSecretCache.getInstance().removeDomainByIngress(namespace, ingressName)).orElse(new HashSet<>());
-                Set<String> newDomainSet = new HashSet<>();
-                for (SslCrtAndKeyStream sslCrtAndKeyStream : tlsConfigList) {
-                    final String domain = sslCrtAndKeyStream.getDomain();
-                    if (!oldDomainSet.contains(domain)) {
-                        if (IngressSecretCache.getInstance().getAndIncrementDomainNums(domain) == 0) {
-                            shenyuSniAsyncMapping.addSslCertificate(sslCrtAndKeyStream);
-                            LOG.info("Add ssl config for domain {}", domain);
-                        }
-                    }
-                    newDomainSet.add(domain);
+
+            oldDomainSet.removeAll(newDomainSet);
+
+            for (String domain : oldDomainSet) {
+                if (IngressSecretCache.getInstance().getAndDecrementDomainNums(domain) == 1) {
+                    shenyuSniAsyncMapping.removeSslCertificate(domain);
+                    LOG.info("Remove ssl config for domain {}", domain);
                 }
-                oldDomainSet.removeAll(newDomainSet);
-                oldDomainSet.forEach(domain -> {
-                    if (IngressSecretCache.getInstance().getAndDecrementDomainNums(domain) == 1) {
-                        shenyuSniAsyncMapping.removeSslCertificate(domain);
-                        LOG.info("Remove ssl config for domain {}", domain);
-                    }
-                });
-                IngressSecretCache.getInstance().putDomainByIngress(namespace, ingressName, newDomainSet);
             }
+
+            IngressSecretCache.getInstance().putDomainByIngress(namespace, ingressName, newDomainSet);
         }
     }