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

alinsran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


The following commit(s) were added to refs/heads/master by this push:
     new 95787e6e chore: refactor provider (#2507)
95787e6e is described below

commit 95787e6e68309f136cda80b546e4cbe8b5bccffc
Author: AlinsRan <alins...@apache.org>
AuthorDate: Tue Aug 19 08:29:57 2025 +0800

    chore: refactor provider (#2507)
---
 .github/workflows/apisix-conformance-test.yml      |   2 +-
 api/adc/types.go                                   |  21 +
 internal/{provider => }/adc/cache/cache.go         |   0
 internal/{provider => }/adc/cache/indexer.go       |   0
 internal/{provider => }/adc/cache/memdb.go         |   0
 internal/{provider => }/adc/cache/noop_db.go       |   0
 internal/{provider => }/adc/cache/schema.go        |   0
 internal/{provider/adc => adc/cache}/store.go      |  15 +-
 internal/adc/client/client.go                      | 317 +++++++++++++
 internal/{provider/adc => adc/client}/executor.go  |  12 +-
 internal/{provider => }/adc/options.go             |   0
 .../adc/translator/apisixconsumer.go               |   0
 .../{provider => }/adc/translator/apisixroute.go   |   0
 .../{provider => }/adc/translator/apisixtls.go     |   0
 .../adc/translator/apisixupstream.go               |   0
 internal/{provider => }/adc/translator/consumer.go |   0
 internal/{provider => }/adc/translator/gateway.go  |   0
 .../config.go => adc/translator/gatewayproxy.go}   | 124 +-----
 .../{provider => }/adc/translator/globalrule.go    |   0
 .../{provider => }/adc/translator/httproute.go     |   0
 internal/{provider => }/adc/translator/ingress.go  |   0
 .../{provider => }/adc/translator/ingressclass.go  |   0
 internal/{provider => }/adc/translator/policies.go |   0
 .../{provider => }/adc/translator/translator.go    |   7 +
 internal/manager/run.go                            |   7 +-
 internal/provider/adc/adc.go                       | 490 ---------------------
 internal/provider/apisix/provider.go               | 297 +++++++++++++
 internal/provider/{adc => apisix}/status.go        |  23 +-
 internal/provider/common/configmanager.go          | 170 +++++++
 .../{adc/translator/translator.go => init/init.go} |  26 +-
 internal/provider/{adc => }/options.go             |  34 +-
 internal/provider/provider.go                      |   1 -
 internal/provider/register.go                      |  49 +++
 internal/types/types.go                            |  29 +-
 test/e2e/crds/v1alpha1/gatewayproxy.go             |   3 +-
 test/e2e/framework/apisix_consts.go                |   5 +
 .../e2e/framework/manifests/apisix-standalone.yaml |   4 +-
 test/e2e/framework/manifests/apisix.yaml           |   4 +-
 test/e2e/scaffold/adc.go                           |   2 +-
 test/e2e/scaffold/apisix_deployer.go               |   3 +-
 40 files changed, 991 insertions(+), 654 deletions(-)

diff --git a/.github/workflows/apisix-conformance-test.yml 
b/.github/workflows/apisix-conformance-test.yml
index 8549fb19..d800252c 100644
--- a/.github/workflows/apisix-conformance-test.yml
+++ b/.github/workflows/apisix-conformance-test.yml
@@ -89,7 +89,7 @@ jobs:
 
       - name: Install And Run Cloud Provider KIND
         run: |
-          go install sigs.k8s.io/cloud-provider-kind@latest
+          go install sigs.k8s.io/cloud-provider-kind@v0.6.0
           nohup cloud-provider-kind > /tmp/kind-loadbalancer.log 2>&1 &
   
       - name: Install Gateway API And CRDs
diff --git a/api/adc/types.go b/api/adc/types.go
index d561abf8..2f6a020d 100644
--- a/api/adc/types.go
+++ b/api/adc/types.go
@@ -726,3 +726,24 @@ func (s *StringOrSlice) UnmarshalJSON(p []byte) error {
        }
        return json.Unmarshal(p, &s.StrVal)
 }
