Skip to content

feat: implement reconciler for apisixroute #164

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

Open
wants to merge 9 commits into
base: release-v2-dev
Choose a base branch
from
Open
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: 1 addition & 1 deletion api/v2/apisixpluginconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type ApisixPluginConfigSpec struct {
}

// ApisixPluginConfigStatus defines the observed state of ApisixPluginConfig.
type ApisixPluginConfigStatus ApisixStatus
type ApisixPluginConfigStatus = ApisixStatus

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
Expand Down
102 changes: 101 additions & 1 deletion api/v2/apisixroute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@
package v2

import (
"strings"

"github.com/pkg/errors"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"

"github.com/apache/apisix-ingress-controller/api/adc"
)

// ApisixRouteSpec is the spec definition for ApisixRouteSpec.
Expand Down Expand Up @@ -66,6 +71,7 @@ type ApisixRouteHTTP struct {
// Upstreams refer to ApisixUpstream CRD
Upstreams []ApisixRouteUpstreamReference `json:"upstreams,omitempty" yaml:"upstreams,omitempty"`

// +kubebuilder:validation:Optional
Websocket bool `json:"websocket" yaml:"websocket"`
PluginConfigName string `json:"plugin_config_name,omitempty" yaml:"plugin_config_name,omitempty"`
// By default, PluginConfigNamespace will be the same as the namespace of ApisixRoute
Expand Down Expand Up @@ -118,7 +124,7 @@ type ApisixRouteHTTPMatch struct {
// value:
// - "127.0.0.1"
// - "10.0.5.11"
NginxVars []ApisixRouteHTTPMatchExpr `json:"exprs,omitempty" yaml:"exprs,omitempty"`
NginxVars ApisixRouteHTTPMatchExprs `json:"exprs,omitempty" yaml:"exprs,omitempty"`
// Matches based on a user-defined filtering function.
// These functions can accept an input parameter `vars`
// which can be used to access the Nginx variables.
Expand Down Expand Up @@ -153,6 +159,7 @@ type ApisixRouteHTTPBackend struct {
// default is endpoints.
ResolveGranularity string `json:"resolveGranularity,omitempty" yaml:"resolveGranularity,omitempty"`
// Weight of this backend.
// +kubebuilder:validation:Optional
Weight *int `json:"weight" yaml:"weight"`
// Subset specifies a subset for the target Service. The subset should be pre-defined
// in ApisixUpstream about this service.
Expand Down Expand Up @@ -211,14 +218,107 @@ type ApisixRouteHTTPMatchExpr struct {
Op string `json:"op" yaml:"op"`
// Set is an array type object of the expression.
// It should be used when the Op is "in" or "not_in";
// +kubebuilder:validation:Optional
Set []string `json:"set" yaml:"set"`
// Value is the normal type object for the expression,
// it should be used when the Op is not "in" and "not_in".
// Set and Value are exclusive so only of them can be set
// in the same time.
// +kubebuilder:validation:Optional
Value *string `json:"value" yaml:"value"`
}

type ApisixRouteHTTPMatchExprs []ApisixRouteHTTPMatchExpr

func (exprs ApisixRouteHTTPMatchExprs) ToVars() (result adc.Vars, err error) {
for _, expr := range exprs {
if expr.Subject.Name == "" && expr.Subject.Scope != ScopePath {
return result, errors.New("empty subject.name")
}

// process key
var (
subj string
this adc.StringOrSlice
)
switch expr.Subject.Scope {
case ScopeQuery:
subj = "arg_" + expr.Subject.Name
case ScopeHeader:
subj = "http_" + strings.ReplaceAll(strings.ToLower(expr.Subject.Name), "-", "_")
case ScopeCookie:
subj = "cookie_" + expr.Subject.Name
case ScopePath:
subj = "uri"
case ScopeVariable:
subj = expr.Subject.Name
default:
return result, errors.New("invalid http match expr: subject.scope should be one of [query, header, cookie, path, variable]")
}
this.SliceVal = append(this.SliceVal, adc.StringOrSlice{StrVal: subj})

// process operator
var (
op string
)
switch expr.Op {
case OpEqual:
op = "=="
case OpGreaterThan:
op = ">"
case OpGreaterThanEqual:
op = ">="
case OpIn:
op = "in"
case OpLessThan:
op = "<"
case OpLessThanEqual:
op = "<="
case OpNotEqual:
op = "~="
case OpNotIn:
op = "in"
case OpRegexMatch:
op = "~~"
case OpRegexMatchCaseInsensitive:
op = "~*"
case OpRegexNotMatch:
op = "~~"
case OpRegexNotMatchCaseInsensitive:
op = "~*"
default:
return result, errors.New("unknown operator")
}
if expr.Op == OpNotIn || expr.Op == OpRegexNotMatch || expr.Op == OpRegexNotMatchCaseInsensitive {
this.SliceVal = append(this.SliceVal, adc.StringOrSlice{StrVal: "!"})
}
this.SliceVal = append(this.SliceVal, adc.StringOrSlice{StrVal: op})

// process value
switch expr.Op {
case OpIn, OpNotIn:
if expr.Set == nil {
return result, errors.New("empty set value")
}
var value adc.StringOrSlice
for _, item := range expr.Set {
value.SliceVal = append(value.SliceVal, adc.StringOrSlice{StrVal: item})
}
this.SliceVal = append(this.SliceVal, value)
default:
if expr.Value == nil {
return result, errors.New("empty value")
}
this.SliceVal = append(this.SliceVal, adc.StringOrSlice{StrVal: *expr.Value})
}

// append to result
result = append(result, this.SliceVal)
}

return result, nil
}

// ApisixRoutePluginConfig is the configuration for
// any plugins.
type ApisixRoutePluginConfig map[string]apiextensionsv1.JSON
Expand Down
10 changes: 10 additions & 0 deletions api/v2/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package v2

import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)

Expand All @@ -30,3 +31,12 @@ var (
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)

func Is(obj client.Object) bool {
switch obj.(type) {
case *ApisixConsumer, *ApisixGlobalRule, *ApisixPluginConfig, *ApisixRoute, *ApisixTls, *ApisixUpstream:
return obj.GetObjectKind().GroupVersionKind().GroupVersion() == GroupVersion
default:
return false
}
}
19 changes: 0 additions & 19 deletions api/v2/reason.go

This file was deleted.

79 changes: 79 additions & 0 deletions api/v2/shared_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 v2

import (
"time"

gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
)

type (
// ApisixRouteConditionType is a type of condition for a route.
ApisixRouteConditionType = gatewayv1.RouteConditionType
// ApisixRouteConditionReason is a reason for a route condition.
ApisixRouteConditionReason = gatewayv1.RouteConditionReason
)

const (
ConditionTypeAccepted ApisixRouteConditionType = gatewayv1.RouteConditionAccepted
ConditionReasonAccepted ApisixRouteConditionReason = gatewayv1.RouteReasonAccepted
ConditionReasonInvalidSpec ApisixRouteConditionReason = "InvalidSpec"
ConditionReasonSyncFailed ApisixRouteConditionReason = "SyncFailed"
)

const (
// DefaultUpstreamTimeout represents the default connect,
// read and send timeout (in seconds) with upstreams.
DefaultUpstreamTimeout = 60 * time.Second

DefaultWeight = 100
)

const (
// OpEqual means the equal ("==") operator in nginxVars.
OpEqual = "Equal"
// OpNotEqual means the not equal ("~=") operator in nginxVars.
OpNotEqual = "NotEqual"
// OpGreaterThan means the greater than (">") operator in nginxVars.
OpGreaterThan = "GreaterThan"
// OpGreaterThanEqual means the greater than (">=") operator in nginxVars.
OpGreaterThanEqual = "GreaterThanEqual"
// OpLessThan means the less than ("<") operator in nginxVars.
OpLessThan = "LessThan"
// OpLessThanEqual means the less than equal ("<=") operator in nginxVars.
OpLessThanEqual = "LessThanEqual"
// OpRegexMatch means the regex match ("~~") operator in nginxVars.
OpRegexMatch = "RegexMatch"
// OpRegexNotMatch means the regex not match ("!~~") operator in nginxVars.
OpRegexNotMatch = "RegexNotMatch"
// OpRegexMatchCaseInsensitive means the regex match "~*" (case insensitive mode) operator in nginxVars.
OpRegexMatchCaseInsensitive = "RegexMatchCaseInsensitive"
// OpRegexNotMatchCaseInsensitive means the regex not match "!~*" (case insensitive mode) operator in nginxVars.
OpRegexNotMatchCaseInsensitive = "RegexNotMatchCaseInsensitive"
// OpIn means the in operator ("in") in nginxVars.
OpIn = "In"
// OpNotIn means the not in operator ("not_in") in nginxVars.
OpNotIn = "NotIn"

// ScopeQuery means the route match expression subject is in the querystring.
ScopeQuery = "Query"
// ScopeHeader means the route match expression subject is in request headers.
ScopeHeader = "Header"
// ScopePath means the route match expression subject is the uri path.
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"
)
20 changes: 20 additions & 0 deletions api/v2/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,29 @@ package v2

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// ApisixStatus is the status report for Apisix ingress Resources
type ApisixStatus struct {
Conditions []metav1.Condition `json:"conditions,omitempty" yaml:"conditions,omitempty"`
}

func GetStatus(object client.Object) ApisixStatus {
switch t := object.(type) {
case *ApisixConsumer:
return t.Status
case *ApisixGlobalRule:
return t.Status
case *ApisixPluginConfig:
return t.Status
case *ApisixRoute:
return t.Status
case *ApisixTls:
return t.Status
case *ApisixUpstream:
return t.Status
default:
return ApisixStatus{}
}
}
45 changes: 22 additions & 23 deletions api/v2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ spec:
- plugins
type: object
status:
description: ApisixPluginConfigStatus defines the observed state of ApisixPluginConfig.
description: ApisixStatus is the status report for Apisix ingress Resources
properties:
conditions:
items:
Expand Down
Loading
Loading