Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ jobs:
echo "building images..."
make build-image

- name: Build Dockerfile.dev and extract adc binary
run: |
echo "Building Dockerfile.dev..."
docker build -f Dockerfile.dev -t adc-builder:latest .
echo "Extracting adc binary..."
docker run --name adc-temp --entrypoint="" adc-builder:latest /bin/true
docker cp adc-temp:/bin/adc ./bin/adc
docker rm adc-temp
chmod +x ./bin/adc
mv ./bin/adc /usr/local/bin/adc
echo "ADC binary extracted to /usr/local/bin/adc"

- name: Launch Kind Cluster
run: |
make kind-up
Expand Down
7 changes: 5 additions & 2 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ARG ENABLE_PROXY=false
FROM node:22 AS node_builder

ARG TARGETARCH
ARG ADC_COMMIT=78484e87a0168e0f86d130bfae8f808d0d1a1e41
ARG ADC_COMMIT=e948079ed0576dbac29320ebfa01c9b7a298924c

WORKDIR /app

Expand All @@ -22,10 +22,13 @@ RUN apt update \
&& rm -rf /app

FROM debian:bullseye-slim

ARG TARGETARCH

WORKDIR /app

COPY --from=node_builder /bin/adc /bin/adc
COPY ./bin/apisix-ingress-controller .
COPY ./bin/apisix-ingress-controller_${TARGETARCH} ./apisix-ingress-controller
COPY ./config/samples/config.yaml ./conf/config.yaml

ENTRYPOINT ["/app/apisix-ingress-controller"]
Expand Down
21 changes: 10 additions & 11 deletions test/e2e/framework/manifests/apisix-standalone.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@ metadata:
name: apisix-conf
data:
config.yaml: |
apisix:
enable_admin: true
admin_key:
- name: admin
key: {{ .AdminKey }}
role: admin
ssl:
enabled: true
nginx_config:
worker_processes: 2
error_log_level: info
deployment:
role: traditional
role_traditional:
config_provider: yaml
admin:
allow_admin:
- 0.0.0.0/0
admin_key:
- key: {{ .AdminKey }}
name: admin
role: admin
nginx_config:
worker_processes: 2
error_log_level: info
---
apiVersion: apps/v1
kind: Deployment
Expand Down
13 changes: 10 additions & 3 deletions test/e2e/gatewayapi/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package gatewayapi
import (
"context"
"fmt"
"log"
"strings"
"time"

Expand Down Expand Up @@ -204,7 +205,9 @@ spec:
tls, err := s.DefaultDataplaneResource().SSL().List(context.Background())
assert.Nil(GinkgoT(), err, "list tls error")
assert.Len(GinkgoT(), tls, 1, "tls number not expect")
assert.Equal(GinkgoT(), Cert, tls[0].Cert, "tls cert not expect")
log.Println("tls", tls)
assert.Len(GinkgoT(), tls[0].Certificates, 1, "length of certificates not expect")
assert.Equal(GinkgoT(), Cert, tls[0].Certificates[0].Certificate, "tls cert not expect")
assert.ElementsMatch(GinkgoT(), []string{host, "*.api6.com"}, tls[0].Snis)
})

Expand Down Expand Up @@ -277,7 +280,8 @@ spec:
tls, err := s.DefaultDataplaneResource().SSL().List(context.Background())
assert.Nil(GinkgoT(), err, "list tls error")
assert.Len(GinkgoT(), tls, 1, "tls number not expect")
assert.Equal(GinkgoT(), Cert, tls[0].Cert, "tls cert not expect")
assert.Len(GinkgoT(), tls[0].Certificates, 1, "length of certificates not expect")
assert.Equal(GinkgoT(), Cert, tls[0].Certificates[0].Certificate, "tls cert not expect")
assert.Equal(GinkgoT(), tls[0].Labels["k8s/controller-name"], "apisix.apache.org/apisix-ingress-controller")

By("update secret")
Expand All @@ -289,7 +293,10 @@ spec:
if len(tls) < 1 {
return ""
}
return tls[0].Cert
if len(tls[0].Certificates) < 1 {
return ""
}
return tls[0].Certificates[0].Certificate
}).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(framework.TestCert))
})
})
Expand Down
3 changes: 2 additions & 1 deletion test/e2e/ingress/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ spec:
tls, err := s.DefaultDataplaneResource().SSL().List(context.Background())
assert.Nil(GinkgoT(), err, "list tls error")
assert.Len(GinkgoT(), tls, 1, "tls number not expect")
assert.Equal(GinkgoT(), Cert, tls[0].Cert, "tls cert not expect")
assert.Len(GinkgoT(), tls[0].Certificates, 1, "length of certificates not expect")
assert.Equal(GinkgoT(), Cert, tls[0].Certificates[0].Certificate, "tls cert not expect")
assert.ElementsMatch(GinkgoT(), []string{host}, tls[0].Snis)
})
})
Expand Down
226 changes: 226 additions & 0 deletions test/e2e/scaffold/adc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
// Licensed 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 scaffold

import (
"bytes"
"context"
"errors"
"os"
"os/exec"
"time"

"github.com/api7/gopkg/pkg/log"
"go.uber.org/zap"
"gopkg.in/yaml.v3"

adctypes "github.com/apache/apisix-ingress-controller/api/adc"
"github.com/apache/apisix-ingress-controller/internal/provider/adc/translator"
)

