Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support variable in ApisixRoute exprs scope #1466

Merged
merged 2 commits into from
Nov 19, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions pkg/kube/apisix/const/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,6 @@ const (
ScopePath = "Path"
// ScopeCookie means the route match expression subject is in cookie.
ScopeCookie = "Cookie"
// ScopeVariable means the route match expression subject is in variable.
ScopeVariable = "Variable"
)
16 changes: 6 additions & 10 deletions pkg/providers/apisix/translation/apisix_route.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,8 @@ func (t *translator) TranslateRouteMatchExprs(nginxVars []configv2.ApisixRouteHT
subj = "cookie_" + expr.Subject.Name
case _const.ScopePath:
subj = "uri"
case _const.ScopeVariable:
subj = expr.Subject.Name
default:
return nil, errors.New("bad subject name")
}
Expand All @@ -504,20 +506,14 @@ func (t *translator) TranslateRouteMatchExprs(nginxVars []configv2.ApisixRouteHT
op = "=="
case _const.OpGreaterThan:
op = ">"
// TODO Implement "<=", ">=" operators after the
// lua-resty-expr supports it. See
// https://github.com/api7/lua-resty-expr/issues/28
// for details.
//case configv2alpha1.OpGreaterThanEqual:
// invert = true
// op = "<"
case _const.OpGreaterThanEqual:
op = ">="
case _const.OpIn:
op = "in"
case _const.OpLessThan:
op = "<"
//case configv2alpha1.OpLessThanEqual:
// invert = true
// op = ">"
case _const.OpLessThanEqual:
op = "<="
case _const.OpNotEqual:
op = "~="
case _const.OpNotIn:
Expand Down
3 changes: 3 additions & 0 deletions samples/deploy/crd/v1/ApisixRoute.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ spec:
- "Header"
- "Path"
- "Query"
- "Variable"
name:
type: string
minLength: 1
Expand All @@ -431,7 +432,9 @@ spec:
- Equal
- NotEqual
- GreaterThan
- GreaterThanEqual
- LessThan
- LessThanEqual
- In
- NotIn
- RegexMatch
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/scaffold/scaffold.go
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,10 @@ func (s *Scaffold) CreateVersionedApisixResourceWithNamespace(yml, namespace str
return fmt.Errorf("the resource %s does not support", kindValue)
}

func (s *Scaffold) ApisixResourceVersion() string {
return s.opts.ApisixResourceVersion
}

func ApisixResourceVersion() *apisixResourceVersionInfo {
return apisixResourceVersion
}
Expand Down
299 changes: 299 additions & 0 deletions test/e2e/suite-features/route_match_exprs.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,75 @@ spec:
assert.Contains(ginkgo.GinkgoT(), msg, "404 Route Not Found")
})

ginkgo.It("operator is GreaterThanEqual", func() {
if s.ApisixResourceVersion() == scaffold.ApisixResourceVersion().V2beta3 {
ginkgo.Skip("Not support ApisixRoute v2beta3")
}

backendSvc, backendPorts := s.DefaultHTTPBackend()

ar := fmt.Sprintf(`
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: httpbin-route
spec:
http:
- name: rule1
match:
hosts:
- httpbin.org
paths:
- /ip
exprs:
- subject:
scope: Query
name: id
op: GreaterThanEqual
value: "13"
backends:
- serviceName: %s
servicePort: %d
`, backendSvc, backendPorts[0])

assert.Nil(ginkgo.GinkgoT(), s.CreateVersionedApisixResource(ar))

time.Sleep(6 * time.Second)
err := s.EnsureNumApisixRoutesCreated(1)
assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes")
err = s.EnsureNumApisixUpstreamsCreated(1)
assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams")

_ = s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.org").
WithQuery("id", 100).
Expect().
Status(http.StatusOK)

_ = s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.org").
WithQuery("id", 13).
Expect().
Status(http.StatusOK)

msg := s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.org").
WithQuery("id", 10).
Expect().
Status(http.StatusNotFound).
Body().
Raw()
assert.Contains(ginkgo.GinkgoT(), msg, "404 Route Not Found")

msg = s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.org").
Expect().
Status(http.StatusNotFound).
Body().
Raw()
assert.Contains(ginkgo.GinkgoT(), msg, "404 Route Not Found")
})

ginkgo.It("operator is less_than", func() {
backendSvc, backendPorts := s.DefaultHTTPBackend()

Expand Down Expand Up @@ -246,6 +315,75 @@ spec:
assert.Contains(ginkgo.GinkgoT(), msg, "404 Route Not Found")
})