+
+type Config struct {
+       Name        string
+       ServerAddrs []string
+       Token       string
+       TlsVerify   bool
+}
+
+// MarshalJSON implements custom JSON marshaling for adcConfig
+// It excludes the Token field for security reasons
+func (c Config) MarshalJSON() ([]byte, error) {
+       return json.Marshal(struct {
+               Name        string   `json:"name"`
+               ServerAddrs []string `json:"serverAddrs"`
+               TlsVerify   bool     `json:"tlsVerify"`
+       }{
+               Name:        c.Name,
+               ServerAddrs: c.ServerAddrs,
+               TlsVerify:   c.TlsVerify,
+       })
+}
diff --git a/internal/provider/adc/cache/cache.go b/internal/adc/cache/cache.go
similarity index 100%
rename from internal/provider/adc/cache/cache.go
rename to internal/adc/cache/cache.go
diff --git a/internal/provider/adc/cache/indexer.go 
b/internal/adc/cache/indexer.go
similarity index 100%
rename from internal/provider/adc/cache/indexer.go
rename to internal/adc/cache/indexer.go
diff --git a/internal/provider/adc/cache/memdb.go b/internal/adc/cache/memdb.go
similarity index 100%
rename from internal/provider/adc/cache/memdb.go
rename to internal/adc/cache/memdb.go
diff --git a/internal/provider/adc/cache/noop_db.go 
b/internal/adc/cache/noop_db.go
similarity index 100%
rename from internal/provider/adc/cache/noop_db.go
rename to internal/adc/cache/noop_db.go
diff --git a/internal/provider/adc/cache/schema.go 
b/internal/adc/cache/schema.go
similarity index 100%
rename from internal/provider/adc/cache/schema.go
rename to internal/adc/cache/schema.go
diff --git a/internal/provider/adc/store.go b/internal/adc/cache/store.go
similarity index 96%
rename from internal/provider/adc/store.go
rename to internal/adc/cache/store.go
index 458a68a2..70152266 100644
--- a/internal/provider/adc/store.go
+++ b/internal/adc/cache/store.go
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package adc
+package cache
 
 import (
        "fmt"
@@ -27,11 +27,10 @@ import (
 
        adctypes "github.com/apache/apisix-ingress-controller/api/adc"
        "github.com/apache/apisix-ingress-controller/internal/controller/label"
-       
"github.com/apache/apisix-ingress-controller/internal/provider/adc/cache"
 )
 
 type Store struct {
-       cacheMap          map[string]cache.Cache
+       cacheMap          map[string]Cache
        pluginMetadataMap map[string]adctypes.PluginMetadata
 
        sync.Mutex
@@ -39,17 +38,17 @@ type Store struct {
 
 func NewStore() *Store {
        return &Store{
-               cacheMap:          make(map[string]cache.Cache),
+               cacheMap:          make(map[string]Cache),
                pluginMetadataMap: make(map[string]adctypes.PluginMetadata),
        }
 }
 
-func (s *Store) Insert(name string, resourceTypes []string, resources 
adctypes.Resources, Labels map[string]string) error {
+func (s *Store) Insert(name string, resourceTypes []string, resources 
*adctypes.Resources, Labels map[string]string) error {
        s.Lock()
        defer s.Unlock()
        targetCache, ok := s.cacheMap[name]
        if !ok {
-               db, err := cache.NewMemDBCache()
+               db, err := NewMemDBCache()
                if err != nil {
                        return err
                }
@@ -57,7 +56,7 @@ func (s *Store) Insert(name string, resourceTypes []string, 
resources adctypes.R
                targetCache = s.cacheMap[name]
        }
        log.Debugw("Inserting resources into cache for", zap.String("name", 
name))
-       selector := &cache.KindLabelSelector{
+       selector := &KindLabelSelector{
                Kind:      Labels[label.LabelKind],
                Name:      Labels[label.LabelName],
                Namespace: Labels[label.LabelNamespace],
@@ -153,7 +152,7 @@ func (s *Store) Delete(name string, resourceTypes []string, 
Labels map[string]st
        if !ok {
                return nil
        }
-       selector := &cache.KindLabelSelector{
+       selector := &KindLabelSelector{
                Kind:      Labels[label.LabelKind],
                Name:      Labels[label.LabelName],
                Namespace: Labels[label.LabelNamespace],
diff --git a/internal/adc/client/client.go b/internal/adc/client/client.go
new file mode 100644
index 00000000..93beb47f
--- /dev/null
+++ b/internal/adc/client/client.go
@@ -0,0 +1,317 @@
+// 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 client
+
+import (
+       "context"
+       "encoding/json"
+       "fmt"
+       "os"
+       "strings"
+       "sync"
+       "time"
+
+       "github.com/api7/gopkg/pkg/log"
+       "github.com/pkg/errors"
+       "go.uber.org/zap"
+
+       adctypes "github.com/apache/apisix-ingress-controller/api/adc"
+       "github.com/apache/apisix-ingress-controller/internal/adc/cache"
+       "github.com/apache/apisix-ingress-controller/internal/provider/common"
+       "github.com/apache/apisix-ingress-controller/internal/types"
+       pkgmetrics "github.com/apache/apisix-ingress-controller/pkg/metrics"
+)
+
+type Client struct {
+       syncMu sync.RWMutex
+       mu     sync.Mutex
+       *cache.Store
+
+       executor    ADCExecutor
+       BackendMode string
+
+       ConfigManager *common.ConfigManager[types.NamespacedNameKind, 
adctypes.Config]
+}
+
+func New(mode string, timeout time.Duration) (*Client, error) {
+       return &Client{
+               Store:         cache.NewStore(),
+               executor:      &DefaultADCExecutor{},
+               BackendMode:   mode,
+               ConfigManager: 
common.NewConfigManager[types.NamespacedNameKind, adctypes.Config](),
+       }, nil
+}
+
+type Task struct {
+       Key           types.NamespacedNameKind
+       Name          string
+       Labels        map[string]string
+       Configs       map[types.NamespacedNameKind]adctypes.Config
+       ResourceTypes []string
+       Resources     *adctypes.Resources
+}
+
+func (d *Client) Update(ctx context.Context, args Task) error {
+       d.mu.Lock()
+       deleteConfigs := d.ConfigManager.Update(args.Key, args.Configs)
+       for _, config := range deleteConfigs {
+               if err := d.Store.Delete(config.Name, args.ResourceTypes, 
args.Labels); err != nil {
+                       log.Errorw("failed to delete resources from store",
+                               zap.String("name", config.Name),
+                               zap.Error(err),
+                       )
+                       return err
+               }
+       }
+
+       for _, config := range args.Configs {
+               if err := d.Insert(config.Name, args.ResourceTypes, 
args.Resources, args.Labels); err != nil {
+                       log.Errorw("failed to insert resources into store",
+                               zap.String("name", config.Name),
+                               zap.Error(err),
+                       )
+                       return err
+               }
+       }
+       d.mu.Unlock()
+
+       d.syncMu.RLock()
+       defer d.syncMu.RUnlock()
+
+       if len(deleteConfigs) > 0 {
+               err := d.sync(ctx, Task{
+                       Name:          args.Name,
+                       Labels:        args.Labels,
+                       ResourceTypes: args.ResourceTypes,
+                       Configs:       deleteConfigs,
+               })
+               if err != nil {
+                       log.Warnw("failed to sync deleted configs", 
zap.Error(err))
+               }
+       }
+
+       return d.sync(ctx, args)
+}
+
+func (d *Client) UpdateConfig(ctx context.Context, args Task) error {
+       d.mu.Lock()
+       defer d.mu.Unlock()
+       deleteConfigs := d.ConfigManager.Update(args.Key, args.Configs)
+
+       for _, config := range deleteConfigs {
+               if err := d.Store.Delete(config.Name, args.ResourceTypes, 
args.Labels); err != nil {
+                       log.Errorw("failed to delete resources from store",
+                               zap.String("name", config.Name),
+                               zap.Error(err),
+                       )
+                       return err
+               }
+       }
+
+       for _, config := range args.Configs {
+               if err := d.Insert(config.Name, args.ResourceTypes, 
args.Resources, args.Labels); err != nil {
+                       log.Errorw("failed to insert resources into store",
+                               zap.String("name", config.Name),
+                               zap.Error(err),
+                       )
+                       return err
+               }
+       }
+       return nil
+}
+
+func (d *Client) Delete(ctx context.Context, args Task) error {
+       d.mu.Lock()
+       configs := d.ConfigManager.Get(args.Key)
+       d.ConfigManager.Delete(args.Key)
+
+       for _, config := range configs {
+               if err := d.Store.Delete(config.Name, args.ResourceTypes, 
args.Labels); err != nil {
+                       log.Errorw("failed to delete resources from store",
+                               zap.String("name", config.Name),
+                               zap.Error(err),
+                       )
+                       return err
+               }
+       }
+       d.mu.Unlock()
+
+       d.syncMu.RLock()
+       defer d.syncMu.RUnlock()
+
+       return d.sync(ctx, Task{
+               Labels:        args.Labels,
+               ResourceTypes: args.ResourceTypes,
+               Configs:       configs,
+       })
+}
+
+func (d *Client) DeleteConfig(ctx context.Context, args Task) error {
+       d.mu.Lock()
+       defer d.mu.Unlock()
+
+       configs := d.ConfigManager.Get(args.Key)
+       d.ConfigManager.Delete(args.Key)
+
+       for _, config := range configs {
+               if err := d.Store.Delete(config.Name, args.ResourceTypes, 
args.Labels); err != nil {
+                       log.Errorw("failed to delete resources from store",
+                               zap.String("name", config.Name),
+                               zap.Error(err),
+                       )
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func (c *Client) Sync(ctx context.Context) 
(map[string]types.ADCExecutionErrors, error) {
+       c.syncMu.Lock()
+       defer c.syncMu.Unlock()
+       log.Debug("syncing all resources")
+
+       configs := c.ConfigManager.List()
+
+       if len(configs) == 0 {
+               log.Warn("no GatewayProxy configs provided")
+               return nil, nil
+       }
+
+       log.Debugw("syncing resources with multiple configs", 
zap.Any("configs", configs))
+
+       failedMap := map[string]types.ADCExecutionErrors{}
+       var failedConfigs []string
+       for _, config := range configs {
+               name := config.Name
+               resources, err := c.GetResources(name)
+               if err != nil {
+                       log.Errorw("failed to get resources from store", 
zap.String("name", name), zap.Error(err))
+                       failedConfigs = append(failedConfigs, name)
+                       continue
+               }
+               if resources == nil {
+                       continue
+               }
+
+               if err := c.sync(ctx, Task{
+                       Name: name + "-sync",
+                       Configs: map[types.NamespacedNameKind]adctypes.Config{
+                               {}: config,
+                       },
+                       Resources: resources,
+               }); err != nil {
+                       log.Errorw("failed to sync resources", 
zap.String("name", name), zap.Error(err))
+                       failedConfigs = append(failedConfigs, name)
+                       var execErrs types.ADCExecutionErrors
+                       if errors.As(err, &execErrs) {
+                               failedMap[name] = execErrs
+                       }
+               }
+       }
+
+       var err error
+       if len(failedConfigs) > 0 {
+               err = fmt.Errorf("failed to sync %d configs: %s",
+                       len(failedConfigs),
+                       strings.Join(failedConfigs, ", "))
+       }
+       return failedMap, err
+}
+
+func (c *Client) sync(ctx context.Context, task Task) error {
+       log.Debugw("syncing resources", zap.Any("task", task))
+
+       if len(task.Configs) == 0 {
+               log.Warnw("no adc configs provided", zap.Any("task", task))
+               return nil
+       }
+
+       var errs types.ADCExecutionErrors
+
+       // Record file I/O duration
+       fileIOStart := time.Now()
+       // every task resources is the same, so we can use the first config to 
prepare the sync file
+       syncFilePath, cleanup, err := prepareSyncFile(task.Resources)
+       if err != nil {
+               pkgmetrics.RecordFileIODuration("prepare_sync_file", "failure", 
time.Since(fileIOStart).Seconds())
+               return err
+       }
+       pkgmetrics.RecordFileIODuration("prepare_sync_file", "success", 
time.Since(fileIOStart).Seconds())
+       defer cleanup()
+
+       args := BuildADCExecuteArgs(syncFilePath, task.Labels, 
task.ResourceTypes)
+
+       for _, config := range task.Configs {
+               // Record sync duration for each config
+               startTime := time.Now()
+               resourceType := strings.Join(task.ResourceTypes, ",")
+               if resourceType == "" {
+                       resourceType = "all"
+               }
+
+               err := c.executor.Execute(ctx, c.BackendMode, config, args)
+               duration := time.Since(startTime).Seconds()
+
+               status := "success"
+               if err != nil {
+                       status = "failure"
+                       log.Errorw("failed to execute adc command", 
zap.Error(err), zap.Any("config", config))
+
+                       var execErr types.ADCExecutionError
+                       if errors.As(err, &execErr) {
+                               errs.Errors = append(errs.Errors, execErr)
+                               pkgmetrics.RecordExecutionError(config.Name, 
execErr.Name)
+                       } else {
+                               pkgmetrics.RecordExecutionError(config.Name, 
"unknown")
+                       }
+               }
+
+               // Record metrics
+               pkgmetrics.RecordSyncDuration(config.Name, resourceType, 
status, duration)
+       }
+
+       if len(errs.Errors) > 0 {
+               return errs
+       }
+       return nil
+}
+
+func prepareSyncFile(resources any) (string, func(), error) {
+       data, err := json.Marshal(resources)
+       if err != nil {
+               return "", nil, err
+       }
+
+       tmpFile, err := os.CreateTemp("", "adc-task-*.json")
+       if err != nil {
+               return "", nil, err
+       }
+       cleanup := func() {
+               _ = tmpFile.Close()
+               _ = os.Remove(tmpFile.Name())
+       }
+       if _, err := tmpFile.Write(data); err != nil {
+               cleanup()
+               return "", nil, err
+       }
+
+       log.Debugw("generated adc file", zap.String("filename", 
tmpFile.Name()), zap.String("json", string(data)))
+
+       return tmpFile.Name(), cleanup, nil
+}
diff --git a/internal/provider/adc/executor.go b/internal/adc/client/executor.go
similarity index 93%
rename from internal/provider/adc/executor.go
rename to internal/adc/client/executor.go
index 5377018d..56b1b02c 100644
--- a/internal/provider/adc/executor.go
+++ b/internal/adc/client/executor.go
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package adc
+package client
 
 import (
        "bytes"
@@ -37,21 +37,21 @@ import (
 )
 
 type ADCExecutor interface {
-       Execute(ctx context.Context, mode string, config adcConfig, args 
[]string) error
+       Execute(ctx context.Context, mode string, config adctypes.Config, args 
[]string) error
 }
 
 type DefaultADCExecutor struct {
        sync.Mutex
 }
 
-func (e *DefaultADCExecutor) Execute(ctx context.Context, mode string, config 
adcConfig, args []string) error {
+func (e *DefaultADCExecutor) Execute(ctx context.Context, mode string, config 
adctypes.Config, args []string) error {
        e.Lock()
        defer e.Unlock()
 
        return e.runADC(ctx, mode, config, args)
 }
 
-func (e *DefaultADCExecutor) runADC(ctx context.Context, mode string, config 
adcConfig, args []string) error {
+func (e *DefaultADCExecutor) runADC(ctx context.Context, mode string, config 
adctypes.Config, args []string) error {
        var execErrs = types.ADCExecutionError{
                Name: config.Name,
        }
@@ -76,13 +76,13 @@ func (e *DefaultADCExecutor) runADC(ctx context.Context, 
mode string, config adc
        return nil
 }
 
-func (e *DefaultADCExecutor) runForSingleServerWithTimeout(ctx 
context.Context, serverAddr, mode string, config adcConfig, args []string) 
error {
+func (e *DefaultADCExecutor) runForSingleServerWithTimeout(ctx 
context.Context, serverAddr, mode string, config adctypes.Config, args 
[]string) error {
        ctx, cancel := context.WithTimeout(ctx, 15*time.Second)
        defer cancel()
        return e.runForSingleServer(ctx, serverAddr, mode, config, args)
 }
 
-func (e *DefaultADCExecutor) runForSingleServer(ctx context.Context, 
serverAddr, mode string, config adcConfig, args []string) error {
+func (e *DefaultADCExecutor) runForSingleServer(ctx context.Context, 
serverAddr, mode string, config adctypes.Config, args []string) error {
        cmdArgs := append([]string{}, args...)
        if !config.TlsVerify {
                cmdArgs = append(cmdArgs, "--tls-skip-verify")
diff --git a/internal/provider/adc/options.go b/internal/adc/options.go
similarity index 100%
copy from internal/provider/adc/options.go
copy to internal/adc/options.go
diff --git a/internal/provider/adc/translator/apisixconsumer.go 
b/internal/adc/translator/apisixconsumer.go
similarity index 100%
rename from internal/provider/adc/translator/apisixconsumer.go
rename to internal/adc/translator/apisixconsumer.go
diff --git a/internal/provider/adc/translator/apisixroute.go 
b/internal/adc/translator/apisixroute.go
similarity index 100%
rename from internal/provider/adc/translator/apisixroute.go
rename to internal/adc/translator/apisixroute.go
diff --git a/internal/provider/adc/translator/apisixtls.go 
b/internal/adc/translator/apisixtls.go
similarity index 100%
rename from internal/provider/adc/translator/apisixtls.go
rename to internal/adc/translator/apisixtls.go
diff --git a/internal/provider/adc/translator/apisixupstream.go 
b/internal/adc/translator/apisixupstream.go
similarity index 100%
rename from internal/provider/adc/translator/apisixupstream.go
rename to internal/adc/translator/apisixupstream.go
diff --git a/internal/provider/adc/translator/consumer.go 
b/internal/adc/translator/consumer.go
similarity index 100%
rename from internal/provider/adc/translator/consumer.go
rename to internal/adc/translator/consumer.go
diff --git a/internal/provider/adc/translator/gateway.go 
b/internal/adc/translator/gateway.go
similarity index 100%
rename from internal/provider/adc/translator/gateway.go
rename to internal/adc/translator/gateway.go
diff --git a/internal/provider/adc/config.go 
b/internal/adc/translator/gatewayproxy.go
similarity index 55%
rename from internal/provider/adc/config.go
rename to internal/adc/translator/gatewayproxy.go
index 20bc3f64..8b7fb673 100644
--- a/internal/provider/adc/config.go
+++ b/internal/adc/translator/gatewayproxy.go
@@ -6,7 +6,7 @@
 // "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
+//     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
@@ -15,29 +15,29 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package adc
+package translator
 
 import (
-       "errors"
        "fmt"
        "net"
-       "slices"
        "strconv"
 
        "github.com/api7/gopkg/pkg/log"
+       "github.com/pkg/errors"
        "go.uber.org/zap"
+       corev1 "k8s.io/api/core/v1"
        discoveryv1 "k8s.io/api/discovery/v1"
        k8stypes "k8s.io/apimachinery/pkg/types"
        "k8s.io/utils/ptr"
        gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
 
+       types "github.com/apache/apisix-ingress-controller/api/adc"
        "github.com/apache/apisix-ingress-controller/api/v1alpha1"
        "github.com/apache/apisix-ingress-controller/internal/provider"
-       "github.com/apache/apisix-ingress-controller/internal/types"
        "github.com/apache/apisix-ingress-controller/internal/utils"
 )
 
-func (d *adcClient) getConfigsForGatewayProxy(tctx *provider.TranslateContext, 
gatewayProxy *v1alpha1.GatewayProxy) (*adcConfig, error) {
+func (t *Translator) TranslateGatewayProxyToConfig(tctx 
*provider.TranslateContext, gatewayProxy *v1alpha1.GatewayProxy, 
resolveEndpoints bool) (*types.Config, error) {
        if gatewayProxy == nil || gatewayProxy.Spec.Provider == nil {
                return nil, nil
        }
@@ -47,8 +47,8 @@ func (d *adcClient) getConfigsForGatewayProxy(tctx 
*provider.TranslateContext, g
                return nil, nil
        }
 
-       config := adcConfig{
-               Name: k8stypes.NamespacedName{Namespace: 
gatewayProxy.Namespace, Name: gatewayProxy.Name}.String(),
+       config := types.Config{
+               Name: utils.NamespacedNameKind(gatewayProxy).String(),
        }
 
        if provider.ControlPlane.TlsVerify != nil {
@@ -88,19 +88,19 @@ func (d *adcClient) getConfigsForGatewayProxy(tctx 
*provider.TranslateContext, g
                        Namespace: gatewayProxy.Namespace,
                        Name:      provider.ControlPlane.Service.Name,
                }
-               _, ok := tctx.Services[namespacedName]
+               svc, ok := tctx.Services[namespacedName]
                if !ok {
                        return nil, fmt.Errorf("no service found for service 
reference: %s", namespacedName)
                }
 
                // APISIXStandalone, configurations need to be sent to each 
data plane instance;
                // In other cases, the service is directly accessed as the adc 
backend server address.
-               if d.BackendMode == BackendModeAPISIXStandalone {
+               if resolveEndpoints {
                        endpoint := tctx.EndpointSlices[namespacedName]
                        if endpoint == nil {
                                return nil, nil
                        }
-                       upstreamNodes, err := 
d.translator.TranslateBackendRefWithFilter(tctx, gatewayv1.BackendRef{
+                       upstreamNodes, err := 
t.TranslateBackendRefWithFilter(tctx, gatewayv1.BackendRef{
                                BackendObjectReference: 
gatewayv1.BackendObjectReference{
                                        Name:      
gatewayv1.ObjectName(provider.ControlPlane.Service.Name),
                                        Namespace: 
(*gatewayv1.Namespace)(&gatewayProxy.Namespace),
@@ -120,9 +120,14 @@ func (d *adcClient) getConfigsForGatewayProxy(tctx 
*provider.TranslateContext, g
                                config.ServerAddrs = append(config.ServerAddrs, 
"http://"+net.JoinHostPort(node.Host, strconv.Itoa(node.Port)))
                        }
                } else {
-                       config.ServerAddrs = []string{
-                               fmt.Sprintf("http://%s.%s:%d";, 
provider.ControlPlane.Service.Name, gatewayProxy.Namespace, 
provider.ControlPlane.Service.Port),
+                       refPort := provider.ControlPlane.Service.Port
+                       var serverAddr string
+                       if svc.Spec.Type == corev1.ServiceTypeExternalName {
+                               serverAddr = fmt.Sprintf("http://%s:%d";, 
svc.Spec.ExternalName, refPort)
+                       } else {
+                               serverAddr = fmt.Sprintf("http://%s.%s.svc:%d";, 
provider.ControlPlane.Service.Name, gatewayProxy.Namespace, refPort)
                        }
+                       config.ServerAddrs = []string{serverAddr}
                }
 
                log.Debugw("add server address to config.ServiceAddrs", 
zap.Strings("config.ServerAddrs", config.ServerAddrs))
@@ -130,96 +135,3 @@ func (d *adcClient) getConfigsForGatewayProxy(tctx 
*provider.TranslateContext, g
 
        return &config, nil
 }
-
-func (d *adcClient) deleteConfigs(rk types.NamespacedNameKind) {
-       d.Lock()
-       defer d.Unlock()
-       delete(d.configs, rk)
-       delete(d.parentRefs, rk)
-}
-
-func (d *adcClient) getParentRefs(rk types.NamespacedNameKind) 
[]types.NamespacedNameKind {
-       d.Lock()
-       defer d.Unlock()
-       return d.parentRefs[rk]
-}
-
-func (d *adcClient) getConfigs(rk types.NamespacedNameKind) []adcConfig {
-       d.Lock()
-       defer d.Unlock()
-       parentRefs := d.parentRefs[rk]
-       configs := make([]adcConfig, 0, len(parentRefs))
-       for _, parentRef := range parentRefs {
-               if config, ok := d.configs[parentRef]; ok {
-                       configs = append(configs, config)
-               }
-       }
-       return configs
-}
-
-func (d *adcClient) updateConfigs(rk types.NamespacedNameKind, tctx 
*provider.TranslateContext) error {
-       d.Lock()
-       defer d.Unlock()
-
-       // set parent refs
-       d.parentRefs[rk] = tctx.ResourceParentRefs[rk]
-       parentRefs := d.parentRefs[rk]
-
-       for _, parentRef := range parentRefs {
-               gatewayProxy, ok := tctx.GatewayProxies[parentRef]
-               if !ok {
-                       log.Debugw("no gateway proxy found for parent ref", 
zap.Any("parentRef", parentRef))
-                       continue
-               }
-               config, err := d.getConfigsForGatewayProxy(tctx, &gatewayProxy)
-               if err != nil {
-                       return err
-               }
-               if config == nil {
-                       log.Debugw("no config found for gateway proxy", 
zap.Any("parentRef", parentRef))
-                       continue
-               }
-               d.configs[parentRef] = *config
-       }
-
-       return nil
-}
-
-// updateConfigForGatewayProxy update config for all referrers of the 
GatewayProxy
-func (d *adcClient) updateConfigForGatewayProxy(tctx 
*provider.TranslateContext, gp *v1alpha1.GatewayProxy) error {
-       d.Lock()
-       defer d.Unlock()
-
-       config, err := d.getConfigsForGatewayProxy(tctx, gp)
-       if err != nil {
-               return err
-       }
-
-       referrers := tctx.GatewayProxyReferrers[utils.NamespacedName(gp)]
-
-       if config == nil {
-               for _, ref := range referrers {
-                       delete(d.configs, ref)
-               }
-               return nil
-       }
-
-       for _, ref := range referrers {
-               d.configs[ref] = *config
-       }
-
-       d.syncNotify()
-       return nil
-}
-
-func (d *adcClient) findConfigsToDelete(oldParentRefs, newParentRefs 
[]types.NamespacedNameKind) []adcConfig {
-       var deleteConfigs []adcConfig
-       for _, parentRef := range oldParentRefs {
-               if !slices.ContainsFunc(newParentRefs, func(rk 
types.NamespacedNameKind) bool {
-                       return rk.Kind == parentRef.Kind && rk.Namespace == 
parentRef.Namespace && rk.Name == parentRef.Name
-               }) {
-                       deleteConfigs = append(deleteConfigs, 
d.configs[parentRef])
-               }
-       }
-       return deleteConfigs
-}
diff --git a/internal/provider/adc/translator/globalrule.go 
b/internal/adc/translator/globalrule.go
similarity index 100%
rename from internal/provider/adc/translator/globalrule.go
rename to internal/adc/translator/globalrule.go
diff --git a/internal/provider/adc/translator/httproute.go 
b/internal/adc/translator/httproute.go
similarity index 100%
rename from internal/provider/adc/translator/httproute.go
rename to internal/adc/translator/httproute.go
diff --git a/internal/provider/adc/translator/ingress.go 
b/internal/adc/translator/ingress.go
similarity index 100%
rename from internal/provider/adc/translator/ingress.go
rename to internal/adc/translator/ingress.go
diff --git a/internal/provider/adc/translator/ingressclass.go 
b/internal/adc/translator/ingressclass.go
similarity index 100%
rename from internal/provider/adc/translator/ingressclass.go
rename to internal/adc/translator/ingressclass.go
diff --git a/internal/provider/adc/translator/policies.go 
b/internal/adc/translator/policies.go
similarity index 100%
rename from internal/provider/adc/translator/policies.go
rename to internal/adc/translator/policies.go
diff --git a/internal/provider/adc/translator/translator.go 
b/internal/adc/translator/translator.go
similarity index 93%
copy from internal/provider/adc/translator/translator.go
copy to internal/adc/translator/translator.go
index 67ab7596..0d50661a 100644
--- a/internal/provider/adc/translator/translator.go
+++ b/internal/adc/translator/translator.go
@@ -26,6 +26,13 @@ import (
 type Translator struct {
        Log logr.Logger
 }
+
+func NewTranslator(log logr.Logger) *Translator {
+       return &Translator{
+               Log: log,
+       }
+}
+
 type TranslateResult struct {
        Routes         []*adctypes.Route
        Services       []*adctypes.Service
diff --git a/internal/manager/run.go b/internal/manager/run.go
index b75b383d..c08ccaba 100644
--- a/internal/manager/run.go
+++ b/internal/manager/run.go
@@ -42,7 +42,8 @@ import (
        "github.com/apache/apisix-ingress-controller/internal/controller/config"
        "github.com/apache/apisix-ingress-controller/internal/controller/status"
        "github.com/apache/apisix-ingress-controller/internal/manager/readiness"
-       "github.com/apache/apisix-ingress-controller/internal/provider/adc"
+       "github.com/apache/apisix-ingress-controller/internal/provider"
+       _ "github.com/apache/apisix-ingress-controller/internal/provider/init"
        _ "github.com/apache/apisix-ingress-controller/pkg/metrics"
 )
 
@@ -164,7 +165,9 @@ func Run(ctx context.Context, logger logr.Logger) error {
                return err
        }
 
-       provider, err := adc.New(updater.Writer(), readier, &adc.Options{
+       providerType := string(config.ControllerConfig.ProviderConfig.Type)
+
+       provider, err := provider.New(providerType, updater.Writer(), readier, 
&provider.Options{
                SyncTimeout:   config.ControllerConfig.ExecADCTimeout.Duration,
                SyncPeriod:    
config.ControllerConfig.ProviderConfig.SyncPeriod.Duration,
                InitSyncDelay: 
config.ControllerConfig.ProviderConfig.InitSyncDelay.Duration,
diff --git a/internal/provider/adc/adc.go b/internal/provider/adc/adc.go
deleted file mode 100644
index 5ff00761..00000000
--- a/internal/provider/adc/adc.go
+++ /dev/null
@@ -1,490 +0,0 @@
-// 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 adc
-
-import (
-       "context"
-       "encoding/json"
-       "fmt"
-       "os"
-       "strings"
-       "sync"
-       "time"
-
-       "github.com/api7/gopkg/pkg/log"
-       "github.com/pkg/errors"
-       "go.uber.org/zap"
-       networkingv1 "k8s.io/api/networking/v1"
-       "sigs.k8s.io/controller-runtime/pkg/client"
-       gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
-
-       adctypes "github.com/apache/apisix-ingress-controller/api/adc"
-       "github.com/apache/apisix-ingress-controller/api/v1alpha1"
-       apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
-       "github.com/apache/apisix-ingress-controller/internal/controller/label"
-       "github.com/apache/apisix-ingress-controller/internal/controller/status"
-       "github.com/apache/apisix-ingress-controller/internal/manager/readiness"
-       "github.com/apache/apisix-ingress-controller/internal/provider"
-       
"github.com/apache/apisix-ingress-controller/internal/provider/adc/translator"
-       "github.com/apache/apisix-ingress-controller/internal/types"
-       "github.com/apache/apisix-ingress-controller/internal/utils"
-       pkgmetrics "github.com/apache/apisix-ingress-controller/pkg/metrics"
-)
-
-type adcConfig struct {
-       Name        string
-       ServerAddrs []string
-       Token       string
-       TlsVerify   bool
-}
-
-// MarshalJSON implements custom JSON marshaling for adcConfig
-// It excludes the Token field for security reasons
-func (c adcConfig) MarshalJSON() ([]byte, error) {
-       return json.Marshal(struct {
-               Name        string   `json:"name"`
-               ServerAddrs []string `json:"serverAddrs"`
-               TlsVerify   bool     `json:"tlsVerify"`
-       }{
-               Name:        c.Name,
-               ServerAddrs: c.ServerAddrs,
-               TlsVerify:   c.TlsVerify,
-       })
-}
-
-type BackendMode string
-
-const (
-       BackendModeAPISIXStandalone string = "apisix-standalone"
-       BackendModeAPISIX           string = "apisix"
-)
-
-type adcClient struct {
-       sync.Mutex
-
-       syncLock sync.Mutex
-
-       translator *translator.Translator
-       // gateway/ingressclass -> adcConfig
-       configs map[types.NamespacedNameKind]adcConfig
-       // httproute/consumer/ingress/gateway -> gateway/ingressclass
-       parentRefs map[types.NamespacedNameKind][]types.NamespacedNameKind
-
-       store *Store
-
-       executor ADCExecutor
-
-       Options
-
-       updater         status.Updater
-       statusUpdateMap map[types.NamespacedNameKind][]string
-
-       readier readiness.ReadinessManager
-
-       syncCh chan struct{}
-}
-
-type Task struct {
-       Name          string
-       Resources     adctypes.Resources
-       Labels        map[string]string
-       ResourceTypes []string
-       configs       []adcConfig
-}
-
-func New(updater status.Updater, readier readiness.ReadinessManager, opts 
...Option) (provider.Provider, error) {
-       o := Options{}
-       o.ApplyOptions(opts)
-
-       return &adcClient{
-               Options:    o,
-               translator: &translator.Translator{},
-               configs:    make(map[types.NamespacedNameKind]adcConfig),
-               parentRefs: 
make(map[types.NamespacedNameKind][]types.NamespacedNameKind),
-               store:      NewStore(),
-               executor:   &DefaultADCExecutor{},
-               updater:    updater,
-               readier:    readier,
-               syncCh:     make(chan struct{}, 1),
-       }, nil
-}
-
-func (d *adcClient) Update(ctx context.Context, tctx 
*provider.TranslateContext, obj client.Object) error {
-       log.Debugw("updating object", zap.Any("object", obj))
-       var (
-               result        *translator.TranslateResult
-               resourceTypes []string
-               err           error
-       )
-
-       rk := utils.NamespacedNameKind(obj)
-
-       switch t := obj.(type) {
-       case *gatewayv1.HTTPRoute:
-               result, err = d.translator.TranslateHTTPRoute(tctx, 
t.DeepCopy())
-               resourceTypes = append(resourceTypes, "service")
-       case *gatewayv1.Gateway:
-               result, err = d.translator.TranslateGateway(tctx, t.DeepCopy())
-               resourceTypes = append(resourceTypes, "global_rule", "ssl", 
"plugin_metadata")
-       case *networkingv1.Ingress:
-               result, err = d.translator.TranslateIngress(tctx, t.DeepCopy())
-               resourceTypes = append(resourceTypes, "service", "ssl")
-       case *v1alpha1.Consumer:
-               result, err = d.translator.TranslateConsumerV1alpha1(tctx, 
t.DeepCopy())
-               resourceTypes = append(resourceTypes, "consumer")
-       case *networkingv1.IngressClass:
-               result, err = d.translator.TranslateIngressClass(tctx, 
t.DeepCopy())
-               resourceTypes = append(resourceTypes, "global_rule", 
"plugin_metadata")
-       case *apiv2.ApisixRoute:
-               result, err = d.translator.TranslateApisixRoute(tctx, 
t.DeepCopy())
-               resourceTypes = append(resourceTypes, "service")
-       case *apiv2.ApisixGlobalRule:
-               result, err = d.translator.TranslateApisixGlobalRule(tctx, 
t.DeepCopy())
-               resourceTypes = append(resourceTypes, "global_rule")
-       case *apiv2.ApisixTls:
-               result, err = d.translator.TranslateApisixTls(tctx, 
t.DeepCopy())
-               resourceTypes = append(resourceTypes, "ssl")
-       case *apiv2.ApisixConsumer:
-               result, err = d.translator.TranslateApisixConsumer(tctx, 
t.DeepCopy())
-               resourceTypes = append(resourceTypes, "consumer")
-       case *v1alpha1.GatewayProxy:
-               return d.updateConfigForGatewayProxy(tctx, t)
-       }
-       if err != nil {
-               return err
-       }
-       if result == nil {
-               return nil
-       }
-
-       oldParentRefs := d.getParentRefs(rk)
-       if err := d.updateConfigs(rk, tctx); err != nil {
-               return err
-       }
-       newParentRefs := d.getParentRefs(rk)
-       deleteConfigs := d.findConfigsToDelete(oldParentRefs, newParentRefs)
-       configs := d.getConfigs(rk)
-
-       // sync delete
-       if len(deleteConfigs) > 0 {
-               err = d.sync(ctx, Task{
-                       Name:          obj.GetName(),
-                       Labels:        label.GenLabel(obj),
-                       ResourceTypes: resourceTypes,
-                       configs:       deleteConfigs,
-               })
-               if err != nil {
-                       return err
-               }
-               for _, config := range deleteConfigs {
-                       if err := d.store.Delete(config.Name, resourceTypes, 
label.GenLabel(obj)); err != nil {
-                               log.Errorw("failed to delete resources from 
store",
-                                       zap.String("name", config.Name),
-                                       zap.Error(err),
-                               )
-                               return err
-                       }
-               }
-       }
-
-       resources := adctypes.Resources{
-               GlobalRules:    result.GlobalRules,
-               PluginMetadata: result.PluginMetadata,
-               Services:       result.Services,
-               SSLs:           result.SSL,
-               Consumers:      result.Consumers,
-       }
-       log.Debugw("update resources", zap.Any("resources", resources))
-
-       for _, config := range configs {
-               if err := d.store.Insert(config.Name, resourceTypes, resources, 
label.GenLabel(obj)); err != nil {
-                       log.Errorw("failed to insert resources into store",
-                               zap.String("name", config.Name),
-                               zap.Error(err),
-                       )
-                       return err
-               }
-       }
-
-       // This mode is full synchronization,
-       // which only needs to be saved in cache
-       // and triggered by a timer for synchronization
-       if d.BackendMode == BackendModeAPISIXStandalone || d.BackendMode == 
BackendModeAPISIX {
-               d.syncNotify()
-               return nil
-       }
-
-       return d.sync(ctx, Task{
-               Name:          obj.GetName(),
-               Labels:        label.GenLabel(obj),
-               Resources:     resources,
-               ResourceTypes: resourceTypes,
-               configs:       configs,
-       })
-}
-
-func (d *adcClient) Delete(ctx context.Context, obj client.Object) error {
-       log.Debugw("deleting object", zap.Any("object", obj))
-
-       var resourceTypes []string
-       var labels map[string]string
-       switch obj.(type) {
-       case *gatewayv1.HTTPRoute, *apiv2.ApisixRoute:
-               resourceTypes = append(resourceTypes, "service")
-               labels = label.GenLabel(obj)
-       case *gatewayv1.Gateway:
-               // delete all resources
-       case *networkingv1.Ingress:
-               resourceTypes = append(resourceTypes, "service", "ssl")
-               labels = label.GenLabel(obj)
-       case *v1alpha1.Consumer:
-               resourceTypes = append(resourceTypes, "consumer")
-               labels = label.GenLabel(obj)
-       case *networkingv1.IngressClass:
-               // delete all resources
-       case *apiv2.ApisixGlobalRule:
-               resourceTypes = append(resourceTypes, "global_rule")
-               labels = label.GenLabel(obj)
-       case *apiv2.ApisixTls:
-               resourceTypes = append(resourceTypes, "ssl")
-               labels = label.GenLabel(obj)
-       case *apiv2.ApisixConsumer:
-               resourceTypes = append(resourceTypes, "consumer")
-               labels = label.GenLabel(obj)
-       }
-
-       rk := utils.NamespacedNameKind(obj)
-
-       configs := d.getConfigs(rk)
-       defer d.deleteConfigs(rk)
-
-       for _, config := range configs {
-               if err := d.store.Delete(config.Name, resourceTypes, labels); 
err != nil {
-                       log.Errorw("failed to delete resources from store",
-                               zap.String("name", config.Name),
-                               zap.Error(err),
-                       )
-                       return err
-               }
-       }
-
-       log.Debugw("successfully deleted resources from store", 
zap.Any("object", obj))
-
-       switch d.BackendMode {
-       case BackendModeAPISIXStandalone, BackendModeAPISIX:
-               // Full synchronization is performed on a gateway by gateway 
basis
-               // and it is not possible to perform scheduled synchronization
-               // on deleted gateway level resources
-               if len(resourceTypes) == 0 {
-                       return d.sync(ctx, Task{
-                               Name:    obj.GetName(),
-                               configs: configs,
-                       })
-               } else {
-                       d.syncNotify()
-               }
-               return nil
-       default:
-               log.Errorw("unknown backend mode", zap.String("mode", 
d.BackendMode))
-               return errors.New("unknown backend mode: " + d.BackendMode)
-       }
-}
-
-func (d *adcClient) Start(ctx context.Context) error {
-       d.readier.WaitReady(ctx, 5*time.Minute)
-
-       initalSyncDelay := d.InitSyncDelay
-       if initalSyncDelay > 0 {
-               time.AfterFunc(initalSyncDelay, func() {
-                       if err := d.Sync(ctx); err != nil {
-                               log.Error(err)
-                               return
-                       }
-               })
-       }
-
-       if d.SyncPeriod < 1 {
-               return nil
-       }
-       ticker := time.NewTicker(d.SyncPeriod)
-       defer ticker.Stop()
-       for {
-               synced := false
-               select {
-               case <-d.syncCh:
-                       synced = true
-               case <-ticker.C:
-                       synced = true
-               case <-ctx.Done():
-                       return nil
-               }
-               if synced {
-                       if err := d.Sync(ctx); err != nil {
-                               log.Error(err)
-                       }
-               }
-       }
-}
-
-func (d *adcClient) Sync(ctx context.Context) error {
-       d.syncLock.Lock()
-       defer d.syncLock.Unlock()
-
-       log.Debug("syncing all resources")
-
-       if len(d.configs) == 0 {
-               return nil
-       }
-
-       cfg := map[string]adcConfig{}
-       for _, config := range d.configs {
-               cfg[config.Name] = config
-       }
-
-       log.Debugw("syncing resources with multiple configs", 
zap.Any("configs", cfg))
-
-       failedMap := map[string]types.ADCExecutionErrors{}
-       var failedConfigs []string
-       for name, config := range cfg {
-               resources, err := d.store.GetResources(name)
-               if err != nil {
-                       log.Errorw("failed to get resources from store", 
zap.String("name", name), zap.Error(err))
-                       failedConfigs = append(failedConfigs, name)
-                       continue
-               }
-               if resources == nil {
-                       continue
-               }
-
-               if err := d.sync(ctx, Task{
-                       Name:      name + "-sync",
-                       configs:   []adcConfig{config},
-                       Resources: *resources,
-               }); err != nil {
-                       log.Errorw("failed to sync resources", 
zap.String("name", name), zap.Error(err))
-                       failedConfigs = append(failedConfigs, name)
-                       var execErrs types.ADCExecutionErrors
-                       if errors.As(err, &execErrs) {
-                               failedMap[name] = execErrs
-                       }
-               }
-       }
-       d.handleADCExecutionErrors(failedMap)
-       if len(failedConfigs) > 0 {
-               return fmt.Errorf("failed to sync %d configs: %s",
-                       len(failedConfigs),
-                       strings.Join(failedConfigs, ", "))
-       }
-       return nil
-}
-
-func (d *adcClient) sync(ctx context.Context, task Task) error {
-       log.Debugw("syncing resources", zap.Any("task", task))
-
-       if len(task.configs) == 0 {
-               log.Warnw("no adc configs provided", zap.Any("task", task))
-               return nil
-       }
-
-       // Record file I/O duration
-       fileIOStart := time.Now()
-       syncFilePath, cleanup, err := prepareSyncFile(task.Resources)
-       if err != nil {
-               pkgmetrics.RecordFileIODuration("prepare_sync_file", "failure", 
time.Since(fileIOStart).Seconds())
-               return err
-       }
-       pkgmetrics.RecordFileIODuration("prepare_sync_file", "success", 
time.Since(fileIOStart).Seconds())
-       defer cleanup()
-
-       args := BuildADCExecuteArgs(syncFilePath, task.Labels, 
task.ResourceTypes)
-
-       var errs types.ADCExecutionErrors
-       for _, config := range task.configs {
-               // Record sync duration for each config
-               startTime := time.Now()
-               resourceType := strings.Join(task.ResourceTypes, ",")
-               if resourceType == "" {
-                       resourceType = "all"
-               }
-
-               err := d.executor.Execute(ctx, d.BackendMode, config, args)
-               duration := time.Since(startTime).Seconds()
-
-               status := "success"
-               if err != nil {
-                       status = "failure"
-                       log.Errorw("failed to execute adc command", 
zap.Error(err), zap.Any("config", config))
-
-                       var execErr types.ADCExecutionError
-                       if errors.As(err, &execErr) {
-                               errs.Errors = append(errs.Errors, execErr)
-                               pkgmetrics.RecordExecutionError(config.Name, 
execErr.Name)
-                       } else {
-                               pkgmetrics.RecordExecutionError(config.Name, 
"unknown")
-                       }
-               }
-
-               // Record metrics
-               pkgmetrics.RecordSyncDuration(config.Name, resourceType, 
status, duration)
-       }
-
-       if len(errs.Errors) > 0 {
-               return errs
-       }
-       return nil
-}
-
-func (d *adcClient) syncNotify() {
-       select {
-       case d.syncCh <- struct{}{}:
-       default:
-       }
-}
-
-func prepareSyncFile(resources any) (string, func(), error) {
-       data, err := json.Marshal(resources)
-       if err != nil {
-               return "", nil, err
-       }
-
-       tmpFile, err := os.CreateTemp("", "adc-task-*.json")
-       if err != nil {
-               return "", nil, err
-       }
-       cleanup := func() {
-               _ = tmpFile.Close()
-               _ = os.Remove(tmpFile.Name())
-       }
-       if _, err := tmpFile.Write(data); err != nil {
-               cleanup()
-               return "", nil, err
-       }
-
-       log.Debugw("generated adc file", zap.String("filename", 
tmpFile.Name()), zap.String("json", string(data)))
-
-       return tmpFile.Name(), cleanup, nil
-}
-
-func (d *adcClient) handleADCExecutionErrors(statusesMap 
map[string]types.ADCExecutionErrors) {
-       statusUpdateMap := d.resolveADCExecutionErrors(statusesMap)
-       d.handleStatusUpdate(statusUpdateMap)
-}
-
-func (d *adcClient) NeedLeaderElection() bool {
-       return true
-}
diff --git a/internal/provider/apisix/provider.go 
b/internal/provider/apisix/provider.go
new file mode 100644
index 00000000..0246b3e7
--- /dev/null
+++ b/internal/provider/apisix/provider.go
@@ -0,0 +1,297 @@
+// 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 apisix
+
+import (
+       "context"
+       "sync"
+       "time"
+
+       "github.com/api7/gopkg/pkg/log"
+       "go.uber.org/zap"
+       networkingv1 "k8s.io/api/networking/v1"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
+
+       adctypes "github.com/apache/apisix-ingress-controller/api/adc"
+       "github.com/apache/apisix-ingress-controller/api/v1alpha1"
+       apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
+       adcclient 
"github.com/apache/apisix-ingress-controller/internal/adc/client"
+       "github.com/apache/apisix-ingress-controller/internal/adc/translator"
+       "github.com/apache/apisix-ingress-controller/internal/controller/label"
+       "github.com/apache/apisix-ingress-controller/internal/controller/status"
+       "github.com/apache/apisix-ingress-controller/internal/manager/readiness"
+       "github.com/apache/apisix-ingress-controller/internal/provider"
+       "github.com/apache/apisix-ingress-controller/internal/types"
+       "github.com/apache/apisix-ingress-controller/internal/utils"
+)
+
+const ProviderTypeAPISIX = "apisix"
+
+type apisixProvider struct {
+       provider.Options
+       sync.Mutex
+
+       translator *translator.Translator
+
+       updater         status.Updater
+       statusUpdateMap map[types.NamespacedNameKind][]string
+
+       readier readiness.ReadinessManager
+
+       syncCh chan struct{}
+
+       client *adcclient.Client
+}
+
+func New(updater status.Updater, readier readiness.ReadinessManager, opts 
...provider.Option) (provider.Provider, error) {
+       o := provider.Options{}
+       o.ApplyOptions(opts)
+       if o.BackendMode == "" {
+               o.BackendMode = ProviderTypeAPISIX
+       }
+
+       cli, err := adcclient.New(o.BackendMode, o.SyncTimeout)
+       if err != nil {
+               return nil, err
+       }
+
+       return &apisixProvider{
+               client:     cli,
+               Options:    o,
+               translator: &translator.Translator{},
+               updater:    updater,
+               readier:    readier,
+               syncCh:     make(chan struct{}, 1),
+       }, nil
+}
+
+func (d *apisixProvider) Update(ctx context.Context, tctx 
*provider.TranslateContext, obj client.Object) error {
+       log.Debugw("updating object", zap.Any("object", obj))
+       var (
+               result        *translator.TranslateResult
+               resourceTypes []string
+               err           error
+       )
+
+       rk := utils.NamespacedNameKind(obj)
+
+       switch t := obj.(type) {
+       case *gatewayv1.HTTPRoute:
+               result, err = d.translator.TranslateHTTPRoute(tctx, 
t.DeepCopy())
+               resourceTypes = append(resourceTypes, "service")
+       case *gatewayv1.Gateway:
+               result, err = d.translator.TranslateGateway(tctx, t.DeepCopy())
+               resourceTypes = append(resourceTypes, "global_rule", "ssl", 
"plugin_metadata")
+       case *networkingv1.Ingress:
+               result, err = d.translator.TranslateIngress(tctx, t.DeepCopy())
+               resourceTypes = append(resourceTypes, "service", "ssl")
+       case *v1alpha1.Consumer:
+               result, err = d.translator.TranslateConsumerV1alpha1(tctx, 
t.DeepCopy())
+               resourceTypes = append(resourceTypes, "consumer")
+       case *networkingv1.IngressClass:
+               result, err = d.translator.TranslateIngressClass(tctx, 
t.DeepCopy())
+               resourceTypes = append(resourceTypes, "global_rule", 
"plugin_metadata")
+       case *apiv2.ApisixRoute:
+               result, err = d.translator.TranslateApisixRoute(tctx, 
t.DeepCopy())
+               resourceTypes = append(resourceTypes, "service")
+       case *apiv2.ApisixGlobalRule:
+               result, err = d.translator.TranslateApisixGlobalRule(tctx, 
t.DeepCopy())
+               resourceTypes = append(resourceTypes, "global_rule")
+       case *apiv2.ApisixTls:
+               result, err = d.translator.TranslateApisixTls(tctx, 
t.DeepCopy())
+               resourceTypes = append(resourceTypes, "ssl")
+       case *apiv2.ApisixConsumer:
+               result, err = d.translator.TranslateApisixConsumer(tctx, 
t.DeepCopy())
+               resourceTypes = append(resourceTypes, "consumer")
+       case *v1alpha1.GatewayProxy:
+               return d.updateConfigForGatewayProxy(tctx, t)
+       }
+       if err != nil {
+               return err
+       }
+       if result == nil {
+               return nil
+       }
+
+       configs, err := d.buildConfig(tctx, rk)
+       if err != nil {
+               return err
+       }
+
+       if len(configs) == 0 {
+               return nil
+       }
+
+       defer d.syncNotify()
+
+       return d.client.UpdateConfig(ctx, adcclient.Task{
+               Key:           rk,
+               Name:          rk.String(),
+               Labels:        label.GenLabel(obj),
+               Configs:       configs,
+               ResourceTypes: resourceTypes,
+               Resources: &adctypes.Resources{
+                       GlobalRules:    result.GlobalRules,
+                       PluginMetadata: result.PluginMetadata,
+                       Services:       result.Services,
+                       SSLs:           result.SSL,
+                       Consumers:      result.Consumers,
+               },
+       })
+}
+
+func (d *apisixProvider) Delete(ctx context.Context, obj client.Object) error {
+       log.Debugw("deleting object", zap.Any("object", obj))
+
+       var resourceTypes []string
+       var labels map[string]string
+       switch obj.(type) {
+       case *gatewayv1.HTTPRoute, *apiv2.ApisixRoute:
+               resourceTypes = append(resourceTypes, "service")
+               labels = label.GenLabel(obj)
+       case *gatewayv1.Gateway:
+               // delete all resources
+       case *networkingv1.Ingress:
+               resourceTypes = append(resourceTypes, "service", "ssl")
+               labels = label.GenLabel(obj)
+       case *v1alpha1.Consumer:
+               resourceTypes = append(resourceTypes, "consumer")
+               labels = label.GenLabel(obj)
+       case *networkingv1.IngressClass:
+               // delete all resources
+       case *apiv2.ApisixGlobalRule:
+               resourceTypes = append(resourceTypes, "global_rule")
+               labels = label.GenLabel(obj)
+       case *apiv2.ApisixTls:
+               resourceTypes = append(resourceTypes, "ssl")
+               labels = label.GenLabel(obj)
+       case *apiv2.ApisixConsumer:
+               resourceTypes = append(resourceTypes, "consumer")
+               labels = label.GenLabel(obj)
+       }
+       nnk := utils.NamespacedNameKind(obj)
+
+       // Full synchronization is performed on a gateway by gateway basis
+       // and it is not possible to perform scheduled synchronization
+       // on deleted gateway level resources
+       if len(resourceTypes) == 0 {
+               return d.client.Delete(ctx, adcclient.Task{
+                       Key:    nnk,
+                       Name:   nnk.String(),
+                       Labels: labels,
+               })
+       }
+       defer d.syncNotify()
+       return d.client.DeleteConfig(ctx, adcclient.Task{
+               Key:           nnk,
+               Name:          nnk.String(),
+               Labels:        labels,
+               ResourceTypes: resourceTypes,
+       })
+}
+
+func (d *apisixProvider) buildConfig(tctx *provider.TranslateContext, nnk 
types.NamespacedNameKind) (map[types.NamespacedNameKind]adctypes.Config, error) 
{
+       configs := make(map[types.NamespacedNameKind]adctypes.Config, 
len(tctx.ResourceParentRefs[nnk]))
+       for _, gp := range tctx.GatewayProxies {
+               config, err := d.translator.TranslateGatewayProxyToConfig(tctx, 
&gp, d.ResolveEndpoints)
+               if err != nil {
+                       return nil, err
+               }
+               configs[utils.NamespacedNameKind(&gp)] = *config
+       }
+       return configs, nil
+}
+
+func (d *apisixProvider) Start(ctx context.Context) error {
+       d.readier.WaitReady(ctx, 5*time.Minute)
+
+       initalSyncDelay := d.InitSyncDelay
+       if initalSyncDelay > 0 {
+               time.AfterFunc(initalSyncDelay, func() {
+                       if err := d.sync(ctx); err != nil {
+                               log.Error(err)
+                               return
+                       }
+               })
+       }
+
+       if d.SyncPeriod < 1 {
+               return nil
+       }
+       ticker := time.NewTicker(d.SyncPeriod)
+       defer ticker.Stop()
+       for {
+               synced := false
+               select {
+               case <-d.syncCh:
+                       synced = true
+               case <-ticker.C:
+                       synced = true
+               case <-ctx.Done():
+                       return nil
+               }
+               if synced {
+                       if err := d.sync(ctx); err != nil {
+                               log.Error(err)
+                       }
+               }
+       }
+}
+
+func (d *apisixProvider) sync(ctx context.Context) error {
+       statusesMap, err := d.client.Sync(ctx)
+       d.handleADCExecutionErrors(statusesMap)
+       return err
+}
+
+func (d *apisixProvider) syncNotify() {
+       select {
+       case d.syncCh <- struct{}{}:
+       default:
+       }
+}
+
+func (d *apisixProvider) handleADCExecutionErrors(statusesMap 
map[string]types.ADCExecutionErrors) {
+       statusUpdateMap := d.resolveADCExecutionErrors(statusesMap)
+       d.handleStatusUpdate(statusUpdateMap)
+       log.Debugw("handled ADC execution errors", zap.Any("status_record", 
statusesMap), zap.Any("status_update", statusUpdateMap))
+}
+
+func (d *apisixProvider) NeedLeaderElection() bool {
+       return true
+}
+
+// updateConfigForGatewayProxy update config for all referrers of the 
GatewayProxy
+func (d *apisixProvider) updateConfigForGatewayProxy(tctx 
*provider.TranslateContext, gp *v1alpha1.GatewayProxy) error {
+       config, err := d.translator.TranslateGatewayProxyToConfig(tctx, gp, 
d.ResolveEndpoints)
+       if err != nil {
+               return err
+       }
+
+       nnk := utils.NamespacedNameKind(gp)
+       if config == nil {
+               d.client.ConfigManager.DeleteConfig(nnk)
+               return nil
+       }
+       referrers := tctx.GatewayProxyReferrers[utils.NamespacedName(gp)]
+       d.client.ConfigManager.SetConfigRefs(nnk, referrers)
+       d.client.ConfigManager.UpdateConfig(nnk, *config)
+       d.syncNotify()
+       return nil
+}
diff --git a/internal/provider/adc/status.go 
b/internal/provider/apisix/status.go
similarity index 90%
rename from internal/provider/adc/status.go
rename to internal/provider/apisix/status.go
index 8d1f70f8..838fd715 100644
--- a/internal/provider/adc/status.go
+++ b/internal/provider/apisix/status.go
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package adc
+package apisix
 
 import (
        "fmt"
@@ -41,7 +41,7 @@ import (
 // For resources in the current failure map (statusUpdateMap), it marks them 
as failed.
 // For resources that exist only in the previous failure history (i.e. not in 
this sync's failures),
 // it marks them as accepted (success).
-func (d *adcClient) handleStatusUpdate(statusUpdateMap 
map[types.NamespacedNameKind][]string) {
+func (d *apisixProvider) handleStatusUpdate(statusUpdateMap 
map[types.NamespacedNameKind][]string) {
        // Mark all resources in the current failure set as failed.
        for nnk, msgs := range statusUpdateMap {
                d.updateStatus(nnk, cutils.NewConditionTypeAccepted(
@@ -67,7 +67,7 @@ func (d *adcClient) handleStatusUpdate(statusUpdateMap 
map[types.NamespacedNameK
        d.statusUpdateMap = statusUpdateMap
 }
 
-func (d *adcClient) updateStatus(nnk types.NamespacedNameKind, condition 
metav1.Condition) {
+func (d *apisixProvider) updateStatus(nnk types.NamespacedNameKind, condition 
metav1.Condition) {
        switch nnk.Kind {
        case types.KindApisixRoute:
                d.updater.Update(status.Update{
@@ -110,7 +110,8 @@ func (d *adcClient) updateStatus(nnk 
types.NamespacedNameKind, condition metav1.
                        }),
                })
        case types.KindHTTPRoute:
-               parentRefs := d.getParentRefs(nnk)
+               parentRefs := 
d.client.ConfigManager.GetConfigRefsByResourceKey(nnk)
+               log.Debugw("updating HTTPRoute status", zap.Any("parentRefs", 
parentRefs))
                gatewayRefs := map[types.NamespacedNameKind]struct{}{}
                for _, parentRef := range parentRefs {
                        if parentRef.Kind == types.KindGateway {
@@ -146,7 +147,7 @@ func (d *adcClient) updateStatus(nnk 
types.NamespacedNameKind, condition metav1.
        }
 }
 
-func (d *adcClient) resolveADCExecutionErrors(
+func (d *apisixProvider) resolveADCExecutionErrors(
        statusesMap map[string]types.ADCExecutionErrors,
 ) map[types.NamespacedNameKind][]string {
        statusUpdateMap := map[types.NamespacedNameKind][]string{}
@@ -165,12 +166,12 @@ func (d *adcClient) resolveADCExecutionErrors(
        return statusUpdateMap
 }
 
-func (d *adcClient) handleEmptyFailedStatuses(
+func (d *apisixProvider) handleEmptyFailedStatuses(
        configName string,
        failedStatus types.ADCExecutionServerAddrError,
        statusUpdateMap map[types.NamespacedNameKind][]string,
 ) {
-       resource, err := d.store.GetResources(configName)
+       resource, err := d.client.GetResources(configName)
        if err != nil {
                log.Errorw("failed to get resources from store", 
zap.String("configName", configName), zap.Error(err))
                return
@@ -188,7 +189,7 @@ func (d *adcClient) handleEmptyFailedStatuses(
                d.addResourceToStatusUpdateMap(obj.GetLabels(), 
failedStatus.Error(), statusUpdateMap)
        }
 
-       globalRules, err := d.store.ListGlobalRules(configName)
+       globalRules, err := d.client.ListGlobalRules(configName)
        if err != nil {
                log.Errorw("failed to list global rules", 
zap.String("configName", configName), zap.Error(err))
                return
@@ -198,14 +199,14 @@ func (d *adcClient) handleEmptyFailedStatuses(
        }
 }
 
-func (d *adcClient) handleDetailedFailedStatuses(
+func (d *apisixProvider) handleDetailedFailedStatuses(
        configName string,
        failedStatus types.ADCExecutionServerAddrError,
        statusUpdateMap map[types.NamespacedNameKind][]string,
 ) {
        for _, status := range failedStatus.FailedStatuses {
                id := status.Event.ResourceID
-               labels, err := d.store.GetResourceLabel(configName, 
status.Event.ResourceType, id)
+               labels, err := d.client.GetResourceLabel(configName, 
status.Event.ResourceType, id)
                if err != nil {
                        log.Errorw("failed to get resource label",
                                zap.String("configName", configName),
@@ -223,7 +224,7 @@ func (d *adcClient) handleDetailedFailedStatuses(
        }
 }
 
-func (d *adcClient) addResourceToStatusUpdateMap(
+func (d *apisixProvider) addResourceToStatusUpdateMap(
        labels map[string]string,
        msg string,
        statusUpdateMap map[types.NamespacedNameKind][]string,
diff --git a/internal/provider/common/configmanager.go 
b/internal/provider/common/configmanager.go
new file mode 100644
index 00000000..387537b0
--- /dev/null
+++ b/internal/provider/common/configmanager.go
@@ -0,0 +1,170 @@
+// 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 common
+
+import (
+       "sync"
+)
+
+/*
+ConfigManager is a generic configuration association manager that maintains 
relationships between:
+  - Resource objects (e.g., HTTPRoute, Ingress)
+  - Configuration objects (e.g., Gateway, IngressClass configurations)
+  - Referenced resources (e.g., Secrets referenced by configurations)
+
+Core data structure:
+  - resourceConfigKeys: Resource object → Configuration keys
+     (e.g., HTTPRoute/Ingress → [ConfigKey1, ConfigKey2])
+  - configs:             Configuration storage pool
+     (e.g., ConfigKey → GatewayProxy Configuration)
+  - configRefs:          Configuration → Referenced resources
+     (e.g., ConfigKey → [Gateway, IngressClass])
+
+Main relationships:
+  Resource objects (HTTPRoute/Ingress) --resourceConfigKeys--> Configuration 
objects
+      --configRefs--> Referenced resources (Gateways/IngressClasses)
+
+Note: The referenced resources in configRefs are typically higher-level 
abstractions
+that configurations depend on (Gateway/IngressClass), not the low-level 
resources like Secrets.
+*/
+
+type ConfigManager[K comparable, T any] struct {
+       mu sync.Mutex
+
+       configs    map[K]T
+       configRefs map[K][]K
+
+       resourceConfigKeys map[K][]K
+}
+
+func NewConfigManager[K comparable, T any]() *ConfigManager[K, T] {
+       return &ConfigManager[K, T]{
+               resourceConfigKeys: make(map[K][]K),
+               configs:            make(map[K]T),
+               configRefs:         make(map[K][]K),
+       }
+}
+
+func (s *ConfigManager[K, T]) GetConfigRefs(key K) []K {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       return s.configRefs[key]
+}
+
+func (s *ConfigManager[K, T]) GetConfigRefsByResourceKey(key K) []K {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       configKeys, ok := s.resourceConfigKeys[key]
+       if !ok {
+               return nil
+       }
+       refs := make([]K, 0, len(configKeys))
+       for _, k := range configKeys {
+               if ref, ok := s.configRefs[k]; ok {
+                       refs = append(refs, ref...)
+               }
+       }
+       return refs
+}
+
+func (s *ConfigManager[K, T]) SetConfigRefs(key K, refs []K) {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       s.configRefs[key] = refs
+}
+
+func (s *ConfigManager[K, T]) Get(key K) map[K]T {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+
+       resourceConfigKeys := s.resourceConfigKeys[key]
+       configs := make(map[K]T, len(resourceConfigKeys))
+       for _, parent := range resourceConfigKeys {
+               if cfg, ok := s.configs[parent]; ok {
+                       configs[parent] = cfg
+               }
+       }
+       return configs
+}
+
+func (s *ConfigManager[K, T]) List() map[K]T {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+
+       configs := make(map[K]T, len(s.configs))
+       for k, v := range s.configs {
+               configs[k] = v
+       }
+       return configs
+}
+
+func (s *ConfigManager[K, T]) UpdateConfig(key K, cfg T) {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       s.configs[key] = cfg
+}
+
+func (s *ConfigManager[K, T]) Update(
+       key K,
+       mapRefs map[K]T,
+) (discard map[K]T) {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+
+       parentRefSet := make(map[K]struct{})
+       oldParentRefs := s.resourceConfigKeys[key]
+       newRefs := make([]K, 0, len(mapRefs))
+
+       for k, v := range mapRefs {
+               newRefs = append(newRefs, k)
+               s.configs[k] = v
+               parentRefSet[k] = struct{}{}
+       }
+       s.resourceConfigKeys[key] = newRefs
+       discard = make(map[K]T)
+       for _, old := range oldParentRefs {
+               if _, stillUsed := parentRefSet[old]; !stillUsed {
+                       if cfg, ok := s.configs[old]; ok {
+                               discard[old] = cfg
+                       }
+               }
+       }
+
+       return discard
+}
+
+func (s *ConfigManager[K, T]) Set(key K, cfg T) {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       s.configs[key] = cfg
+}
+
+func (s *ConfigManager[K, T]) Delete(key K) {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       delete(s.resourceConfigKeys, key)
+       delete(s.configs, key)
+       delete(s.configRefs, key)
+}
+
+func (s *ConfigManager[K, T]) DeleteConfig(key K) {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+       delete(s.configs, key)
+       delete(s.configRefs, key)
+}
diff --git a/internal/provider/adc/translator/translator.go 
b/internal/provider/init/init.go
similarity index 53%
rename from internal/provider/adc/translator/translator.go
rename to internal/provider/init/init.go
index 67ab7596..3fc68912 100644
--- a/internal/provider/adc/translator/translator.go
+++ b/internal/provider/init/init.go
@@ -15,22 +15,20 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package translator
+package init
 
 import (
-       "github.com/go-logr/logr"
-
-       adctypes "github.com/apache/apisix-ingress-controller/api/adc"
+       "github.com/apache/apisix-ingress-controller/internal/controller/status"
+       "github.com/apache/apisix-ingress-controller/internal/manager/readiness"
+       "github.com/apache/apisix-ingress-controller/internal/provider"
+       "github.com/apache/apisix-ingress-controller/internal/provider/apisix"
 )
 
-type Translator struct {
-       Log logr.Logger
-}
-type TranslateResult struct {
-       Routes         []*adctypes.Route
-       Services       []*adctypes.Service
-       SSL            []*adctypes.SSL
-       GlobalRules    adctypes.GlobalRule
-       PluginMetadata adctypes.PluginMetadata
-       Consumers      []*adctypes.Consumer
+func init() {
+       provider.Register("apisix", apisix.New)
+       provider.Register("apisix-standalone", func(statusUpdater 
status.Updater, readinessManager readiness.ReadinessManager, opts 
...provider.Option) (provider.Provider, error) {
+               opts = append(opts, 
provider.WithBackendMode("apisix-standalone"))
+               opts = append(opts, provider.WithResolveEndpoints())
+               return apisix.New(statusUpdater, readinessManager, opts...)
+       })
 }
diff --git a/internal/provider/adc/options.go b/internal/provider/options.go
similarity index 67%
rename from internal/provider/adc/options.go
rename to internal/provider/options.go
index 8b6d7631..540f2e63 100644
--- a/internal/provider/adc/options.go
+++ b/internal/provider/options.go
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package adc
+package provider
 
 import "time"
 
@@ -24,10 +24,11 @@ type Option interface {
 }
 
 type Options struct {
-       SyncTimeout   time.Duration
-       SyncPeriod    time.Duration
-       InitSyncDelay time.Duration
-       BackendMode   string
+       SyncTimeout      time.Duration
+       SyncPeriod       time.Duration
+       InitSyncDelay    time.Duration
+       BackendMode      string
+       ResolveEndpoints bool
 }
 
 func (o *Options) ApplyToList(lo *Options) {
@@ -43,6 +44,9 @@ func (o *Options) ApplyToList(lo *Options) {
        if o.BackendMode != "" {
                lo.BackendMode = o.BackendMode
        }
+       if o.ResolveEndpoints {
+               lo.ResolveEndpoints = o.ResolveEndpoints
+       }
 }
 
 func (o *Options) ApplyOptions(opts []Option) *Options {
@@ -51,3 +55,23 @@ func (o *Options) ApplyOptions(opts []Option) *Options {
        }
        return o
 }
+
+type backendModeOption string
+
+func (b backendModeOption) ApplyToList(o *Options) {
+       o.BackendMode = string(b)
+}
+
+func WithBackendMode(mode string) Option {
+       return backendModeOption(mode)
+}
+
+type resolveEndpointsOption bool
+
+func (r resolveEndpointsOption) ApplyToList(o *Options) {
+       o.ResolveEndpoints = bool(r)
+}
+
+func WithResolveEndpoints() Option {
+       return resolveEndpointsOption(true)
+}
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index d9b6cbfa..ef93de54 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -35,7 +35,6 @@ import (
 type Provider interface {
        Update(context.Context, *TranslateContext, client.Object) error
        Delete(context.Context, client.Object) error
-       Sync(context.Context) error
        Start(context.Context) error
        NeedLeaderElection() bool
 }
diff --git a/internal/provider/register.go b/internal/provider/register.go
new file mode 100644
index 00000000..a2542ad7
--- /dev/null
+++ b/internal/provider/register.go
@@ -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 provider
+
+import (
+       "fmt"
+
+       "github.com/apache/apisix-ingress-controller/internal/controller/status"
+       "github.com/apache/apisix-ingress-controller/internal/manager/readiness"
+)
+
+type RegisterFunc func(status.Updater, readiness.ReadinessManager, ...Option) 
(Provider, error)
+
+var providers = map[string]RegisterFunc{}
+
+func Register(name string, registerFunc RegisterFunc) {
+       providers[name] = registerFunc
+}
+
+func Get(name string) (RegisterFunc, error) {
+       f, ok := providers[name]
+       if !ok {
+               return nil, fmt.Errorf("provider %q not found", name)
+       }
+       return f, nil
+}
+
+func New(providerType string, updater status.Updater, readinesser 
readiness.ReadinessManager, opts ...Option) (Provider, error) {
+       f, err := Get(providerType)
+       if err != nil {
+               return nil, fmt.Errorf("failed to get provider %q: %w", 
providerType, err)
+       }
+       return f(updater, readinesser, opts...)
+}
diff --git a/internal/types/types.go b/internal/types/types.go
index f695da87..5fe4b6a2 100644
--- a/internal/types/types.go
+++ b/internal/types/types.go
@@ -18,6 +18,9 @@
 package types
 
 import (
+       "fmt"
+       "strings"
+
        k8stypes "k8s.io/apimachinery/pkg/types"
 )
 
@@ -27,9 +30,33 @@ type NamespacedNameKind struct {
        Kind      string
 }
 
-func (n *NamespacedNameKind) NamespacedName() k8stypes.NamespacedName {
+func (n NamespacedNameKind) NamespacedName() k8stypes.NamespacedName {
        return k8stypes.NamespacedName{
                Namespace: n.Namespace,
                Name:      n.Name,
        }
 }
+
+func (n NamespacedNameKind) String() string {
+       return n.Kind + "/" + n.Namespace + "/" + n.Name
+}
+
+func (n NamespacedNameKind) MarshalText() ([]byte, error) {
+       return []byte(n.String()), nil
+}
+
+func (n *NamespacedNameKind) UnmarshalText(text []byte) error {
+       return n.FromString(string(text))
+}
+
+func (n *NamespacedNameKind) FromString(s string) error {
+       parts := strings.Split(s, "/")
+       if len(parts) != 3 {
+               return fmt.Errorf("invalid format for NamespacedNameKind: %q, 
expected Kind/Namespace/Name", s)
+       }
+
+       n.Kind = parts[0]
+       n.Namespace = parts[1]
+       n.Name = parts[2]
+       return nil
+}
diff --git a/test/e2e/crds/v1alpha1/gatewayproxy.go 
b/test/e2e/crds/v1alpha1/gatewayproxy.go
index 7668cfa1..abe56aac 100644
--- a/test/e2e/crds/v1alpha1/gatewayproxy.go
+++ b/test/e2e/crds/v1alpha1/gatewayproxy.go
@@ -30,7 +30,6 @@ import (
        "k8s.io/apimachinery/pkg/util/wait"
        "k8s.io/utils/ptr"
 
-       "github.com/apache/apisix-ingress-controller/internal/provider/adc"
        "github.com/apache/apisix-ingress-controller/test/e2e/framework"
        "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
 )
@@ -187,7 +186,7 @@ spec:
                                keyword string
                        )
 
-                       if framework.ProviderType == adc.BackendModeAPISIX {
+                       if framework.ProviderType == 
framework.ProviderTypeAPISIX {
                                keyword = fmt.Sprintf(`{"config.ServerAddrs": 
["%s"]}`, s.Deployer.GetAdminEndpoint())
                        } else {
                                keyword = fmt.Sprintf(`{"config.ServerAddrs": 
["http://%s:9180"]}`, s.GetPodIP(s.Namespace(), 
"app.kubernetes.io/name=apisix"))
diff --git a/test/e2e/framework/apisix_consts.go 
b/test/e2e/framework/apisix_consts.go
index 42214982..1761b1ec 100644
--- a/test/e2e/framework/apisix_consts.go
+++ b/test/e2e/framework/apisix_consts.go
@@ -30,6 +30,11 @@ var (
        ProviderType = cmp.Or(os.Getenv("PROVIDER_TYPE"), "apisix")
 )
 
+const (
+       ProviderTypeAPISIX           = "apisix"
+       ProviderTypeAPISIXStandalone = "apisix-standalone"
+)
+
 var (
        //go:embed manifests/apisix.yaml
        apisixStandaloneTemplate string
diff --git a/test/e2e/framework/manifests/apisix-standalone.yaml 
b/test/e2e/framework/manifests/apisix-standalone.yaml
index 457a68b1..1a76b29c 100644
--- a/test/e2e/framework/manifests/apisix-standalone.yaml
+++ b/test/e2e/framework/manifests/apisix-standalone.yaml
@@ -54,7 +54,7 @@ spec:
     spec:
       initContainers:
         - name: config-setup
-          image: apache/apisix:dev
+          image: apache/apisix:3.13.0-ubuntu
           command:
             - sh
             - -c
@@ -72,7 +72,7 @@ spec:
               mountPath: /tmp/apisix-conf
       containers:
         - name: apisix
-          image: apache/apisix:dev
+          image: apache/apisix:3.13.0-ubuntu
           ports:
             - name: http
               containerPort: 9080
diff --git a/test/e2e/framework/manifests/apisix.yaml 
b/test/e2e/framework/manifests/apisix.yaml
index b01beca1..3117ccee 100644
--- a/test/e2e/framework/manifests/apisix.yaml
+++ b/test/e2e/framework/manifests/apisix.yaml
@@ -61,7 +61,7 @@ spec:
     spec:
       initContainers:
         - name: config-setup
-          image: apache/apisix:dev
+          image: apache/apisix:3.13.0-ubuntu
           command:
             - sh
             - -c
@@ -79,7 +79,7 @@ spec:
               mountPath: /tmp/apisix-conf
       containers:
         - name: apisix
-          image: apache/apisix:dev
+          image: apache/apisix:3.13.0-ubuntu
           ports:
             - name: http
               containerPort: 9080
diff --git a/test/e2e/scaffold/adc.go b/test/e2e/scaffold/adc.go
index 12bd229e..11d5a712 100644
--- a/test/e2e/scaffold/adc.go
+++ b/test/e2e/scaffold/adc.go
@@ -30,7 +30,7 @@ import (
        "gopkg.in/yaml.v3"
 
        adctypes "github.com/apache/apisix-ingress-controller/api/adc"
-       
"github.com/apache/apisix-ingress-controller/internal/provider/adc/translator"
+       "github.com/apache/apisix-ingress-controller/internal/adc/translator"
 )
 
 // DataplaneResource defines the interface for accessing dataplane resources
diff --git a/test/e2e/scaffold/apisix_deployer.go 
b/test/e2e/scaffold/apisix_deployer.go
index 740f9e02..f83cd29d 100644
--- a/test/e2e/scaffold/apisix_deployer.go
+++ b/test/e2e/scaffold/apisix_deployer.go
@@ -30,7 +30,6 @@ import (
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/utils/ptr"
 
-       "github.com/apache/apisix-ingress-controller/internal/provider/adc"
        "github.com/apache/apisix-ingress-controller/pkg/utils"
        "github.com/apache/apisix-ingress-controller/test/e2e/framework"
 )
@@ -215,7 +214,7 @@ func (s *APISIXDeployer) deployDataplane(opts 
*APISIXDeployOptions) *corev1.Serv
 
        kubectlOpts := k8s.NewKubectlOptions("", "", opts.Namespace)
 
-       if framework.ProviderType == adc.BackendModeAPISIX {
+       if framework.ProviderType == framework.ProviderTypeAPISIX {
                opts.ConfigProvider = "etcd"
                // deploy etcd
                k8s.KubectlApplyFromString(s.GinkgoT, kubectlOpts, 
framework.EtcdSpec)

Reply via email to