This is an automated email from the ASF dual-hosted git repository.
tokers 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 c6e7180 fix: pass remote_addrs to APISIX (#347)
c6e7180 is described below
commit c6e71803cca5470679ac0433753b361753e38783
Author: Alex Zhang <[email protected]>
AuthorDate: Sat Apr 10 11:21:35 2021 +0800
fix: pass remote_addrs to APISIX (#347)
---
pkg/apisix/resource.go | 44 +++++++-------
pkg/apisix/route.go | 70 +++++++++++-----------
pkg/kube/translation/apisix_route.go | 9 +++
pkg/kube/translation/util.go | 17 ++++++
pkg/kube/translation/util_test.go | 39 +++++++++++++
pkg/types/apisix/v1/types.go | 1 +
test/e2e/features/remote_addrs_match.go | 100 ++++++++++++++++++++++++++++++++
7 files changed, 226 insertions(+), 54 deletions(-)
diff --git a/pkg/apisix/resource.go b/pkg/apisix/resource.go
index 8808788..d5ea072 100644
--- a/pkg/apisix/resource.go
+++ b/pkg/apisix/resource.go
@@ -73,17 +73,18 @@ type item struct {
}
type routeItem struct {
- UpstreamId string `json:"upstream_id"`
- ServiceId string `json:"service_id"`
- Host string `json:"host"`
- Hosts []string `json:"hosts"`
- URI string `json:"uri"`
- Vars [][]v1.StringOrSlice `json:"vars"`
- Uris []string `json:"uris"`
- Desc string `json:"desc"`
- Methods []string `json:"methods"`
- Priority int `json:"priority"`
- Plugins map[string]interface{} `json:"plugins"`
+ UpstreamId string `json:"upstream_id"`
+ ServiceId string `json:"service_id"`
+ RemoteAddrs []string `json:"remote_addrs"`
+ Host string `json:"host"`
+ Hosts []string `json:"hosts"`
+ URI string `json:"uri"`
+ Vars [][]v1.StringOrSlice `json:"vars"`
+ Uris []string `json:"uris"`
+ Desc string `json:"desc"`
+ Methods []string `json:"methods"`
+ Priority int `json:"priority"`
+ Plugins map[string]interface{} `json:"plugins"`
}
// route decodes item.Value and converts it to v1.Route.
@@ -108,16 +109,17 @@ func (i *item) route(clusterName string) (*v1.Route,
error) {
Group: clusterName,
Name: route.Desc,
},
- Host: route.Host,
- Path: route.URI,
- Uris: route.Uris,
- Vars: route.Vars,
- Methods: route.Methods,
- UpstreamId: route.UpstreamId,
- ServiceId: route.ServiceId,
- Plugins: route.Plugins,
- Hosts: route.Hosts,
- Priority: route.Priority,
+ Host: route.Host,
+ Path: route.URI,
+ Uris: route.Uris,
+ Vars: route.Vars,
+ Methods: route.Methods,
+ RemoteAddrs: route.RemoteAddrs,
+ UpstreamId: route.UpstreamId,
+ ServiceId: route.ServiceId,
+ Plugins: route.Plugins,
+ Hosts: route.Hosts,
+ Priority: route.Priority,
}, nil
}
diff --git a/pkg/apisix/route.go b/pkg/apisix/route.go
index 70c4f35..7d87754 100644
--- a/pkg/apisix/route.go
+++ b/pkg/apisix/route.go
@@ -29,17 +29,18 @@ import (
)
type routeReqBody struct {
- Desc string `json:"desc,omitempty"`
- Name string `json:"name,omitempty"`
- URI string `json:"uri,omitempty"`
- Priority int `json:"priority,omitempty"`
- Uris []string `json:"uris,omitempty"`
- Vars [][]v1.StringOrSlice `json:"vars,omitempty"`
- Host string `json:"host,omitempty"`
- Hosts []string `json:"hosts,omitempty"`
- ServiceId string `json:"service_id,omitempty"`
- UpstreamId string `json:"upstream_id,omitempty"`
- Plugins v1.Plugins `json:"plugins,omitempty"`
+ Desc string `json:"desc,omitempty"`
+ Name string `json:"name,omitempty"`
+ URI string `json:"uri,omitempty"`
+ Priority int `json:"priority,omitempty"`
+ Uris []string `json:"uris,omitempty"`
+ Vars [][]v1.StringOrSlice `json:"vars,omitempty"`
+ Host string `json:"host,omitempty"`
+ Hosts []string `json:"hosts,omitempty"`
+ ServiceId string `json:"service_id,omitempty"`
+ RemoteAddrs []string `json:"remote_addrs,omitempty"`
+ UpstreamId string `json:"upstream_id,omitempty"`
+ Plugins v1.Plugins `json:"plugins,omitempty"`
}
type routeClient struct {
@@ -162,17 +163,18 @@ func (r *routeClient) Create(ctx context.Context, obj
*v1.Route) (*v1.Route, err
return nil, err
}
data, err := json.Marshal(routeReqBody{
- Priority: obj.Priority,
- Desc: obj.Name,
- Name: obj.Name,
- URI: obj.Path,
- Host: obj.Host,
- Hosts: obj.Hosts,
- ServiceId: obj.ServiceId,
- UpstreamId: obj.UpstreamId,
- Uris: obj.Uris,
- Plugins: obj.Plugins,
- Vars: obj.Vars,
+ Priority: obj.Priority,
+ Desc: obj.Name,
+ Name: obj.Name,
+ URI: obj.Path,
+ Host: obj.Host,
+ Hosts: obj.Hosts,
+ ServiceId: obj.ServiceId,
+ UpstreamId: obj.UpstreamId,
+ Uris: obj.Uris,
+ Plugins: obj.Plugins,
+ Vars: obj.Vars,
+ RemoteAddrs: obj.RemoteAddrs,
})
if err != nil {
return nil, err
@@ -232,18 +234,20 @@ func (r *routeClient) Update(ctx context.Context, obj
*v1.Route) (*v1.Route, err
if err := r.cluster.HasSynced(ctx); err != nil {
return nil, err
}
+ // FIXME use unified v1.Route, removing routeReqBody.
body, err := json.Marshal(routeReqBody{
- Priority: obj.Priority,
- Desc: obj.Name,
- Name: obj.Name,
- URI: obj.Path,
- Host: obj.Host,
- Hosts: obj.Hosts,
- ServiceId: obj.ServiceId,
- UpstreamId: obj.UpstreamId,
- Uris: obj.Uris,
- Plugins: obj.Plugins,
- Vars: obj.Vars,
+ Priority: obj.Priority,
+ Desc: obj.Name,
+ Name: obj.Name,
+ URI: obj.Path,
+ Host: obj.Host,
+ Hosts: obj.Hosts,
+ ServiceId: obj.ServiceId,
+ UpstreamId: obj.UpstreamId,
+ Uris: obj.Uris,
+ Plugins: obj.Plugins,
+ Vars: obj.Vars,
+ RemoteAddrs: obj.RemoteAddrs,
})
if err != nil {
return nil, err
diff --git a/pkg/kube/translation/apisix_route.go
b/pkg/kube/translation/apisix_route.go
index 6914293..6336455 100644
--- a/pkg/kube/translation/apisix_route.go
+++ b/pkg/kube/translation/apisix_route.go
@@ -165,6 +165,14 @@ func (t *translator) TranslateRouteV2alpha1(ar
*configv2alpha1.ApisixRoute) ([]*
return nil, nil, err
}
}
+ if err := validateRemoteAddrs(part.Match.RemoteAddrs); err !=
nil {
+ log.Errorw("ApisixRoute with invalid remote addrs",
+ zap.Error(err),
+ zap.Strings("remote_addrs",
part.Match.RemoteAddrs),
+ zap.Any("ApisixRoute", ar),
+ )
+ return nil, nil, err
+ }
routeName := apisixv1.ComposeRouteName(ar.Namespace, ar.Name,
part.Name)
upstreamName := apisixv1.ComposeUpstreamName(ar.Namespace,
backend.ServiceName, svcPort)
@@ -177,6 +185,7 @@ func (t *translator) TranslateRouteV2alpha1(ar
*configv2alpha1.ApisixRoute) ([]*
ResourceVersion: ar.ResourceVersion,
},
Priority: part.Priority,
+ RemoteAddrs: part.Match.RemoteAddrs,
Vars: exprs,
Hosts: part.Match.Hosts,
Uris: part.Match.Paths,
diff --git a/pkg/kube/translation/util.go b/pkg/kube/translation/util.go
index 3584dae..a66b7dd 100644
--- a/pkg/kube/translation/util.go
+++ b/pkg/kube/translation/util.go
@@ -16,6 +16,7 @@ package translation
import (
"errors"
+ "net"
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/util/intstr"
@@ -26,6 +27,10 @@ import (
apisixv1
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
)
+var (
+ _errInvalidAddress = errors.New("address is neither IP or CIDR")
+)
+
func (t *translator) getServiceClusterIPAndPort(backend
*configv2alpha1.ApisixRouteHTTPBackend, ar *configv2alpha1.ApisixRoute)
(string, int32, error) {
svc, err :=
t.ServiceLister.Services(ar.Namespace).Get(backend.ServiceName)
if err != nil {
@@ -84,3 +89,15 @@ func (t *translator) translateUpstream(namespace, svcName,
svcResolveGranularity
ups.ID = id.GenID(ups.FullName)
return ups, nil
}
+
+func validateRemoteAddrs(remoteAddrs []string) error {
+ for _, addr := range remoteAddrs {
+ if ip := net.ParseIP(addr); ip == nil {
+ // addr is not an IP address, try to parse it as a CIDR.
+ if _, _, err := net.ParseCIDR(addr); err != nil {
+ return _errInvalidAddress
+ }
+ }
+ }
+ return nil
+}
diff --git a/pkg/kube/translation/util_test.go
b/pkg/kube/translation/util_test.go
new file mode 100644
index 0000000..f990a4d
--- /dev/null
+++ b/pkg/kube/translation/util_test.go
@@ -0,0 +1,39 @@
+// 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 translation
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestValidateRemoteAddrs(t *testing.T) {
+ addrs := []string{
+ "192.168.3.4",
+ "192.168.3.3/16",
+ "123",
+ }
+ err := validateRemoteAddrs(addrs)
+ assert.Equal(t, err, _errInvalidAddress)
+
+ addrs = []string{
+ "192.168.3.4",
+ "192.168.3.3/16",
+ "2001:db8::68",
+ "2001:db8:a0b:12f0::1/32",
+ }
+ assert.Nil(t, validateRemoteAddrs(addrs))
+}
diff --git a/pkg/types/apisix/v1/types.go b/pkg/types/apisix/v1/types.go
index 3650a0b..f314689 100644
--- a/pkg/types/apisix/v1/types.go
+++ b/pkg/types/apisix/v1/types.go
@@ -89,6 +89,7 @@ type Route struct {
Vars [][]StringOrSlice `json:"vars,omitempty"
yaml:"vars,omitempty"`
Uris []string `json:"uris,omitempty"
yaml:"uris,omitempty"`
Methods []string `json:"methods,omitempty"
yaml:"methods,omitempty"`
+ RemoteAddrs []string `json:"remote_addrs,omitempty"
yaml:"remote_addrs,omitempty"`
ServiceId string `json:"service_id,omitempty"
yaml:"service_id,omitempty"`
ServiceName string `json:"service_name,omitempty"
yaml:"service_name,omitempty"`
UpstreamId string `json:"upstream_id,omitempty"
yaml:"upstream_id,omitempty"`
diff --git a/test/e2e/features/remote_addrs_match.go
b/test/e2e/features/remote_addrs_match.go
new file mode 100644
index 0000000..f804e33
--- /dev/null
+++ b/test/e2e/features/remote_addrs_match.go
@@ -0,0 +1,100 @@
+// 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 features
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+ "github.com/onsi/ginkgo"
+ "github.com/stretchr/testify/assert"
+)
+
+var _ = ginkgo.Describe("traffic split", func() {
+ opts := &scaffold.Options{
+ Name: "default",
+ Kubeconfig: scaffold.GetKubeconfig(),
+ APISIXConfigPath: "testdata/apisix-gw-config.yaml",
+ APISIXDefaultConfigPath:
"testdata/apisix-gw-config-default.yaml",
+ IngressAPISIXReplicas: 1,
+ HTTPBinServicePort: 80,
+ APISIXRouteVersion: "apisix.apache.org/v2alpha1",
+ }
+ s := scaffold.NewScaffold(opts)
+ ginkgo.It("sanity", func() {
+ backendSvc, backendPorts := s.DefaultHTTPBackend()
+ ar := fmt.Sprintf(`
+apiVersion: apisix.apache.org/v2alpha1
+kind: ApisixRoute
+metadata:
+ name: httpbin-route
+spec:
+ http:
+ - name: rule1
+ match:
+ hosts:
+ - httpbin.org
+ paths:
+ - /ip
+ remoteAddrs:
+ - "10.0.5.0/8"
+ backends:
+ - serviceName: %s
+ servicePort: %d
+`, backendSvc, backendPorts[0])
+ assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(ar))
+
+ err := s.EnsureNumApisixUpstreamsCreated(1)
+ assert.Nil(ginkgo.GinkgoT(), err, "Checking number of
upstreams")
+ err = s.EnsureNumApisixRoutesCreated(1)
+ assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes")
+
+ resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host",
"httpbin.org").Expect()
+ resp.Status(http.StatusNotFound)
+ resp.Body().Contains("404 Route Not Found")
+
+ ar = fmt.Sprintf(`
+apiVersion: apisix.apache.org/v2alpha1
+kind: ApisixRoute
+metadata:
+ name: httpbin-route
+spec:
+ http:
+ - name: rule1
+ match:
+ hosts:
+ - httpbin.org
+ paths:
+ - /ip
+ remoteAddrs:
+ - "127.0.0.1"
+ backends:
+ - serviceName: %s
+ servicePort: %d
+`, backendSvc, backendPorts[0])
+
+ assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(ar))
+
+ err = s.EnsureNumApisixUpstreamsCreated(1)
+ assert.Nil(ginkgo.GinkgoT(), err, "Checking number of
upstreams")
+ err = s.EnsureNumApisixRoutesCreated(1)
+ assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes")
+
+ resp = s.NewAPISIXClient().GET("/ip").WithHeader("Host",
"httpbin.org").Expect()
+ resp.Status(http.StatusOK)
+ resp.Body().Contains("origin")
+ })
+})