ginkgo.It("operator is LessThanEqual", func() {
if s.ApisixResourceVersion() == scaffold.ApisixResourceVersion().V2beta3 {
ginkgo.Skip("Not support ApisixRoute v2beta3")
}

backendSvc, backendPorts := s.DefaultHTTPBackend()

ar := fmt.Sprintf(`
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: httpbin-route
spec:
http:
- name: rule1
match:
hosts:
- httpbin.org
paths:
- /ip
exprs:
- subject:
scope: Query
name: ID
op: LessThanEqual
value: "13"
backends:
- serviceName: %s
servicePort: %d
`, backendSvc, backendPorts[0])

assert.Nil(ginkgo.GinkgoT(), s.CreateVersionedApisixResource(ar))

time.Sleep(6 * time.Second)
err := s.EnsureNumApisixRoutesCreated(1)
assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes")
err = s.EnsureNumApisixUpstreamsCreated(1)
assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams")

_ = s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.org").
WithQuery("ID", 12).
Expect().
Status(http.StatusOK)

_ = s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.org").
WithQuery("ID", 13).
Expect().
Status(http.StatusOK)

msg := s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.org").
WithQuery("ID", 14).
Expect().
Status(http.StatusNotFound).
Body().
Raw()
assert.Contains(ginkgo.GinkgoT(), msg, "404 Route Not Found")

msg = s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.org").
Expect().
Status(http.StatusNotFound).
Body().
Raw()
assert.Contains(ginkgo.GinkgoT(), msg, "404 Route Not Found")
})

ginkgo.It("operator is in", func() {
backendSvc, backendPorts := s.DefaultHTTPBackend()

Expand Down Expand Up @@ -683,3 +821,164 @@ spec:
suites(scaffold.NewDefaultV2Scaffold)
})
})

var _ = ginkgo.Describe("suite-features: route match exprs with variable", func() {
s := scaffold.NewDefaultScaffold()
ginkgo.It("exprs with request_method variable", func() {
backendSvc, backendPorts := s.DefaultHTTPBackend()

ar := fmt.Sprintf(`
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: httpbin-route
spec:
http:
- name: rule1
match:
hosts:
- httpbin.org
paths:
- /get
- /post
- /put
exprs:
- subject:
scope: Variable
name: request_method
op: In
set:
- GET
- POST
backends:
- serviceName: %s
servicePort: %d
`, backendSvc, backendPorts[0])

assert.Nil(ginkgo.GinkgoT(), s.CreateVersionedApisixResource(ar), "creating route")
time.Sleep(6 * time.Second)
assert.Nil(ginkgo.GinkgoT(), s.EnsureNumApisixRoutesCreated(1), "Checking number of routes")

_ = s.NewAPISIXClient().GET("/get").
WithHeader("Host", "httpbin.org").
Expect().
Status(http.StatusOK)

_ = s.NewAPISIXClient().POST("/post").
WithHeader("Host", "httpbin.org").
Expect().
Status(http.StatusOK)

_ = s.NewAPISIXClient().PUT("/put").
WithHeader("Host", "httpbin.org").
Expect().
Status(http.StatusNotFound)
})

ginkgo.It("exprs with host variable", func() {
backendSvc, backendPorts := s.DefaultHTTPBackend()

ar := fmt.Sprintf(`
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: httpbin-route
spec:
http:
- name: rule1
match:
paths:
- /ip
exprs:
- subject:
scope: Variable
name: host
op: In
set:
- httpbin.net
- httpbin.org
- httpbin.com
backends:
- serviceName: %s
servicePort: %d
`, backendSvc, backendPorts[0])

assert.Nil(ginkgo.GinkgoT(), s.CreateVersionedApisixResource(ar), "creating route")
time.Sleep(6 * time.Second)
assert.Nil(ginkgo.GinkgoT(), s.EnsureNumApisixRoutesCreated(1), "Checking number of routes")

_ = s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.net").
Expect().
Status(http.StatusOK)

_ = s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.org").
Expect().
Status(http.StatusOK)

_ = s.NewAPISIXClient().GET("/ip").
WithHeader("Host", "httpbin.com").
Expect().
Status(http.StatusOK)
})

ginkgo.It("exprs request_method and host variable", func() {
backendSvc, backendPorts := s.DefaultHTTPBackend()

ar := fmt.Sprintf(`
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: httpbin-route
spec:
http:
- name: rule1
match:
paths:
- /*
exprs:
- subject:
scope: Variable
name: request_method
op: In
set:
- GET
- PUT
- subject:
scope: Variable
name: host
op: In
set:
- httpbin.org
- httpbin.com
backends:
- serviceName: %s
servicePort: %d
`, backendSvc, backendPorts[0])

assert.Nil(ginkgo.GinkgoT(), s.CreateVersionedApisixResource(ar), "creating route")
time.Sleep(6 * time.Second)
assert.Nil(ginkgo.GinkgoT(), s.EnsureNumApisixRoutesCreated(1), "Checking number of routes")

_ = s.NewAPISIXClient().GET("/get").
WithHeader("Host", "httpbin.net").
Expect().
Status(http.StatusNotFound)

_ = s.NewAPISIXClient().GET("/get").
WithHeader("Host", "httpbin.org").
Expect().
Status(http.StatusOK)

_ = s.NewAPISIXClient().POST("/post").
WithHeader("Host", "httpbin.org").
Expect().
Status(http.StatusNotFound)

_ = s.NewAPISIXClient().PUT("/put").
WithHeader("Host", "httpbin.com").
Expect().
Status(http.StatusOK)
})
})