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

kvn 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 8006297  chore: use kind to run e2e test suites (#331)
8006297 is described below

commit 80062976ab9bed2c147f1ad7812a003af02e96ff
Author: Alex Zhang <[email protected]>
AuthorDate: Thu Apr 1 22:05:04 2021 +0800

    chore: use kind to run e2e test suites (#331)
    
    * chore: use kind to run e2e test suites
    
    * fix
    
    * fix: license check failure
---
 .github/workflows/e2e-test-ci.yml | 19 +++------
 Makefile                          | 64 +++++++++++++++++++++--------
 test/e2e/README.md                | 16 +++++++-
 test/e2e/scaffold/apisix.go       | 63 +---------------------------
 test/e2e/scaffold/etcd.go         |  2 +-
 test/e2e/scaffold/httpbin.go      |  2 +-
 test/e2e/scaffold/ingress.go      |  8 ++--
 test/e2e/scaffold/k8s.go          | 76 ++++++++++++++++++++++------------
 test/e2e/scaffold/scaffold.go     | 22 +++++-----
 utils/kind-with-registry.sh       | 86 +++++++++++++++++++++++++++++++++++++++
 10 files changed, 219 insertions(+), 139 deletions(-)

diff --git a/.github/workflows/e2e-test-ci.yml 
b/.github/workflows/e2e-test-ci.yml
index ebe21ab..d6f093e 100644
--- a/.github/workflows/e2e-test-ci.yml
+++ b/.github/workflows/e2e-test-ci.yml
@@ -7,25 +7,16 @@ on:
   pull_request:
     branches:
       - master
-      - ci/e2e
 jobs:
   e2e-test:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
-      - name: Install minikube
+      - name: Install kind
         run: |
-          sh ./utils/minikube.sh
-      - name: Output cluster info
-        run: kubectl cluster-info
-      - name: Add images
-        run: |
-          IMAGE_TAG=dev make build-image-to-minikube
-          eval $(minikube docker-env)
-          docker pull apache/apisix:dev
-          docker pull bitnami/etcd:3.4.14-debian-10-r0
-          docker pull kennethreitz/httpbin
-          docker images
+          curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.10.0/kind-linux-amd64
+          chmod +x ./kind
+          sudo mv kind /usr/local/bin
       - name: Setup Go Env
         uses: actions/setup-go@v1
         with:
@@ -37,7 +28,7 @@ jobs:
       - name: Run e2e test cases
         working-directory: ./
         run: |
-          make e2e-test E2E_SKIP_BUILD=1 E2E_CONCURRENCY=1
+          make e2e-test E2E_CONCURRENCY=2
       - name: upload coverage profile
         working-directory: ./test/e2e
         run: |
diff --git a/Makefile b/Makefile
index bb04c5e..0313bbd 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,7 @@ default: help
 
 VERSION ?= 0.4.0
 RELEASE_SRC = apache-apisix-ingress-controller-${VERSION}-src
+LOCAL_REGISTRY="localhost:5000"
 IMAGE_TAG ?= dev
 
 GINKGO ?= $(shell which ginkgo)
@@ -36,31 +37,37 @@ GO_LDFLAGS ?= "-X=$(VERSYM)=$(VERSION) 
-X=$(GITSHASYM)=$(GITSHA) -X=$(BUILDOSSYM
 E2E_CONCURRENCY ?= 1
 E2E_SKIP_BUILD ?= 0
 
-### build:            Build apisix-ingress-controller
+### build:                Build apisix-ingress-controller
+.PHONY: build
 build:
        go build \
                -o apisix-ingress-controller \
                -ldflags $(GO_LDFLAGS) \
                main.go
 
-### build-image:      Build apisix-ingress-controller image
+### build-image:          Build apisix-ingress-controller image
+.PHONY: build-image
 build-image:
        docker build -t apache/apisix-ingress-controller:$(IMAGE_TAG) .
 
-### lint:             Do static lint check
+### lint:                 Do static lint check
+.PHONY: lint
 lint:
        golangci-lint run
 
-### gofmt:            Format all go codes
+### gofmt:                Format all go codes
+.PHONY: gofmt
 gofmt:
        find . -type f -name "*.go" | xargs gofmt -w -s
 
-### unit-test:        Run unit test cases
+### unit-test:            Run unit test cases
+.PHONY: unit-test
 unit-test:
        go test -cover -coverprofile=coverage.txt ./...
 
-### e2e-test:         Run e2e test cases (minikube is required)
-e2e-test: ginkgo-check build-image-to-minikube
+### e2e-test:             Run e2e test cases (kind is required)
+.PHONY: e2e-test
+e2e-test: ginkgo-check push-images-to-kind
        kubectl apply -f $(PWD)/samples/deploy/crd/v1beta1/ApisixRoute.yaml
        kubectl apply -f $(PWD)/samples/deploy/crd/v1beta1/ApisixUpstream.yaml
        kubectl apply -f $(PWD)/samples/deploy/crd/v1beta1/ApisixTls.yaml
@@ -73,16 +80,38 @@ ifeq ("$(wildcard $(GINKGO))", "")
        exit 1
 endif
 
-# build images to minikube node directly, it's an internal directive, so don't
-# expose it's help message.
-build-image-to-minikube:
+### push-images-to-kind:  Push images used in e2e test suites to kind.
+.PHONY: push-images-to-kind
+push-images-to-kind: kind-up
 ifeq ($(E2E_SKIP_BUILD), 0)
-       @minikube version > /dev/null 2>&1 || (echo "ERROR: minikube is 
required."; exit 1)
-       @eval $$(minikube docker-env);\
+       docker pull apache/apisix:dev
+       docker tag apache/apisix:dev $(LOCAL_REGISTRY)/apache/apisix:dev
+       docker push $(LOCAL_REGISTRY)/apache/apisix:dev
+
+       docker pull bitnami/etcd:3.4.14-debian-10-r0
+       docker tag bitnami/etcd:3.4.14-debian-10-r0 
$(LOCAL_REGISTRY)/bitnami/etcd:3.4.14-debian-10-r0
+       docker push $(LOCAL_REGISTRY)/bitnami/etcd:3.4.14-debian-10-r0
+
+       docker pull kennethreitz/httpbin
+       docker tag kennethreitz/httpbin $(LOCAL_REGISTRY)/kennethreitz/httpbin
+       docker push $(LOCAL_REGISTRY)/kennethreitz/httpbin
+
        docker build -t apache/apisix-ingress-controller:$(IMAGE_TAG) .
+       docker tag apache/apisix-ingress-controller:$(IMAGE_TAG) 
$(LOCAL_REGISTRY)/apache/apisix-ingress-controller:$(IMAGE_TAG)
+       docker push 
$(LOCAL_REGISTRY)/apache/apisix-ingress-controller:$(IMAGE_TAG)
 endif
 
-### license-check:    Do Apache License Header check
+### kind-up:              Launch a Kubernetes cluster with a image registry by 
Kind.
+.PHONY: kind-up
+kind-up:
+       ./utils/kind-with-registry.sh
+### kind-reset:           Delete the Kubernetes cluster created by "make 
kind-up"
+.PHONY: kind-reset
+kind-reset:
+       kind delete cluster --name apisix
+
+### license-check:        Do Apache License Header check
+.PHONY: license-check
 license-check:
 ifeq ("$(wildcard .actions/openwhisk-utilities/scancode/scanCode.py)", "")
        git clone https://github.com/apache/openwhisk-utilities.git 
.actions/openwhisk-utilities
@@ -90,13 +119,15 @@ ifeq ("$(wildcard 
.actions/openwhisk-utilities/scancode/scanCode.py)", "")
 endif
        .actions/openwhisk-utilities/scancode/scanCode.py --config 
.actions/ASF-Release.cfg ./
 
-### help:             Show Makefile rules
+### help:                 Show Makefile rules
+.PHONY: help
 help:
        @echo Makefile rules:
        @echo
        @grep -E '^### [-A-Za-z0-9_]+:' Makefile | sed 's/###/   /'
 
-### release-src:      Release source
+### release-src:          Release source
+.PHONY: release-src
 release-src:
        tar -zcvf $(RELEASE_SRC).tgz \
        --exclude .github \
@@ -118,6 +149,3 @@ release-src:
        mv $(RELEASE_SRC).tgz release/$(RELEASE_SRC).tgz
        mv $(RELEASE_SRC).tgz.asc release/$(RELEASE_SRC).tgz.asc
        mv $(RELEASE_SRC).tgz.sha512 release/$(RELEASE_SRC).tgz.sha512
-
-.PHONY: build lint help
-
diff --git a/test/e2e/README.md b/test/e2e/README.md
index bc35f93..c986b7a 100644
--- a/test/e2e/README.md
+++ b/test/e2e/README.md
@@ -20,8 +20,6 @@
 apisix ingress controller e2e test suites
 =========================================
 
-For running e2e test cases, a Kubernetes cluster is required, 
[minikube](https://minikube.sigs.k8s.io/docs/start/) is a good choice to build 
k8s cluster in development environment.
-
 Scaffold
 ---------
 
@@ -44,3 +42,17 @@ Features
 --------
 
 Test caes inside `features` directory test some features about APISIX, such as 
traffic-split, health check and so on.
+
+Quick Start
+-----------
+
+Run `make e2e-test` to run the e2e test suites in your development 
environment, a several stuffs that this command will do:
+
+1. Create a Kubernetes cluster by [kind](https://kind.sigs.k8s.io/), please 
installing in advance.
+2. Build and push all related images to this cluster.
+3. Run e2e test suites.
+
+Step `1` and `2` can be skipped by passing `E2E_SKIP_BUILD=1` to this 
directive, also, you can customize the
+running concurrency of e2e test suites by passing `E2E_CONCURRENCY=X` where 
`X` is the desired number of cases running in parallel.
+
+Run `make kind-reset` to delete the cluster that created by `make e2e-test`.
diff --git a/test/e2e/scaffold/apisix.go b/test/e2e/scaffold/apisix.go
index f4448fe..5719f45 100644
--- a/test/e2e/scaffold/apisix.go
+++ b/test/e2e/scaffold/apisix.go
@@ -15,10 +15,7 @@
 package scaffold
 
 import (
-       "errors"
        "fmt"
-       "net"
-       "strconv"
        "strings"
 
        "github.com/gruntwork-io/terratest/modules/k8s"
@@ -77,7 +74,7 @@ spec:
             tcpSocket:
               port: 9080
             timeoutSeconds: 2
-          image: "apache/apisix:dev"
+          image: "localhost:5000/apache/apisix:dev"
           imagePullPolicy: IfNotPresent
           name: apisix-deployment-e2e-test
           ports:
@@ -127,63 +124,6 @@ spec:
 `
 )
 
-func (s *Scaffold) apisixServiceURL() (string, error) {
-       if len(s.nodes) == 0 {
-               return "", errors.New("no available node")
-       }
-       var addr string
-       for _, node := range s.nodes {
-               if len(node.Status.Addresses) > 0 {
-                       addr = node.Status.Addresses[0].Address
-                       break
-               }
-       }
-       for _, port := range s.apisixService.Spec.Ports {
-               if port.Name == "http" {
-                       return net.JoinHostPort(addr, 
strconv.Itoa(int(port.NodePort))), nil
-               }
-       }
-       return "", errors.New("no http port in apisix service")
-}
-
-func (s *Scaffold) apisixServiceHttpsURL() (string, error) {
-       if len(s.nodes) == 0 {
-               return "", errors.New("no available node")
-       }
-       var addr string
-       for _, node := range s.nodes {
-               if len(node.Status.Addresses) > 0 {
-                       addr = node.Status.Addresses[0].Address
-                       break
-               }
-       }
-       for _, port := range s.apisixService.Spec.Ports {
-               if port.Name == "https" {
-                       return net.JoinHostPort(addr, 
strconv.Itoa(int(port.NodePort))), nil
-               }
-       }
-       return "", errors.New("no https port defined in apisix service")
-}
-
-func (s *Scaffold) apisixAdminServiceURL() (string, error) {
-       if len(s.nodes) == 0 {
-               return "", errors.New("no available node")
-       }
-       var addr string
-       for _, node := range s.nodes {
-               if len(node.Status.Addresses) > 0 {
-                       addr = node.Status.Addresses[0].Address
-                       break
-               }
-       }
-       for _, port := range s.apisixService.Spec.Ports {
-               if port.Name == "http-admin" {
-                       return net.JoinHostPort(addr, 
strconv.Itoa(int(port.NodePort))), nil
-               }
-       }
-       return "", errors.New("no http-admin port in apisix admin service")
-}
-
 func (s *Scaffold) newAPISIX() (*corev1.Service, error) {
        defaultData, err := s.renderConfig(s.opts.APISIXDefaultConfigPath)
        if err != nil {
@@ -210,6 +150,7 @@ func (s *Scaffold) newAPISIX() (*corev1.Service, error) {
        if err != nil {
                return nil, err
        }
+
        return svc, nil
 }
 
diff --git a/test/e2e/scaffold/etcd.go b/test/e2e/scaffold/etcd.go
index de227e1..c0559bb 100644
--- a/test/e2e/scaffold/etcd.go
+++ b/test/e2e/scaffold/etcd.go
@@ -65,7 +65,7 @@ spec:
             tcpSocket:
               port: 2379
             timeoutSeconds: 2
-          image: "bitnami/etcd:3.4.14-debian-10-r0"
+          image: "localhost:5000/bitnami/etcd:3.4.14-debian-10-r0"
           imagePullPolicy: IfNotPresent
           name: etcd-deployment-e2e-test
           ports:
diff --git a/test/e2e/scaffold/httpbin.go b/test/e2e/scaffold/httpbin.go
index 41701d6..d9fd861 100644
--- a/test/e2e/scaffold/httpbin.go
+++ b/test/e2e/scaffold/httpbin.go
@@ -64,7 +64,7 @@ spec:
             tcpSocket:
               port: 80
             timeoutSeconds: 2
-          image: "kennethreitz/httpbin"
+          image: "localhost:5000/kennethreitz/httpbin"
           imagePullPolicy: IfNotPresent
           name: httpbin-deployment-e2e-test
           ports:
diff --git a/test/e2e/scaffold/ingress.go b/test/e2e/scaffold/ingress.go
index b3cb70f..67f9343 100644
--- a/test/e2e/scaffold/ingress.go
+++ b/test/e2e/scaffold/ingress.go
@@ -227,8 +227,8 @@ spec:
               valueFrom:
                 fieldRef:
                   fieldPath: metadata.name
-          image: "apache/apisix-ingress-controller:dev"
-          imagePullPolicy: Never
+          image: "localhost:5000/apache/apisix-ingress-controller:dev"
+          imagePullPolicy: Always
           name: ingress-apisix-controller-deployment-e2e-test
           ports:
             - containerPort: 8080
@@ -268,11 +268,11 @@ func (s *Scaffold) newIngressAPISIXController() error {
        if err := k8s.KubectlApplyFromStringE(s.t, s.kubectlOptions, crb); err 
!= nil {
                return err
        }
-       s.addFinializer(func() {
+       s.addFinalizers(func() {
                err := k8s.KubectlDeleteFromStringE(s.t, s.kubectlOptions, crb)
                assert.Nil(s.t, err, "deleting ClusterRoleBinding")
        })
-       s.addFinializer(func() {
+       s.addFinalizers(func() {
                err := k8s.KubectlDeleteFromStringE(s.t, s.kubectlOptions, cr)
                assert.Nil(s.t, err, "deleting ClusterRole")
        })
diff --git a/test/e2e/scaffold/k8s.go b/test/e2e/scaffold/k8s.go
index 0c3fec9..a87a55f 100644
--- a/test/e2e/scaffold/k8s.go
+++ b/test/e2e/scaffold/k8s.go
@@ -109,7 +109,7 @@ func (s *Scaffold) 
CreateResourceFromStringWithNamespace(yaml, namespace string)
        defer func() {
                s.kubectlOptions.Namespace = originalNamespace
        }()
-       s.addFinializer(func() {
+       s.addFinalizers(func() {
                originalNamespace := s.kubectlOptions.Namespace
                s.kubectlOptions.Namespace = namespace
                defer func() {
@@ -154,13 +154,9 @@ func ensureNumApisixCRDsCreated(url string, desired int) 
error {
 // EnsureNumApisixRoutesCreated waits until desired number of Routes are 
created in
 // APISIX cluster.
 func (s *Scaffold) EnsureNumApisixRoutesCreated(desired int) error {
-       host, err := s.apisixAdminServiceURL()
-       if err != nil {
-               return err
-       }
        u := url.URL{
                Scheme: "http",
-               Host:   host,
+               Host:   s.apisixAdminTunnel.Endpoint(),
                Path:   "/apisix/admin/routes",
        }
        return ensureNumApisixCRDsCreated(u.String(), desired)
@@ -169,13 +165,9 @@ func (s *Scaffold) EnsureNumApisixRoutesCreated(desired 
int) error {
 // EnsureNumApisixUpstreamsCreated waits until desired number of Upstreams are 
created in
 // APISIX cluster.
 func (s *Scaffold) EnsureNumApisixUpstreamsCreated(desired int) error {
-       host, err := s.apisixAdminServiceURL()
-       if err != nil {
-               return err
-       }
        u := url.URL{
                Scheme: "http",
-               Host:   host,
+               Host:   s.apisixAdminTunnel.Endpoint(),
                Path:   "/apisix/admin/upstreams",
        }
        return ensureNumApisixCRDsCreated(u.String(), desired)
@@ -183,13 +175,9 @@ func (s *Scaffold) EnsureNumApisixUpstreamsCreated(desired 
int) error {
 
 // ListApisixUpstreams list all upstreams from APISIX
 func (s *Scaffold) ListApisixUpstreams() ([]*v1.Upstream, error) {
-       host, err := s.apisixAdminServiceURL()
-       if err != nil {
-               return nil, err
-       }
        u := url.URL{
                Scheme: "http",
-               Host:   host,
+               Host:   s.apisixAdminTunnel.Endpoint(),
                Path:   "/apisix/admin",
        }
        cli, err := apisix.NewClient()
@@ -207,13 +195,9 @@ func (s *Scaffold) ListApisixUpstreams() ([]*v1.Upstream, 
error) {
 
 // ListApisixRoutes list all routes from APISIX.
 func (s *Scaffold) ListApisixRoutes() ([]*v1.Route, error) {
-       host, err := s.apisixAdminServiceURL()
-       if err != nil {
-               return nil, err
-       }
        u := url.URL{
                Scheme: "http",
-               Host:   host,
+               Host:   s.apisixAdminTunnel.Endpoint(),
                Path:   "/apisix/admin",
        }
        cli, err := apisix.NewClient()
@@ -231,13 +215,9 @@ func (s *Scaffold) ListApisixRoutes() ([]*v1.Route, error) 
{
 
 // ListApisixTls list all ssl from APISIX
 func (s *Scaffold) ListApisixTls() ([]*v1.Ssl, error) {
-       host, err := s.apisixAdminServiceURL()
-       if err != nil {
-               return nil, err
-       }
        u := url.URL{
                Scheme: "http",
-               Host:   host,
+               Host:   s.apisixAdminTunnel.Endpoint(),
                Path:   "/apisix/admin",
        }
        cli, err := apisix.NewClient()
@@ -252,3 +232,47 @@ func (s *Scaffold) ListApisixTls() ([]*v1.Ssl, error) {
        }
        return cli.Cluster("").SSL().List(context.TODO())
 }
+
+func (s *Scaffold) newAPISIXTunnels() error {
+       var (
+               adminNodePort int
+               httpNodePort  int
+               httpsNodePort int
+               adminPort     int
+               httpPort      int
+               httpsPort     int
+       )
+       for _, port := range s.apisixService.Spec.Ports {
+               if port.Name == "http" {
+                       httpNodePort = int(port.NodePort)
+                       httpPort = int(port.Port)
+               } else if port.Name == "https" {
+                       httpsNodePort = int(port.NodePort)
+                       httpsPort = int(port.Port)
+               } else if port.Name == "http-admin" {
+                       adminNodePort = int(port.NodePort)
+                       adminPort = int(port.Port)
+               }
+       }
+
+       s.apisixAdminTunnel = k8s.NewTunnel(s.kubectlOptions, 
k8s.ResourceTypeService, "apisix-service-e2e-test",
+               adminNodePort, adminPort)
+       s.apisixHttpTunnel = k8s.NewTunnel(s.kubectlOptions, 
k8s.ResourceTypeService, "apisix-service-e2e-test",
+               httpNodePort, httpPort)
+       s.apisixHttpsTunnel = k8s.NewTunnel(s.kubectlOptions, 
k8s.ResourceTypeService, "apisix-service-e2e-test",
+               httpsNodePort, httpsPort)
+
+       if err := s.apisixAdminTunnel.ForwardPortE(s.t); err != nil {
+               return err
+       }
+       s.addFinalizers(s.apisixAdminTunnel.Close)
+       if err := s.apisixHttpTunnel.ForwardPortE(s.t); err != nil {
+               return err
+       }
+       s.addFinalizers(s.apisixHttpTunnel.Close)
+       if err := s.apisixHttpsTunnel.ForwardPortE(s.t); err != nil {
+               return err
+       }
+       s.addFinalizers(s.apisixHttpsTunnel.Close)
+       return nil
+}
diff --git a/test/e2e/scaffold/scaffold.go b/test/e2e/scaffold/scaffold.go
index 7a9da7e..d64e07d 100644
--- a/test/e2e/scaffold/scaffold.go
+++ b/test/e2e/scaffold/scaffold.go
@@ -62,6 +62,10 @@ type Scaffold struct {
        httpbinService    *corev1.Service
        finializers       []func()
 
+       apisixAdminTunnel *k8s.Tunnel
+       apisixHttpTunnel  *k8s.Tunnel
+       apisixHttpsTunnel *k8s.Tunnel
+
        // Used for template rendering.
        EtcdServiceFQDN string
 }
@@ -137,18 +141,11 @@ func (s *Scaffold) DefaultHTTPBackend() (string, []int32) 
{
        return s.httpbinService.Name, ports
 }
 
-// GetAPISIXEndpoint returns the service and port (as an endpoint).
-func (s *Scaffold) GetAPISIXEndpoint() (string, error) {
-       return s.apisixServiceURL()
-}
-
 // NewAPISIXClient creates the default HTTP client.
 func (s *Scaffold) NewAPISIXClient() *httpexpect.Expect {
-       host, err := s.apisixServiceURL()
-       assert.Nil(s.t, err, "getting apisix service url")
        u := url.URL{
                Scheme: "http",
-               Host:   host,
+               Host:   s.apisixHttpTunnel.Endpoint(),
        }
        return httpexpect.WithConfig(httpexpect.Config{
                BaseURL: u.String(),
@@ -166,11 +163,9 @@ func (s *Scaffold) NewAPISIXClient() *httpexpect.Expect {
 
 // NewAPISIXHttpsClient creates the default HTTPs client.
 func (s *Scaffold) NewAPISIXHttpsClient() *httpexpect.Expect {
-       host, err := s.apisixServiceHttpsURL()
-       assert.Nil(s.t, err, "getting apisix service url")
        u := url.URL{
                Scheme: "https",
-               Host:   host,
+               Host:   s.apisixHttpsTunnel.Endpoint(),
        }
        return httpexpect.WithConfig(httpexpect.Config{
                BaseURL: u.String(),
@@ -213,6 +208,9 @@ func (s *Scaffold) beforeEach() {
        err = s.waitAllAPISIXPodsAvailable()
        assert.Nil(s.t, err, "waiting for apisix ready")
 
+       err = s.newAPISIXTunnels()
+       assert.Nil(s.t, err, "creating apisix tunnels")
+
        s.httpbinService, err = s.newHTTPBIN()
        assert.Nil(s.t, err, "initializing httpbin")
 
@@ -239,7 +237,7 @@ func (s *Scaffold) afterEach() {
        time.Sleep(3 * time.Second)
 }
 
-func (s *Scaffold) addFinializer(f func()) {
+func (s *Scaffold) addFinalizers(f func()) {
        s.finializers = append(s.finializers, f)
 }
 
diff --git a/utils/kind-with-registry.sh b/utils/kind-with-registry.sh
new file mode 100755
index 0000000..ea01a2c
--- /dev/null
+++ b/utils/kind-with-registry.sh
@@ -0,0 +1,86 @@
+#!/usr/bin/env bash
+#
+# 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.
+#
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+# desired cluster name; default is "apisix"
+KIND_CLUSTER_NAME="${KIND_CLUSTER_NAME:-apisix}"
+
+if kind get clusters | grep -q ^apisix$ ; then
+  echo "cluster already exists, moving on"
+  exit 0
+fi
+
+# create registry container unless it already exists
+kind_version=$(kind version)
+kind_network='kind'
+reg_name='kind-registry'
+reg_port='5000'
+case "${kind_version}" in
+  "kind v0.7."* | "kind v0.6."* | "kind v0.5."*)
+    kind_network='bridge'
+    ;;
+esac
+
+# create registry container unless it already exists
+running="$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || 
true)"
+if [ "${running}" != 'true' ]; then
+  docker run \
+    -d --restart=always -p "${reg_port}:5000" --name "${reg_name}" \
+    registry:2
+fi
+
+reg_host="${reg_name}"
+if [ "${kind_network}" = "bridge" ]; then
+    reg_host="$(docker inspect -f '{{.NetworkSettings.IPAddress}}' 
"${reg_name}")"
+fi
+echo "Registry Host: ${reg_host}"
+
+# create a cluster with the local registry enabled in containerd
+cat <<EOF | kind create cluster --name "${KIND_CLUSTER_NAME}" --config=-
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
+nodes:
+- role: control-plane
+- role: worker
+- role: worker
+- role: worker
+containerdConfigPatches:
+- |-
+  
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:${reg_port}"]
+    endpoint = ["http://${reg_host}:${reg_port}";]
+EOF
+
+for node in $(kind get nodes --name "${KIND_CLUSTER_NAME}"); do
+  kubectl annotate node "${node}" tilt.dev/registry=localhost:${reg_port};
+done
+
+if [ "${kind_network}" != "bridge" ]; then
+  containers=$(docker network inspect ${kind_network} -f "{{range 
.Containers}}{{.Name}} {{end}}")
+  needs_connect="true"
+  for c in $containers; do
+    if [ "$c" = "${reg_name}" ]; then
+      needs_connect="false"
+    fi
+  done
+  if [ "${needs_connect}" = "true" ]; then               
+    docker network connect "${kind_network}" "${reg_name}" || true
+  fi
+fi

Reply via email to