Skip to content

Commit a9513d2

Browse files
authored
feat: support deployment of multiple data plane modes (#2647)
1 parent 6f0e78c commit a9513d2

File tree

15 files changed

+327
-84
lines changed

15 files changed

+327
-84
lines changed

api/adc/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,7 @@ type Config struct {
779779
ServerAddrs []string
780780
Token string
781781
TlsVerify bool
782+
BackendType string
782783
}
783784

784785
// MarshalJSON implements custom JSON marshaling for adcConfig

api/v1alpha1/gatewayproxy_types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,13 @@ type ControlPlaneAuth struct {
119119

120120
// ControlPlaneProvider defines configuration for control plane provider.
121121
// +kubebuilder:validation:XValidation:rule="has(self.endpoints) != has(self.service)"
122+
// +kubebuilder:validation:XValidation:rule="oldSelf == null || (!has(self.mode) && !has(oldSelf.mode)) || self.mode == oldSelf.mode",message="mode is immutable"
122123
type ControlPlaneProvider struct {
124+
// Mode specifies the mode of control plane provider.
125+
// Can be `apisix` or `apisix-standalone`.
126+
//
127+
// +kubebuilder:validation:Optional
128+
Mode string `json:"mode,omitempty"`
123129
// Endpoints specifies the list of control plane endpoints.
124130
// +kubebuilder:validation:Optional
125131
// +kubebuilder:validation:MinItems=1

config/crd/bases/apisix.apache.org_gatewayproxies.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ spec:
127127
type: string
128128
minItems: 1
129129
type: array
130+
mode:
131+
description: |-
132+
Mode specifies the mode of control plane provider.
133+
Can be `apisix` or `apisix-standalone`.
134+
type: string
130135
service:
131136
properties:
132137
name:
@@ -150,6 +155,9 @@ spec:
150155
type: object
151156
x-kubernetes-validations:
152157
- rule: has(self.endpoints) != has(self.service)
158+
- message: mode is immutable
159+
rule: oldSelf == null || (!has(self.mode) && !has(oldSelf.mode))
160+
|| self.mode == oldSelf.mode
153161
type:
154162
description: Type specifies the type of provider. Can only be
155163
`ControlPlane`.

docs/en/latest/reference/api-reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ ControlPlaneProvider defines configuration for control plane provider.
229229

230230
| Field | Description |
231231
| --- | --- |
232+
| `mode` _string_ | Mode specifies the mode of control plane provider. Can be `apisix` or `apisix-standalone`. |
232233
| `endpoints` _string array_ | Endpoints specifies the list of control plane endpoints. |
233234
| `service` _[ProviderService](#providerservice)_ | |
234235
| `tlsVerify` _boolean_ | TlsVerify specifies whether to verify the TLS certificate of the control plane. |

internal/adc/client/client.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,17 @@ type Client struct {
4141
mu sync.Mutex
4242
*cache.Store
4343

44-
executor ADCExecutor
45-
BackendMode string
44+
executor ADCExecutor
4645

4746
ConfigManager *common.ConfigManager[types.NamespacedNameKind, adctypes.Config]
4847
ADCDebugProvider *common.ADCDebugProvider
4948

49+
defaultMode string
50+
5051
log logr.Logger
5152
}
5253

53-
func New(log logr.Logger, mode string, timeout time.Duration) (*Client, error) {
54+
func New(log logr.Logger, defaultMode string, timeout time.Duration) (*Client, error) {
5455
serverURL := os.Getenv("ADC_SERVER_URL")
5556
if serverURL == "" {
5657
serverURL = defaultHTTPADCExecutorAddr
@@ -59,15 +60,15 @@ func New(log logr.Logger, mode string, timeout time.Duration) (*Client, error) {
5960
configManager := common.NewConfigManager[types.NamespacedNameKind, adctypes.Config]()
6061

6162
logger := log.WithName("client")
62-
logger.Info("ADC client initialized", "mode", mode)
63+
logger.Info("ADC client initialized")
6364

6465
return &Client{
6566
Store: store,
6667
executor: NewHTTPADCExecutor(log, serverURL, timeout),
67-
BackendMode: mode,
6868
ConfigManager: configManager,
6969
ADCDebugProvider: common.NewADCDebugProvider(store, configManager),
7070
log: logger,
71+
defaultMode: defaultMode,
7172
}, nil
7273
}
7374

@@ -254,8 +255,11 @@ func (c *Client) sync(ctx context.Context, task Task) error {
254255
if resourceType == "" {
255256
resourceType = "all"
256257
}
258+
if config.BackendType == "" {
259+
config.BackendType = c.defaultMode
260+
}
257261

258-
err := c.executor.Execute(ctx, c.BackendMode, config, args)
262+
err := c.executor.Execute(ctx, config, args)
259263
duration := time.Since(startTime).Seconds()
260264

261265
status := adctypes.StatusSuccess

internal/adc/client/executor.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,25 +44,25 @@ const (
4444
)
4545

4646
type ADCExecutor interface {
47-
Execute(ctx context.Context, mode string, config adctypes.Config, args []string) error
47+
Execute(ctx context.Context, config adctypes.Config, args []string) error
4848
}
4949

5050
type DefaultADCExecutor struct {
5151
sync.Mutex
5252
log logr.Logger
5353
}
5454

55-
func (e *DefaultADCExecutor) Execute(ctx context.Context, mode string, config adctypes.Config, args []string) error {
56-
return e.runADC(ctx, mode, config, args)
55+
func (e *DefaultADCExecutor) Execute(ctx context.Context, config adctypes.Config, args []string) error {
56+
return e.runADC(ctx, config, args)
5757
}
5858

59-
func (e *DefaultADCExecutor) runADC(ctx context.Context, mode string, config adctypes.Config, args []string) error {
59+
func (e *DefaultADCExecutor) runADC(ctx context.Context, config adctypes.Config, args []string) error {
6060
var execErrs = types.ADCExecutionError{
6161
Name: config.Name,
6262
}
6363

6464
for _, addr := range config.ServerAddrs {
65-
if err := e.runForSingleServerWithTimeout(ctx, addr, mode, config, args); err != nil {
65+
if err := e.runForSingleServerWithTimeout(ctx, addr, config, args); err != nil {
6666
e.log.Error(err, "failed to run adc for server", "server", addr)
6767
var execErr types.ADCExecutionServerAddrError
6868
if errors.As(err, &execErr) {
@@ -81,21 +81,21 @@ func (e *DefaultADCExecutor) runADC(ctx context.Context, mode string, config adc
8181
return nil
8282
}
8383

84-
func (e *DefaultADCExecutor) runForSingleServerWithTimeout(ctx context.Context, serverAddr, mode string, config adctypes.Config, args []string) error {
84+
func (e *DefaultADCExecutor) runForSingleServerWithTimeout(ctx context.Context, serverAddr string, config adctypes.Config, args []string) error {
8585
ctx, cancel := context.WithTimeout(ctx, 15*time.Second)
8686
defer cancel()
87-
return e.runForSingleServer(ctx, serverAddr, mode, config, args)
87+
return e.runForSingleServer(ctx, serverAddr, config, args)
8888
}
8989

90-
func (e *DefaultADCExecutor) runForSingleServer(ctx context.Context, serverAddr, mode string, config adctypes.Config, args []string) error {
90+
func (e *DefaultADCExecutor) runForSingleServer(ctx context.Context, serverAddr string, config adctypes.Config, args []string) error {
9191
cmdArgs := append([]string{}, args...)
9292
if !config.TlsVerify {
9393
cmdArgs = append(cmdArgs, "--tls-skip-verify")
9494
}
9595

9696
cmdArgs = append(cmdArgs, "--timeout", "15s")
9797

98-
env := e.prepareEnv(serverAddr, mode, config.Token)
98+
env := e.prepareEnv(serverAddr, config.BackendType, config.Token)
9999

100100
var stdout, stderr bytes.Buffer
101101
cmd := exec.CommandContext(ctx, "adc", cmdArgs...)
@@ -250,26 +250,26 @@ func NewHTTPADCExecutor(log logr.Logger, serverURL string, timeout time.Duration
250250
}
251251

252252
// Execute implements the ADCExecutor interface using HTTP calls
253-
func (e *HTTPADCExecutor) Execute(ctx context.Context, mode string, config adctypes.Config, args []string) error {
254-
return e.runHTTPSync(ctx, mode, config, args)
253+
func (e *HTTPADCExecutor) Execute(ctx context.Context, config adctypes.Config, args []string) error {
254+
return e.runHTTPSync(ctx, config, args)
255255
}
256256

257257
// runHTTPSync performs HTTP sync to ADC Server for each server address
258-
func (e *HTTPADCExecutor) runHTTPSync(ctx context.Context, mode string, config adctypes.Config, args []string) error {
258+
func (e *HTTPADCExecutor) runHTTPSync(ctx context.Context, config adctypes.Config, args []string) error {
259259
var execErrs = types.ADCExecutionError{
260260
Name: config.Name,
261261
}
262262

263263
serverAddrs := func() []string {
264-
if mode == "apisix-standalone" {
264+
if config.BackendType == "apisix-standalone" {
265265
return []string{strings.Join(config.ServerAddrs, ",")}
266266
}
267267
return config.ServerAddrs
268268
}()
269-
e.log.V(1).Info("running http sync", "serverAddrs", serverAddrs, "mode", mode)
269+
e.log.V(1).Info("running http sync", "serverAddrs", serverAddrs)
270270

271271
for _, addr := range serverAddrs {
272-
if err := e.runHTTPSyncForSingleServer(ctx, addr, mode, config, args); err != nil {
272+
if err := e.runHTTPSyncForSingleServer(ctx, addr, config, args); err != nil {
273273
e.log.Error(err, "failed to run http sync for server", "server", addr)
274274
var execErr types.ADCExecutionServerAddrError
275275
if errors.As(err, &execErr) {
@@ -289,7 +289,7 @@ func (e *HTTPADCExecutor) runHTTPSync(ctx context.Context, mode string, config a
289289
}
290290

291291
// runHTTPSyncForSingleServer performs HTTP sync to a single ADC Server
292-
func (e *HTTPADCExecutor) runHTTPSyncForSingleServer(ctx context.Context, serverAddr, mode string, config adctypes.Config, args []string) error {
292+
func (e *HTTPADCExecutor) runHTTPSyncForSingleServer(ctx context.Context, serverAddr string, config adctypes.Config, args []string) error {
293293
ctx, cancel := context.WithTimeout(ctx, e.httpClient.Timeout)
294294
defer cancel()
295295

@@ -306,7 +306,7 @@ func (e *HTTPADCExecutor) runHTTPSyncForSingleServer(ctx context.Context, server
306306
}
307307

308308
// Build HTTP request
309-
req, err := e.buildHTTPRequest(ctx, serverAddr, mode, config, labels, types, resources)
309+
req, err := e.buildHTTPRequest(ctx, serverAddr, config, labels, types, resources)
310310
if err != nil {
311311
return fmt.Errorf("failed to build HTTP request: %w", err)
312312
}
@@ -379,13 +379,13 @@ func (e *HTTPADCExecutor) loadResourcesFromFile(filePath string) (*adctypes.Reso
379379
}
380380

381381
// buildHTTPRequest builds the HTTP request for ADC Server
382-
func (e *HTTPADCExecutor) buildHTTPRequest(ctx context.Context, serverAddr, mode string, config adctypes.Config, labels map[string]string, types []string, resources *adctypes.Resources) (*http.Request, error) {
382+
func (e *HTTPADCExecutor) buildHTTPRequest(ctx context.Context, serverAddr string, config adctypes.Config, labels map[string]string, types []string, resources *adctypes.Resources) (*http.Request, error) {
383383
// Prepare request body
384384
tlsVerify := config.TlsVerify
385385
reqBody := ADCServerRequest{
386386
Task: ADCServerTask{
387387
Opts: ADCServerOpts{
388-
Backend: mode,
388+
Backend: config.BackendType,
389389
Server: strings.Split(serverAddr, ","),
390390
Token: config.Token,
391391
LabelSelector: labels,
@@ -407,7 +407,7 @@ func (e *HTTPADCExecutor) buildHTTPRequest(ctx context.Context, serverAddr, mode
407407
e.log.V(1).Info("sending HTTP request to ADC Server",
408408
"url", e.serverURL+"/sync",
409409
"server", serverAddr,
410-
"mode", mode,
410+
"mode", config.BackendType,
411411
"cacheKey", config.Name,
412412
"labelSelector", labels,
413413
"includeResourceType", types,

internal/adc/translator/gatewayproxy.go

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131

3232
types "github.com/apache/apisix-ingress-controller/api/adc"
3333
"github.com/apache/apisix-ingress-controller/api/v1alpha1"
34+
"github.com/apache/apisix-ingress-controller/internal/controller/config"
3435
"github.com/apache/apisix-ingress-controller/internal/provider"
3536
"github.com/apache/apisix-ingress-controller/internal/utils"
3637
)
@@ -44,47 +45,55 @@ func (t *Translator) TranslateGatewayProxyToConfig(tctx *provider.TranslateConte
4445
if provider.Type != v1alpha1.ProviderTypeControlPlane || provider.ControlPlane == nil {
4546
return nil, nil
4647
}
48+
cp := provider.ControlPlane
4749

48-
config := types.Config{
49-
Name: utils.NamespacedNameKind(gatewayProxy).String(),
50+
cfg := types.Config{
51+
Name: utils.NamespacedNameKind(gatewayProxy).String(),
52+
BackendType: cp.Mode,
5053
}
5154

52-
if provider.ControlPlane.TlsVerify != nil {
53-
config.TlsVerify = *provider.ControlPlane.TlsVerify
55+
if cp.TlsVerify != nil {
56+
cfg.TlsVerify = *cp.TlsVerify
5457
}
5558

56-
if provider.ControlPlane.Auth.Type == v1alpha1.AuthTypeAdminKey && provider.ControlPlane.Auth.AdminKey != nil {
57-
if provider.ControlPlane.Auth.AdminKey.ValueFrom != nil && provider.ControlPlane.Auth.AdminKey.ValueFrom.SecretKeyRef != nil {
58-
secretRef := provider.ControlPlane.Auth.AdminKey.ValueFrom.SecretKeyRef
59+
if cp.Auth.Type == v1alpha1.AuthTypeAdminKey && cp.Auth.AdminKey != nil {
60+
if cp.Auth.AdminKey.ValueFrom != nil && cp.Auth.AdminKey.ValueFrom.SecretKeyRef != nil {
61+
secretRef := cp.Auth.AdminKey.ValueFrom.SecretKeyRef
5962
secret, ok := tctx.Secrets[k8stypes.NamespacedName{
6063
// we should use gateway proxy namespace
6164
Namespace: gatewayProxy.GetNamespace(),
6265
Name: secretRef.Name,
6366
}]
6467
if ok {
6568
if token, ok := secret.Data[secretRef.Key]; ok {
66-
config.Token = string(token)
69+
cfg.Token = string(token)
6770
}
6871
}
69-
} else if provider.ControlPlane.Auth.AdminKey.Value != "" {
70-
config.Token = provider.ControlPlane.Auth.AdminKey.Value
72+
} else if cp.Auth.AdminKey.Value != "" {
73+
cfg.Token = cp.Auth.AdminKey.Value
7174
}
7275
}
7376

74-
if config.Token == "" {
77+
if cfg.Token == "" {
7578
return nil, errors.New("no token found")
7679
}
7780

78-
endpoints := provider.ControlPlane.Endpoints
81+
endpoints := cp.Endpoints
7982
if len(endpoints) > 0 {
80-
config.ServerAddrs = endpoints
81-
return &config, nil
83+
cfg.ServerAddrs = endpoints
84+
return &cfg, nil
8285
}
8386

84-
if provider.ControlPlane.Service != nil {
87+
// If Mode is empty, use the default static configuration.
88+
// If Mode is set, resolve endpoints only when the ControlPlane is in standalone mode.
89+
if cp.Mode != "" {
90+
resolveEndpoints = cp.Mode == string(config.ProviderTypeStandalone)
91+
}
92+
93+
if cp.Service != nil {
8594
namespacedName := k8stypes.NamespacedName{
8695
Namespace: gatewayProxy.Namespace,
87-
Name: provider.ControlPlane.Service.Name,
96+
Name: cp.Service.Name,
8897
}
8998
svc, ok := tctx.Services[namespacedName]
9099
if !ok {
@@ -100,9 +109,9 @@ func (t *Translator) TranslateGatewayProxyToConfig(tctx *provider.TranslateConte
100109
}
101110
upstreamNodes, _, err := t.TranslateBackendRefWithFilter(tctx, gatewayv1.BackendRef{
102111
BackendObjectReference: gatewayv1.BackendObjectReference{
103-
Name: gatewayv1.ObjectName(provider.ControlPlane.Service.Name),
112+
Name: gatewayv1.ObjectName(cp.Service.Name),
104113
Namespace: (*gatewayv1.Namespace)(&gatewayProxy.Namespace),
105-
Port: ptr.To(gatewayv1.PortNumber(provider.ControlPlane.Service.Port)),
114+
Port: ptr.To(gatewayv1.PortNumber(cp.Service.Port)),
106115
},
107116
}, func(endpoint *discoveryv1.Endpoint) bool {
108117
if endpoint.Conditions.Terminating != nil && *endpoint.Conditions.Terminating {
@@ -115,21 +124,21 @@ func (t *Translator) TranslateGatewayProxyToConfig(tctx *provider.TranslateConte
115124
return nil, err
116125
}
117126
for _, node := range upstreamNodes {
118-
config.ServerAddrs = append(config.ServerAddrs, "http://"+net.JoinHostPort(node.Host, strconv.Itoa(node.Port)))
127+
cfg.ServerAddrs = append(cfg.ServerAddrs, "http://"+net.JoinHostPort(node.Host, strconv.Itoa(node.Port)))
119128
}
120129
} else {
121-
refPort := provider.ControlPlane.Service.Port
130+
refPort := cp.Service.Port
122131
var serverAddr string
123132
if svc.Spec.Type == corev1.ServiceTypeExternalName {
124133
serverAddr = fmt.Sprintf("http://%s:%d", svc.Spec.ExternalName, refPort)
125134
} else {
126-
serverAddr = fmt.Sprintf("http://%s.%s.svc:%d", provider.ControlPlane.Service.Name, gatewayProxy.Namespace, refPort)
135+
serverAddr = fmt.Sprintf("http://%s.%s.svc:%d", cp.Service.Name, gatewayProxy.Namespace, refPort)
127136
}
128-
config.ServerAddrs = []string{serverAddr}
137+
cfg.ServerAddrs = []string{serverAddr}
129138
}
130139

131-
t.Log.V(1).Info("add server address to config.ServiceAddrs", "config.ServerAddrs", config.ServerAddrs)
140+
t.Log.V(1).Info("add server address to config.ServiceAddrs", "config.ServerAddrs", cfg.ServerAddrs)
132141
}
133142

134-
return &config, nil
143+
return &cfg, nil
135144
}

internal/manager/run.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ func Run(ctx context.Context, logger logr.Logger) error {
183183
SyncTimeout: config.ControllerConfig.ExecADCTimeout.Duration,
184184
SyncPeriod: config.ControllerConfig.ProviderConfig.SyncPeriod.Duration,
185185
InitSyncDelay: config.ControllerConfig.ProviderConfig.InitSyncDelay.Duration,
186-
BackendMode: string(config.ControllerConfig.ProviderConfig.Type),
187186
}
188187
provider, err := provider.New(providerType, logger, updater.Writer(), readier, providerOptions)
189188
if err != nil {

internal/provider/apisix/provider.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ type apisixProvider struct {
7272
func New(log logr.Logger, updater status.Updater, readier readiness.ReadinessManager, opts ...provider.Option) (provider.Provider, error) {
7373
o := provider.Options{}
7474
o.ApplyOptions(opts)
75-
if o.BackendMode == "" {
76-
o.BackendMode = ProviderTypeAPISIX
75+
if o.DefaultBackendMode == "" {
76+
o.DefaultBackendMode = ProviderTypeAPISIX
7777
}
7878

79-
cli, err := adcclient.New(log, o.BackendMode, o.SyncTimeout)
79+
cli, err := adcclient.New(log, o.DefaultBackendMode, o.SyncTimeout)
8080
if err != nil {
8181
return nil, err
8282
}
@@ -239,7 +239,7 @@ func (d *apisixProvider) Delete(ctx context.Context, obj client.Object) error {
239239
func (d *apisixProvider) buildConfig(tctx *provider.TranslateContext, nnk types.NamespacedNameKind) (map[types.NamespacedNameKind]adctypes.Config, error) {
240240
configs := make(map[types.NamespacedNameKind]adctypes.Config, len(tctx.ResourceParentRefs[nnk]))
241241
for _, gp := range tctx.GatewayProxies {
242-
config, err := d.translator.TranslateGatewayProxyToConfig(tctx, &gp, d.ResolveEndpoints)
242+
config, err := d.translator.TranslateGatewayProxyToConfig(tctx, &gp, d.DefaultResolveEndpoints)
243243
if err != nil {
244244
return nil, err
245245
}
@@ -307,7 +307,7 @@ func (d *apisixProvider) NeedLeaderElection() bool {
307307

308308
// updateConfigForGatewayProxy update config for all referrers of the GatewayProxy
309309
func (d *apisixProvider) updateConfigForGatewayProxy(tctx *provider.TranslateContext, gp *v1alpha1.GatewayProxy) error {
310-
config, err := d.translator.TranslateGatewayProxyToConfig(tctx, gp, d.ResolveEndpoints)
310+
config, err := d.translator.TranslateGatewayProxyToConfig(tctx, gp, d.DefaultResolveEndpoints)
311311
if err != nil {
312312
return err
313313
}

0 commit comments

Comments
 (0)