// DataplaneResource defines the interface for accessing dataplane resources
type DataplaneResource interface {
Route() RouteResource
Service() ServiceResource
SSL() SSLResource
Consumer() ConsumerResource
}

// RouteResource defines the interface for route resources
type RouteResource interface {
List(ctx context.Context) ([]*adctypes.Route, error)
}

// ServiceResource defines the interface for service resources
type ServiceResource interface {
List(ctx context.Context) ([]*adctypes.Service, error)
}

// SSLResource defines the interface for SSL resources
type SSLResource interface {
List(ctx context.Context) ([]*adctypes.SSL, error)
}

// ConsumerResource defines the interface for consumer resources
type ConsumerResource interface {
List(ctx context.Context) ([]*adctypes.Consumer, error)
}

// adcDataplaneResource implements DataplaneResource using ADC command
type adcDataplaneResource struct {
backend string
serverAddr string
token string
tlsVerify bool
syncTimeout time.Duration
}

// newADCDataplaneResource creates a new ADC-based dataplane resource
func newADCDataplaneResource(backend, serverAddr, token string, tlsVerify bool) DataplaneResource {
return &adcDataplaneResource{
backend: backend,
serverAddr: serverAddr,
token: token,
tlsVerify: tlsVerify,
syncTimeout: 30 * time.Second,
}
}

func (a *adcDataplaneResource) Route() RouteResource {
return &adcRouteResource{a}
}

func (a *adcDataplaneResource) Service() ServiceResource {
return &adcServiceResource{a}
}

func (a *adcDataplaneResource) SSL() SSLResource {
return &adcSSLResource{a}
}

func (a *adcDataplaneResource) Consumer() ConsumerResource {
return &adcConsumerResource{a}
}

func init() {
// dashboard sdk log
l, err := log.NewLogger(
log.WithOutputFile("stderr"),
log.WithLogLevel("debug"),
log.WithSkipFrames(3),
)
if err != nil {
panic(err)
}
log.DefaultLogger = l
}

// dumpResources executes adc dump command and returns the resources
func (a *adcDataplaneResource) dumpResources(ctx context.Context) (*translator.TranslateResult, error) {
ctxWithTimeout, cancel := context.WithTimeout(ctx, a.syncTimeout)
defer cancel()

args := []string{"dump", "-o", "/tmp/dump.yaml"}
if !a.tlsVerify {
args = append(args, "--tls-skip-verify")
}

adcEnv := []string{
"ADC_RUNNING_MODE=", // need to set empty
"ADC_BACKEND=" + a.backend,
"ADC_SERVER=" + a.serverAddr,
"ADC_TOKEN=" + a.token,
}

var stdout, stderr bytes.Buffer
cmd := exec.CommandContext(ctxWithTimeout, "adc", args...)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmd.Env = append(cmd.Env, os.Environ()...)
cmd.Env = append(cmd.Env, adcEnv...)

log.Debug("running adc command", zap.String("command", cmd.String()), zap.Strings("env", adcEnv))

if err := cmd.Run(); err != nil {
stderrStr := stderr.String()
stdoutStr := stdout.String()
errMsg := stderrStr
if errMsg == "" {
errMsg = stdoutStr
}
log.Errorw("failed to run adc",
zap.Error(err),
zap.String("output", stdoutStr),
zap.String("stderr", stderrStr),
)
return nil, errors.New("failed to dump resources: " + errMsg + ", exit err: " + err.Error())
}

// Read the YAML file that was created by adc dump
yamlData, err := os.ReadFile("/tmp/dump.yaml")
if err != nil {
return nil, err
}

var resources adctypes.Resources
if err := yaml.Unmarshal(yamlData, &resources); err != nil {
return nil, err
}

// Extract routes from services
var routes []*adctypes.Route
for _, service := range resources.Services {
routes = append(routes, service.Routes...)
}

return &translator.TranslateResult{
Routes: routes,
Services: resources.Services,
SSL: resources.SSLs,
GlobalRules: resources.GlobalRules,
PluginMetadata: resources.PluginMetadata,
Consumers: resources.Consumers,
}, nil
}

// adcRouteResource implements RouteResource
type adcRouteResource struct {
*adcDataplaneResource
}

func (r *adcRouteResource) List(ctx context.Context) ([]*adctypes.Route, error) {
result, err := r.dumpResources(ctx)
if err != nil {
return nil, err
}
return result.Routes, nil
}

// adcServiceResource implements ServiceResource
type adcServiceResource struct {
*adcDataplaneResource
}

func (s *adcServiceResource) List(ctx context.Context) ([]*adctypes.Service, error) {
result, err := s.dumpResources(ctx)
if err != nil {
return nil, err
}
return result.Services, nil
}

// adcSSLResource implements SSLResource
type adcSSLResource struct {
*adcDataplaneResource
}

func (s *adcSSLResource) List(ctx context.Context) ([]*adctypes.SSL, error) {
result, err := s.dumpResources(ctx)
if err != nil {
return nil, err
}
return result.SSL, nil
}

// adcConsumerResource implements ConsumerResource
type adcConsumerResource struct {
*adcDataplaneResource
}

func (c *adcConsumerResource) List(ctx context.Context) ([]*adctypes.Consumer, error) {
result, err := c.dumpResources(ctx)
if err != nil {
return nil, err
}
return result.Consumers, nil
}
Loading
Loading