This is an automated email from the ASF dual-hosted git repository.
zhangjintao 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 fa57ff5e feat: add new ApisixGlobalRule resource to support global
rules (#1586)
fa57ff5e is described below
commit fa57ff5e1c9b231e62087b963385a2b049bb4e5e
Author: Xin Rong <[email protected]>
AuthorDate: Tue Jan 31 15:03:04 2023 +0800
feat: add new ApisixGlobalRule resource to support global rules (#1586)
---
docs/en/latest/concepts/apisix_global_rule.md | 50 +++
docs/en/latest/references/apisix_global_rule_v2.md | 37 ++
pkg/kube/apisix/apis/config/v2/types.go | 32 ++
.../apisix/apis/config/v2/zz_generated.deepcopy.go | 84 +++++
.../apisix/apis/config/v2/zz_generated.register.go | 2 +
.../versioned/typed/config/v2/apisixglobalrule.go | 194 ++++++++++
.../versioned/typed/config/v2/config_client.go | 5 +
.../typed/config/v2/fake/fake_apisixglobalrule.go | 141 ++++++++
.../typed/config/v2/fake/fake_config_client.go | 4 +
.../typed/config/v2/generated_expansion.go | 2 +
.../externalversions/config/v2/apisixglobalrule.go | 89 +++++
.../externalversions/config/v2/interface.go | 7 +
.../client/informers/externalversions/generic.go | 2 +
.../client/listers/config/v2/apisixglobalrule.go | 98 ++++++
.../listers/config/v2/expansion_generated.go | 8 +
pkg/kube/apisix_global_rule.go | 156 ++++++++
pkg/providers/apisix/apisix_global_rule.go | 391 +++++++++++++++++++++
pkg/providers/apisix/provider.go | 10 +
.../apisix/translation/apisix_global_rule.go | 77 ++++
pkg/providers/apisix/translation/translator.go | 2 +
pkg/providers/controller.go | 8 +
pkg/providers/translation/context.go | 5 +
pkg/providers/types/types.go | 2 +
pkg/providers/utils/manifest.go | 45 +++
pkg/types/apisix/v1/types.go | 28 +-
samples/deploy/crd/v1/ApisixGlobalRule.yaml | 86 +++++
samples/deploy/crd/v1/kustomization.yaml | 1 +
test/e2e/scaffold/ingress.go | 2 +
test/e2e/suite-features/global_rule.go | 115 ++++++
29 files changed, 1680 insertions(+), 3 deletions(-)
diff --git a/docs/en/latest/concepts/apisix_global_rule.md
b/docs/en/latest/concepts/apisix_global_rule.md
new file mode 100644
index 00000000..8d143e72
--- /dev/null
+++ b/docs/en/latest/concepts/apisix_global_rule.md
@@ -0,0 +1,50 @@
+---
+title: ApisixGlobalRule
+keywords:
+ - APISIX ingress
+ - Apache APISIX
+ - ApisixGlobalRule
+description: Guide to using ApisixGlobalRule custom Kubernetes resource.
+---
+
+<!--
+#
+# 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.
+#
+-->
+
+`ApisixGlobalRule` is a Kubernetes CRD resource used to create an APISIX
[global-rule](https://apisix.apache.org/docs/apisix/terminology/global-rule/)
object, which can apply the
[plugin](https://apisix.apache.org/docs/apisix/next/terminology/plugin/) to all
requests.
+
+## Example
+
+Enable the
[limit-count](https://apisix.apache.org/docs/apisix/next/plugins/limit-count/)
plugin on the APISIX, which can limit all requests.
+
+```yaml
+apiVersion: apisix.apache.org/v2
+kind: ApisixGlobalRule
+metadata:
+ name: global
+spec:
+ plugins:
+ name: limit-count
+ enalbed: true
+ config:
+ time_window": 60,
+ policy: "local",
+ count: 2,
+ key: "remote_addr",
+ rejected_code: 503
+```
diff --git a/docs/en/latest/references/apisix_global_rule_v2.md
b/docs/en/latest/references/apisix_global_rule_v2.md
new file mode 100644
index 00000000..8e213476
--- /dev/null
+++ b/docs/en/latest/references/apisix_global_rule_v2.md
@@ -0,0 +1,37 @@
+---
+title: ApisixGlobalRule/v2
+keywords:
+ - APISIX ingress
+ - Apache APISIX
+ - ApisixGlobalRule
+description: Reference for ApisixGlobalRule/v2 custom Kubernetes resource.
+---
+<!--
+#
+# 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.
+#
+-->
+
+## Spec
+
+,See the [definition](../concepts/apisix_global_rule.md) on GitHub.
+
+| Field | Type | Description
|
+|------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------|
+| plugins | array | Plugins that will be executed on the all
requests.
|
+| plugins[].name | string | Name of the Plugin. See [Plugin
hub](https://apisix.apache.org/plugins/) for a list of available Plugins.
|
+| plugins[].enable | boolean | When set to `true`, enables the Plugin.
|
+| plugins[].config | object | Configuration of the Plugin, the schema is
totally same to the one in APISIX. |
diff --git a/pkg/kube/apisix/apis/config/v2/types.go
b/pkg/kube/apisix/apis/config/v2/types.go
index 5bab54d8..5f223f62 100644
--- a/pkg/kube/apisix/apis/config/v2/types.go
+++ b/pkg/kube/apisix/apis/config/v2/types.go
@@ -758,3 +758,35 @@ type ApisixPluginConfigList struct {
metav1.ListMeta `json:"metadata" yaml:"metadata"`
Items []ApisixPluginConfig `json:"items,omitempty"
yaml:"items,omitempty"`
}
+
+// +genclient
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+// +kubebuilder:subresource:status
+
+// ApisixGlobalRule is the Schema for the ApisixGlobalRule resource.
+// An ApisixGlobalRule is used to support a group of plugin configs
+type ApisixGlobalRule struct {
+ metav1.TypeMeta `json:",inline" yaml:",inline"`
+ metav1.ObjectMeta `json:"metadata" yaml:"metadata"`
+
+ // Spec defines the desired state of ApisixGlobalRuleSpec.
+ Spec ApisixGlobalRuleSpec `json:"spec" yaml:"spec"`
+ Status ApisixStatus `json:"status,omitempty"
yaml:"status,omitempty"`
+}
+
+// ApisixGlobalRuleSpec defines the desired state of ApisixGlobalRuleSpec.
+type ApisixGlobalRuleSpec struct {
+ // Plugins contains a list of ApisixRoutePlugin
+ // +required
+ Plugins []ApisixRoutePlugin `json:"plugins" yaml:"plugins"`
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+// +kubebuilder:object:generate=true
+
+// ApisixGlobalRuleList contains a list of ApisixGlobalRule.
+type ApisixGlobalRuleList struct {
+ metav1.TypeMeta `json:",inline" yaml:",inline"`
+ metav1.ListMeta `json:"metadata" yaml:"metadata"`
+ Items []ApisixGlobalRule `json:"items,omitempty"
yaml:"items,omitempty"`
+}
diff --git a/pkg/kube/apisix/apis/config/v2/zz_generated.deepcopy.go
b/pkg/kube/apisix/apis/config/v2/zz_generated.deepcopy.go
index 90b29cdc..f83b3648 100644
--- a/pkg/kube/apisix/apis/config/v2/zz_generated.deepcopy.go
+++ b/pkg/kube/apisix/apis/config/v2/zz_generated.deepcopy.go
@@ -586,6 +586,90 @@ func (in *ApisixConsumerWolfRBACValue) DeepCopy()
*ApisixConsumerWolfRBACValue {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
+func (in *ApisixGlobalRule) DeepCopyInto(out *ApisixGlobalRule) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver,
creating a new ApisixGlobalRule.
+func (in *ApisixGlobalRule) DeepCopy() *ApisixGlobalRule {
+ if in == nil {
+ return nil
+ }
+ out := new(ApisixGlobalRule)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver,
creating a new runtime.Object.
+func (in *ApisixGlobalRule) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
+func (in *ApisixGlobalRuleList) DeepCopyInto(out *ApisixGlobalRuleList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ApisixGlobalRule, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver,
creating a new ApisixGlobalRuleList.
+func (in *ApisixGlobalRuleList) DeepCopy() *ApisixGlobalRuleList {
+ if in == nil {
+ return nil
+ }
+ out := new(ApisixGlobalRuleList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver,
creating a new runtime.Object.
+func (in *ApisixGlobalRuleList) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
+func (in *ApisixGlobalRuleSpec) DeepCopyInto(out *ApisixGlobalRuleSpec) {
+ *out = *in
+ if in.Plugins != nil {
+ in, out := &in.Plugins, &out.Plugins
+ *out = make([]ApisixRoutePlugin, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver,
creating a new ApisixGlobalRuleSpec.
+func (in *ApisixGlobalRuleSpec) DeepCopy() *ApisixGlobalRuleSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ApisixGlobalRuleSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
func (in *ApisixMutualTlsClientConfig) DeepCopyInto(out
*ApisixMutualTlsClientConfig) {
*out = *in
diff --git a/pkg/kube/apisix/apis/config/v2/zz_generated.register.go
b/pkg/kube/apisix/apis/config/v2/zz_generated.register.go
index a6a38f17..79cb61ef 100644
--- a/pkg/kube/apisix/apis/config/v2/zz_generated.register.go
+++ b/pkg/kube/apisix/apis/config/v2/zz_generated.register.go
@@ -64,6 +64,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&ApisixClusterConfigList{},
&ApisixConsumer{},
&ApisixConsumerList{},
+ &ApisixGlobalRule{},
+ &ApisixGlobalRuleList{},
&ApisixPluginConfig{},
&ApisixPluginConfigList{},
&ApisixRoute{},
diff --git
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/apisixglobalrule.go
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/apisixglobalrule.go
new file mode 100644
index 00000000..30664e49
--- /dev/null
+++
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/apisixglobalrule.go
@@ -0,0 +1,194 @@
+// 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.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v2
+
+import (
+ "context"
+ "time"
+
+ v2
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
+ scheme
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned/scheme"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ types "k8s.io/apimachinery/pkg/types"
+ watch "k8s.io/apimachinery/pkg/watch"
+ rest "k8s.io/client-go/rest"
+)
+
+// ApisixGlobalRulesGetter has a method to return a ApisixGlobalRuleInterface.
+// A group's client should implement this interface.
+type ApisixGlobalRulesGetter interface {
+ ApisixGlobalRules(namespace string) ApisixGlobalRuleInterface
+}
+
+// ApisixGlobalRuleInterface has methods to work with ApisixGlobalRule
resources.
+type ApisixGlobalRuleInterface interface {
+ Create(ctx context.Context, apisixGlobalRule *v2.ApisixGlobalRule, opts
v1.CreateOptions) (*v2.ApisixGlobalRule, error)
+ Update(ctx context.Context, apisixGlobalRule *v2.ApisixGlobalRule, opts
v1.UpdateOptions) (*v2.ApisixGlobalRule, error)
+ UpdateStatus(ctx context.Context, apisixGlobalRule
*v2.ApisixGlobalRule, opts v1.UpdateOptions) (*v2.ApisixGlobalRule, error)
+ Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
+ DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts
v1.ListOptions) error
+ Get(ctx context.Context, name string, opts v1.GetOptions)
(*v2.ApisixGlobalRule, error)
+ List(ctx context.Context, opts v1.ListOptions)
(*v2.ApisixGlobalRuleList, error)
+ Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
+ Patch(ctx context.Context, name string, pt types.PatchType, data
[]byte, opts v1.PatchOptions, subresources ...string) (result
*v2.ApisixGlobalRule, err error)
+ ApisixGlobalRuleExpansion
+}
+
+// apisixGlobalRules implements ApisixGlobalRuleInterface
+type apisixGlobalRules struct {
+ client rest.Interface
+ ns string
+}
+
+// newApisixGlobalRules returns a ApisixGlobalRules
+func newApisixGlobalRules(c *ApisixV2Client, namespace string)
*apisixGlobalRules {
+ return &apisixGlobalRules{
+ client: c.RESTClient(),
+ ns: namespace,
+ }
+}
+
+// Get takes name of the apisixGlobalRule, and returns the corresponding
apisixGlobalRule object, and an error if there is any.
+func (c *apisixGlobalRules) Get(ctx context.Context, name string, options
v1.GetOptions) (result *v2.ApisixGlobalRule, err error) {
+ result = &v2.ApisixGlobalRule{}
+ err = c.client.Get().
+ Namespace(c.ns).
+ Resource("apisixglobalrules").
+ Name(name).
+ VersionedParams(&options, scheme.ParameterCodec).
+ Do(ctx).
+ Into(result)
+ return
+}
+
+// List takes label and field selectors, and returns the list of
ApisixGlobalRules that match those selectors.
+func (c *apisixGlobalRules) List(ctx context.Context, opts v1.ListOptions)
(result *v2.ApisixGlobalRuleList, err error) {
+ var timeout time.Duration
+ if opts.TimeoutSeconds != nil {
+ timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
+ }
+ result = &v2.ApisixGlobalRuleList{}
+ err = c.client.Get().
+ Namespace(c.ns).
+ Resource("apisixglobalrules").
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Timeout(timeout).
+ Do(ctx).
+ Into(result)
+ return
+}
+
+// Watch returns a watch.Interface that watches the requested
apisixGlobalRules.
+func (c *apisixGlobalRules) Watch(ctx context.Context, opts v1.ListOptions)
(watch.Interface, error) {
+ var timeout time.Duration
+ if opts.TimeoutSeconds != nil {
+ timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
+ }
+ opts.Watch = true
+ return c.client.Get().
+ Namespace(c.ns).
+ Resource("apisixglobalrules").
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Timeout(timeout).
+ Watch(ctx)
+}
+
+// Create takes the representation of a apisixGlobalRule and creates it.
Returns the server's representation of the apisixGlobalRule, and an error, if
there is any.
+func (c *apisixGlobalRules) Create(ctx context.Context, apisixGlobalRule
*v2.ApisixGlobalRule, opts v1.CreateOptions) (result *v2.ApisixGlobalRule, err
error) {
+ result = &v2.ApisixGlobalRule{}
+ err = c.client.Post().
+ Namespace(c.ns).
+ Resource("apisixglobalrules").
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Body(apisixGlobalRule).
+ Do(ctx).
+ Into(result)
+ return
+}
+
+// Update takes the representation of a apisixGlobalRule and updates it.
Returns the server's representation of the apisixGlobalRule, and an error, if
there is any.
+func (c *apisixGlobalRules) Update(ctx context.Context, apisixGlobalRule
*v2.ApisixGlobalRule, opts v1.UpdateOptions) (result *v2.ApisixGlobalRule, err
error) {
+ result = &v2.ApisixGlobalRule{}
+ err = c.client.Put().
+ Namespace(c.ns).
+ Resource("apisixglobalrules").
+ Name(apisixGlobalRule.Name).
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Body(apisixGlobalRule).
+ Do(ctx).
+ Into(result)
+ return
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating
UpdateStatus().
+func (c *apisixGlobalRules) UpdateStatus(ctx context.Context, apisixGlobalRule
*v2.ApisixGlobalRule, opts v1.UpdateOptions) (result *v2.ApisixGlobalRule, err
error) {
+ result = &v2.ApisixGlobalRule{}
+ err = c.client.Put().
+ Namespace(c.ns).
+ Resource("apisixglobalrules").
+ Name(apisixGlobalRule.Name).
+ SubResource("status").
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Body(apisixGlobalRule).
+ Do(ctx).
+ Into(result)
+ return
+}
+
+// Delete takes name of the apisixGlobalRule and deletes it. Returns an error
if one occurs.
+func (c *apisixGlobalRules) Delete(ctx context.Context, name string, opts
v1.DeleteOptions) error {
+ return c.client.Delete().
+ Namespace(c.ns).
+ Resource("apisixglobalrules").
+ Name(name).
+ Body(&opts).
+ Do(ctx).
+ Error()
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *apisixGlobalRules) DeleteCollection(ctx context.Context, opts
v1.DeleteOptions, listOpts v1.ListOptions) error {
+ var timeout time.Duration
+ if listOpts.TimeoutSeconds != nil {
+ timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
+ }
+ return c.client.Delete().
+ Namespace(c.ns).
+ Resource("apisixglobalrules").
+ VersionedParams(&listOpts, scheme.ParameterCodec).
+ Timeout(timeout).
+ Body(&opts).
+ Do(ctx).
+ Error()
+}
+
+// Patch applies the patch and returns the patched apisixGlobalRule.
+func (c *apisixGlobalRules) Patch(ctx context.Context, name string, pt
types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string)
(result *v2.ApisixGlobalRule, err error) {
+ result = &v2.ApisixGlobalRule{}
+ err = c.client.Patch(pt).
+ Namespace(c.ns).
+ Resource("apisixglobalrules").
+ Name(name).
+ SubResource(subresources...).
+ VersionedParams(&opts, scheme.ParameterCodec).
+ Body(data).
+ Do(ctx).
+ Into(result)
+ return
+}
diff --git
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/config_client.go
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/config_client.go
index ab6131be..e8eaaa53 100644
---
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/config_client.go
+++
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/config_client.go
@@ -29,6 +29,7 @@ type ApisixV2Interface interface {
RESTClient() rest.Interface
ApisixClusterConfigsGetter
ApisixConsumersGetter
+ ApisixGlobalRulesGetter
ApisixPluginConfigsGetter
ApisixRoutesGetter
ApisixTlsesGetter
@@ -48,6 +49,10 @@ func (c *ApisixV2Client) ApisixConsumers(namespace string)
ApisixConsumerInterfa
return newApisixConsumers(c, namespace)
}
+func (c *ApisixV2Client) ApisixGlobalRules(namespace string)
ApisixGlobalRuleInterface {
+ return newApisixGlobalRules(c, namespace)
+}
+
func (c *ApisixV2Client) ApisixPluginConfigs(namespace string)
ApisixPluginConfigInterface {
return newApisixPluginConfigs(c, namespace)
}
diff --git
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/fake/fake_apisixglobalrule.go
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/fake/fake_apisixglobalrule.go
new file mode 100644
index 00000000..161cdbdb
--- /dev/null
+++
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/fake/fake_apisixglobalrule.go
@@ -0,0 +1,141 @@
+// 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.
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+ "context"
+
+ v2
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ labels "k8s.io/apimachinery/pkg/labels"
+ schema "k8s.io/apimachinery/pkg/runtime/schema"
+ types "k8s.io/apimachinery/pkg/types"
+ watch "k8s.io/apimachinery/pkg/watch"
+ testing "k8s.io/client-go/testing"
+)
+
+// FakeApisixGlobalRules implements ApisixGlobalRuleInterface
+type FakeApisixGlobalRules struct {
+ Fake *FakeApisixV2
+ ns string
+}
+
+var apisixglobalrulesResource = schema.GroupVersionResource{Group:
"apisix.apache.org", Version: "v2", Resource: "apisixglobalrules"}
+
+var apisixglobalrulesKind = schema.GroupVersionKind{Group:
"apisix.apache.org", Version: "v2", Kind: "ApisixGlobalRule"}
+
+// Get takes name of the apisixGlobalRule, and returns the corresponding
apisixGlobalRule object, and an error if there is any.
+func (c *FakeApisixGlobalRules) Get(ctx context.Context, name string, options
v1.GetOptions) (result *v2.ApisixGlobalRule, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewGetAction(apisixglobalrulesResource, c.ns,
name), &v2.ApisixGlobalRule{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v2.ApisixGlobalRule), err
+}
+
+// List takes label and field selectors, and returns the list of
ApisixGlobalRules that match those selectors.
+func (c *FakeApisixGlobalRules) List(ctx context.Context, opts v1.ListOptions)
(result *v2.ApisixGlobalRuleList, err error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewListAction(apisixglobalrulesResource,
apisixglobalrulesKind, c.ns, opts), &v2.ApisixGlobalRuleList{})
+
+ if obj == nil {
+ return nil, err
+ }
+
+ label, _, _ := testing.ExtractFromListOptions(opts)
+ if label == nil {
+ label = labels.Everything()
+ }
+ list := &v2.ApisixGlobalRuleList{ListMeta:
obj.(*v2.ApisixGlobalRuleList).ListMeta}
+ for _, item := range obj.(*v2.ApisixGlobalRuleList).Items {
+ if label.Matches(labels.Set(item.Labels)) {
+ list.Items = append(list.Items, item)
+ }
+ }
+ return list, err
+}
+
+// Watch returns a watch.Interface that watches the requested
apisixGlobalRules.
+func (c *FakeApisixGlobalRules) Watch(ctx context.Context, opts
v1.ListOptions) (watch.Interface, error) {
+ return c.Fake.
+ InvokesWatch(testing.NewWatchAction(apisixglobalrulesResource,
c.ns, opts))
+
+}
+
+// Create takes the representation of a apisixGlobalRule and creates it.
Returns the server's representation of the apisixGlobalRule, and an error, if
there is any.
+func (c *FakeApisixGlobalRules) Create(ctx context.Context, apisixGlobalRule
*v2.ApisixGlobalRule, opts v1.CreateOptions) (result *v2.ApisixGlobalRule, err
error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewCreateAction(apisixglobalrulesResource,
c.ns, apisixGlobalRule), &v2.ApisixGlobalRule{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v2.ApisixGlobalRule), err
+}
+
+// Update takes the representation of a apisixGlobalRule and updates it.
Returns the server's representation of the apisixGlobalRule, and an error, if
there is any.
+func (c *FakeApisixGlobalRules) Update(ctx context.Context, apisixGlobalRule
*v2.ApisixGlobalRule, opts v1.UpdateOptions) (result *v2.ApisixGlobalRule, err
error) {
+ obj, err := c.Fake.
+ Invokes(testing.NewUpdateAction(apisixglobalrulesResource,
c.ns, apisixGlobalRule), &v2.ApisixGlobalRule{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v2.ApisixGlobalRule), err
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating
UpdateStatus().
+func (c *FakeApisixGlobalRules) UpdateStatus(ctx context.Context,
apisixGlobalRule *v2.ApisixGlobalRule, opts v1.UpdateOptions)
(*v2.ApisixGlobalRule, error) {
+ obj, err := c.Fake.
+
Invokes(testing.NewUpdateSubresourceAction(apisixglobalrulesResource, "status",
c.ns, apisixGlobalRule), &v2.ApisixGlobalRule{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v2.ApisixGlobalRule), err
+}
+
+// Delete takes name of the apisixGlobalRule and deletes it. Returns an error
if one occurs.
+func (c *FakeApisixGlobalRules) Delete(ctx context.Context, name string, opts
v1.DeleteOptions) error {
+ _, err := c.Fake.
+
Invokes(testing.NewDeleteActionWithOptions(apisixglobalrulesResource, c.ns,
name, opts), &v2.ApisixGlobalRule{})
+
+ return err
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *FakeApisixGlobalRules) DeleteCollection(ctx context.Context, opts
v1.DeleteOptions, listOpts v1.ListOptions) error {
+ action := testing.NewDeleteCollectionAction(apisixglobalrulesResource,
c.ns, listOpts)
+
+ _, err := c.Fake.Invokes(action, &v2.ApisixGlobalRuleList{})
+ return err
+}
+
+// Patch applies the patch and returns the patched apisixGlobalRule.
+func (c *FakeApisixGlobalRules) Patch(ctx context.Context, name string, pt
types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string)
(result *v2.ApisixGlobalRule, err error) {
+ obj, err := c.Fake.
+
Invokes(testing.NewPatchSubresourceAction(apisixglobalrulesResource, c.ns,
name, pt, data, subresources...), &v2.ApisixGlobalRule{})
+
+ if obj == nil {
+ return nil, err
+ }
+ return obj.(*v2.ApisixGlobalRule), err
+}
diff --git
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/fake/fake_config_client.go
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/fake/fake_config_client.go
index 025feb4f..b54d7605 100644
---
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/fake/fake_config_client.go
+++
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/fake/fake_config_client.go
@@ -35,6 +35,10 @@ func (c *FakeApisixV2) ApisixConsumers(namespace string)
v2.ApisixConsumerInterf
return &FakeApisixConsumers{c, namespace}
}
+func (c *FakeApisixV2) ApisixGlobalRules(namespace string)
v2.ApisixGlobalRuleInterface {
+ return &FakeApisixGlobalRules{c, namespace}
+}
+
func (c *FakeApisixV2) ApisixPluginConfigs(namespace string)
v2.ApisixPluginConfigInterface {
return &FakeApisixPluginConfigs{c, namespace}
}
diff --git
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/generated_expansion.go
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/generated_expansion.go
index 09555586..202b79d5 100644
---
a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/generated_expansion.go
+++
b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2/generated_expansion.go
@@ -21,6 +21,8 @@ type ApisixClusterConfigExpansion interface{}
type ApisixConsumerExpansion interface{}
+type ApisixGlobalRuleExpansion interface{}
+
type ApisixPluginConfigExpansion interface{}
type ApisixRouteExpansion interface{}
diff --git
a/pkg/kube/apisix/client/informers/externalversions/config/v2/apisixglobalrule.go
b/pkg/kube/apisix/client/informers/externalversions/config/v2/apisixglobalrule.go
new file mode 100644
index 00000000..6d6847d1
--- /dev/null
+++
b/pkg/kube/apisix/client/informers/externalversions/config/v2/apisixglobalrule.go
@@ -0,0 +1,89 @@
+// 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.
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+package v2
+
+import (
+ "context"
+ time "time"
+
+ configv2
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
+ versioned
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/clientset/versioned"
+ internalinterfaces
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/informers/externalversions/internalinterfaces"
+ v2
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/listers/config/v2"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ watch "k8s.io/apimachinery/pkg/watch"
+ cache "k8s.io/client-go/tools/cache"
+)
+
+// ApisixGlobalRuleInformer provides access to a shared informer and lister for
+// ApisixGlobalRules.
+type ApisixGlobalRuleInformer interface {
+ Informer() cache.SharedIndexInformer
+ Lister() v2.ApisixGlobalRuleLister
+}
+
+type apisixGlobalRuleInformer struct {
+ factory internalinterfaces.SharedInformerFactory
+ tweakListOptions internalinterfaces.TweakListOptionsFunc
+ namespace string
+}
+
+// NewApisixGlobalRuleInformer constructs a new informer for ApisixGlobalRule
type.
+// Always prefer using an informer factory to get a shared informer instead of
getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewApisixGlobalRuleInformer(client versioned.Interface, namespace string,
resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
+ return NewFilteredApisixGlobalRuleInformer(client, namespace,
resyncPeriod, indexers, nil)
+}
+
+// NewFilteredApisixGlobalRuleInformer constructs a new informer for
ApisixGlobalRule type.
+// Always prefer using an informer factory to get a shared informer instead of
getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewFilteredApisixGlobalRuleInformer(client versioned.Interface, namespace
string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions
internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
+ return cache.NewSharedIndexInformer(
+ &cache.ListWatch{
+ ListFunc: func(options v1.ListOptions) (runtime.Object,
error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return
client.ApisixV2().ApisixGlobalRules(namespace).List(context.TODO(), options)
+ },
+ WatchFunc: func(options v1.ListOptions)
(watch.Interface, error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return
client.ApisixV2().ApisixGlobalRules(namespace).Watch(context.TODO(), options)
+ },
+ },
+ &configv2.ApisixGlobalRule{},
+ resyncPeriod,
+ indexers,
+ )
+}
+
+func (f *apisixGlobalRuleInformer) defaultInformer(client versioned.Interface,
resyncPeriod time.Duration) cache.SharedIndexInformer {
+ return NewFilteredApisixGlobalRuleInformer(client, f.namespace,
resyncPeriod, cache.Indexers{cache.NamespaceIndex:
cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+}
+
+func (f *apisixGlobalRuleInformer) Informer() cache.SharedIndexInformer {
+ return f.factory.InformerFor(&configv2.ApisixGlobalRule{},
f.defaultInformer)
+}
+
+func (f *apisixGlobalRuleInformer) Lister() v2.ApisixGlobalRuleLister {
+ return v2.NewApisixGlobalRuleLister(f.Informer().GetIndexer())
+}
diff --git
a/pkg/kube/apisix/client/informers/externalversions/config/v2/interface.go
b/pkg/kube/apisix/client/informers/externalversions/config/v2/interface.go
index 3d6cd93d..b40a12b8 100644
--- a/pkg/kube/apisix/client/informers/externalversions/config/v2/interface.go
+++ b/pkg/kube/apisix/client/informers/externalversions/config/v2/interface.go
@@ -27,6 +27,8 @@ type Interface interface {
ApisixClusterConfigs() ApisixClusterConfigInformer
// ApisixConsumers returns a ApisixConsumerInformer.
ApisixConsumers() ApisixConsumerInformer
+ // ApisixGlobalRules returns a ApisixGlobalRuleInformer.
+ ApisixGlobalRules() ApisixGlobalRuleInformer
// ApisixPluginConfigs returns a ApisixPluginConfigInformer.
ApisixPluginConfigs() ApisixPluginConfigInformer
// ApisixRoutes returns a ApisixRouteInformer.
@@ -58,6 +60,11 @@ func (v *version) ApisixConsumers() ApisixConsumerInformer {
return &apisixConsumerInformer{factory: v.factory, namespace:
v.namespace, tweakListOptions: v.tweakListOptions}
}
+// ApisixGlobalRules returns a ApisixGlobalRuleInformer.
+func (v *version) ApisixGlobalRules() ApisixGlobalRuleInformer {
+ return &apisixGlobalRuleInformer{factory: v.factory, namespace:
v.namespace, tweakListOptions: v.tweakListOptions}
+}
+
// ApisixPluginConfigs returns a ApisixPluginConfigInformer.
func (v *version) ApisixPluginConfigs() ApisixPluginConfigInformer {
return &apisixPluginConfigInformer{factory: v.factory, namespace:
v.namespace, tweakListOptions: v.tweakListOptions}
diff --git a/pkg/kube/apisix/client/informers/externalversions/generic.go
b/pkg/kube/apisix/client/informers/externalversions/generic.go
index 2a29a506..513c4525 100644
--- a/pkg/kube/apisix/client/informers/externalversions/generic.go
+++ b/pkg/kube/apisix/client/informers/externalversions/generic.go
@@ -57,6 +57,8 @@ func (f *sharedInformerFactory) ForResource(resource
schema.GroupVersionResource
return &genericInformer{resource: resource.GroupResource(),
informer: f.Apisix().V2().ApisixClusterConfigs().Informer()}, nil
case v2.SchemeGroupVersion.WithResource("apisixconsumers"):
return &genericInformer{resource: resource.GroupResource(),
informer: f.Apisix().V2().ApisixConsumers().Informer()}, nil
+ case v2.SchemeGroupVersion.WithResource("apisixglobalrules"):
+ return &genericInformer{resource: resource.GroupResource(),
informer: f.Apisix().V2().ApisixGlobalRules().Informer()}, nil
case v2.SchemeGroupVersion.WithResource("apisixpluginconfigs"):
return &genericInformer{resource: resource.GroupResource(),
informer: f.Apisix().V2().ApisixPluginConfigs().Informer()}, nil
case v2.SchemeGroupVersion.WithResource("apisixroutes"):
diff --git a/pkg/kube/apisix/client/listers/config/v2/apisixglobalrule.go
b/pkg/kube/apisix/client/listers/config/v2/apisixglobalrule.go
new file mode 100644
index 00000000..c37e6b07
--- /dev/null
+++ b/pkg/kube/apisix/client/listers/config/v2/apisixglobalrule.go
@@ -0,0 +1,98 @@
+// 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.
+
+// Code generated by lister-gen. DO NOT EDIT.
+
+package v2
+
+import (
+ v2
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/client-go/tools/cache"
+)
+
+// ApisixGlobalRuleLister helps list ApisixGlobalRules.
+// All objects returned here must be treated as read-only.
+type ApisixGlobalRuleLister interface {
+ // List lists all ApisixGlobalRules in the indexer.
+ // Objects returned here must be treated as read-only.
+ List(selector labels.Selector) (ret []*v2.ApisixGlobalRule, err error)
+ // ApisixGlobalRules returns an object that can list and get
ApisixGlobalRules.
+ ApisixGlobalRules(namespace string) ApisixGlobalRuleNamespaceLister
+ ApisixGlobalRuleListerExpansion
+}
+
+// apisixGlobalRuleLister implements the ApisixGlobalRuleLister interface.
+type apisixGlobalRuleLister struct {
+ indexer cache.Indexer
+}
+
+// NewApisixGlobalRuleLister returns a new ApisixGlobalRuleLister.
+func NewApisixGlobalRuleLister(indexer cache.Indexer) ApisixGlobalRuleLister {
+ return &apisixGlobalRuleLister{indexer: indexer}
+}
+
+// List lists all ApisixGlobalRules in the indexer.
+func (s *apisixGlobalRuleLister) List(selector labels.Selector) (ret
[]*v2.ApisixGlobalRule, err error) {
+ err = cache.ListAll(s.indexer, selector, func(m interface{}) {
+ ret = append(ret, m.(*v2.ApisixGlobalRule))
+ })
+ return ret, err
+}
+
+// ApisixGlobalRules returns an object that can list and get ApisixGlobalRules.
+func (s *apisixGlobalRuleLister) ApisixGlobalRules(namespace string)
ApisixGlobalRuleNamespaceLister {
+ return apisixGlobalRuleNamespaceLister{indexer: s.indexer, namespace:
namespace}
+}
+
+// ApisixGlobalRuleNamespaceLister helps list and get ApisixGlobalRules.
+// All objects returned here must be treated as read-only.
+type ApisixGlobalRuleNamespaceLister interface {
+ // List lists all ApisixGlobalRules in the indexer for a given
namespace.
+ // Objects returned here must be treated as read-only.
+ List(selector labels.Selector) (ret []*v2.ApisixGlobalRule, err error)
+ // Get retrieves the ApisixGlobalRule from the indexer for a given
namespace and name.
+ // Objects returned here must be treated as read-only.
+ Get(name string) (*v2.ApisixGlobalRule, error)
+ ApisixGlobalRuleNamespaceListerExpansion
+}
+
+// apisixGlobalRuleNamespaceLister implements the
ApisixGlobalRuleNamespaceLister
+// interface.
+type apisixGlobalRuleNamespaceLister struct {
+ indexer cache.Indexer
+ namespace string
+}
+
+// List lists all ApisixGlobalRules in the indexer for a given namespace.
+func (s apisixGlobalRuleNamespaceLister) List(selector labels.Selector) (ret
[]*v2.ApisixGlobalRule, err error) {
+ err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m
interface{}) {
+ ret = append(ret, m.(*v2.ApisixGlobalRule))
+ })
+ return ret, err
+}
+
+// Get retrieves the ApisixGlobalRule from the indexer for a given namespace
and name.
+func (s apisixGlobalRuleNamespaceLister) Get(name string)
(*v2.ApisixGlobalRule, error) {
+ obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
+ if err != nil {
+ return nil, err
+ }
+ if !exists {
+ return nil, errors.NewNotFound(v2.Resource("apisixglobalrule"),
name)
+ }
+ return obj.(*v2.ApisixGlobalRule), nil
+}
diff --git a/pkg/kube/apisix/client/listers/config/v2/expansion_generated.go
b/pkg/kube/apisix/client/listers/config/v2/expansion_generated.go
index 2bbd0fd4..2aac2a09 100644
--- a/pkg/kube/apisix/client/listers/config/v2/expansion_generated.go
+++ b/pkg/kube/apisix/client/listers/config/v2/expansion_generated.go
@@ -29,6 +29,14 @@ type ApisixConsumerListerExpansion interface{}
// ApisixConsumerNamespaceLister.
type ApisixConsumerNamespaceListerExpansion interface{}
+// ApisixGlobalRuleListerExpansion allows custom methods to be added to
+// ApisixGlobalRuleLister.
+type ApisixGlobalRuleListerExpansion interface{}
+
+// ApisixGlobalRuleNamespaceListerExpansion allows custom methods to be added
to
+// ApisixGlobalRuleNamespaceLister.
+type ApisixGlobalRuleNamespaceListerExpansion interface{}
+
// ApisixPluginConfigListerExpansion allows custom methods to be added to
// ApisixPluginConfigLister.
type ApisixPluginConfigListerExpansion interface{}
diff --git a/pkg/kube/apisix_global_rule.go b/pkg/kube/apisix_global_rule.go
new file mode 100644
index 00000000..e25670ef
--- /dev/null
+++ b/pkg/kube/apisix_global_rule.go
@@ -0,0 +1,156 @@
+// 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 kube
+
+import (
+ "errors"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "github.com/apache/apisix-ingress-controller/pkg/config"
+ configv2
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
+ listersv2
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/listers/config/v2"
+)
+
+// ApisixGlobalRuleLister is an encapsulation for the lister of
ApisixGlobalRule,
+// it aims at to be compatible with different ApisixGlobalRule versions.
+type ApisixGlobalRuleLister interface {
+ // V2 gets the ApisixGlobalRule in apisix.apache.org/v2.
+ V2(string, string) (ApisixGlobalRule, error)
+
+ ApisixGlobalRule(string, string) (ApisixGlobalRule, error)
+}
+
+// ApisixGlobalRuleInformer is an encapsulation for the informer of
ApisixGlobalRule,
+// it aims at to be compatible with different ApisixGlobalRule versions.
+type ApisixGlobalRuleInformer interface {
+ Run(chan struct{})
+}
+
+// ApisixGlobalRule is an encapsulation for ApisixGlobalRule resource with
different
+// versions, for now, they are apisix.apache.org/v1 and
apisix.apache.org/v2alpha1
+type ApisixGlobalRule interface {
+ // GroupVersion returns the api group version of the
+ // real ApisixGlobalRule.
+ GroupVersion() string
+ // V2 returns the ApisixGlobalRule in apisix.apache.org/v2, the real
+ // ApisixGlobalRule must be in this group version, otherwise will panic.
+ V2() *configv2.ApisixGlobalRule
+ // ResourceVersion returns the the resource version field inside
+ // the real ApisixGlobalRule.
+ ResourceVersion() string
+
+ metav1.Object
+}
+
+// ApisixGlobalRuleEvent contains the ApisixGlobalRule key (namespace/name)
+// and the group version message.
+type ApisixGlobalRuleEvent struct {
+ Key string
+ OldObject ApisixGlobalRule
+ GroupVersion string
+}
+
+type apisixGlobalRule struct {
+ groupVersion string
+ v2 *configv2.ApisixGlobalRule
+ metav1.Object
+}
+
+func (agr *apisixGlobalRule) V2() *configv2.ApisixGlobalRule {
+ if agr.groupVersion != config.ApisixV2 {
+ panic("not a apisix.apache.org/v2 ApisixGlobalRule")
+ }
+ return agr.v2
+}
+
+func (agr *apisixGlobalRule) GroupVersion() string {
+ return agr.groupVersion
+}
+
+func (agr *apisixGlobalRule) ResourceVersion() string {
+ return agr.V2().ResourceVersion
+}
+
+type apisixGlobalRuleLister struct {
+ groupVersion string
+ v2Lister listersv2.ApisixGlobalRuleLister
+}
+
+func (l *apisixGlobalRuleLister) V2(namespace, name string) (ApisixGlobalRule,
error) {
+ agr, err := l.v2Lister.ApisixGlobalRules(namespace).Get(name)
+ if err != nil {
+ return nil, err
+ }
+ return &apisixGlobalRule{
+ groupVersion: config.ApisixV2,
+ v2: agr,
+ Object: agr.GetObjectMeta(),
+ }, nil
+}
+
+func (l *apisixGlobalRuleLister) ApisixGlobalRule(namespace, name string)
(ApisixGlobalRule, error) {
+ switch l.groupVersion {
+ case config.ApisixV2:
+ agr, err := l.v2Lister.ApisixGlobalRules(namespace).Get(name)
+ if err != nil {
+ return nil, err
+ }
+ return &apisixGlobalRule{
+ groupVersion: config.ApisixV2,
+ v2: agr,
+ }, nil
+ default:
+ panic("invalid ApisixGlobalRule group version")
+ }
+}
+
+// MustNewApisixGlobalRule creates a kube.ApisixGlobalRule object according to
the
+// type of obj.
+func MustNewApisixGlobalRule(obj interface{}) ApisixGlobalRule {
+ switch agr := obj.(type) {
+ case *configv2.ApisixGlobalRule:
+ return &apisixGlobalRule{
+ groupVersion: config.ApisixV2,
+ v2: agr,
+ Object: agr.GetObjectMeta(),
+ }
+ default:
+ panic("invalid ApisixGlobalRule type")
+ }
+}
+
+// NewApisixGlobalRule creates a kube.ApisixGlobalRule object according to the
+// type of obj. It returns nil and the error reason when the
+// type assertion fails.
+func NewApisixGlobalRule(obj interface{}) (ApisixGlobalRule, error) {
+ switch agr := obj.(type) {
+ case *configv2.ApisixGlobalRule:
+ return &apisixGlobalRule{
+ groupVersion: config.ApisixV2,
+ v2: agr,
+ Object: agr.GetObjectMeta(),
+ }, nil
+ default:
+ return nil, errors.New("invalid ApisixGlobalRule type")
+ }
+}
+
+func NewApisixGlobalRuleLister(apiVersion string, v2
listersv2.ApisixGlobalRuleLister) ApisixGlobalRuleLister {
+ return &apisixGlobalRuleLister{
+ groupVersion: apiVersion,
+ v2Lister: v2,
+ }
+}
diff --git a/pkg/providers/apisix/apisix_global_rule.go
b/pkg/providers/apisix/apisix_global_rule.go
new file mode 100644
index 00000000..c15d3e83
--- /dev/null
+++ b/pkg/providers/apisix/apisix_global_rule.go
@@ -0,0 +1,391 @@
+// 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 apisix
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "go.uber.org/zap"
+ v1 "k8s.io/api/core/v1"
+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/tools/cache"
+ "k8s.io/client-go/util/workqueue"
+
+ "github.com/apache/apisix-ingress-controller/pkg/config"
+ "github.com/apache/apisix-ingress-controller/pkg/kube"
+ configv2
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
+ "github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/utils"
+ "github.com/apache/apisix-ingress-controller/pkg/types"
+)
+
+type apisixGlobalRuleController struct {
+ *apisixCommon
+
+ workqueue workqueue.RateLimitingInterface
+ workers int
+}
+
+func newApisixGlobalRuleController(common *apisixCommon)
*apisixGlobalRuleController {
+ c := &apisixGlobalRuleController{
+ apisixCommon: common,
+ workqueue:
workqueue.NewNamedRateLimitingQueue(workqueue.NewItemFastSlowRateLimiter(1*time.Second,
60*time.Second, 5), "ApisixGlobalRule"),
+ workers: 1,
+ }
+
+ c.ApisixGlobalRuleInformer.AddEventHandler(
+ cache.ResourceEventHandlerFuncs{
+ AddFunc: c.onAdd,
+ UpdateFunc: c.onUpdate,
+ DeleteFunc: c.onDelete,
+ },
+ )
+ return c
+}
+
+func (c *apisixGlobalRuleController) run(ctx context.Context) {
+ log.Info("ApisixGlobalRule controller started")
+ defer log.Info("ApisixGlobalRule controller exited")
+ defer c.workqueue.ShutDown()
+
+ for i := 0; i < c.workers; i++ {
+ go c.runWorker(ctx)
+ }
+ <-ctx.Done()
+}
+
+func (c *apisixGlobalRuleController) runWorker(ctx context.Context) {
+ for {
+ obj, quit := c.workqueue.Get()
+ if quit {
+ return
+ }
+ err := c.sync(ctx, obj.(*types.Event))
+ c.workqueue.Done(obj)
+ c.handleSyncErr(obj, err)
+ }
+}
+
+func (c *apisixGlobalRuleController) sync(ctx context.Context, ev
*types.Event) error {
+ obj := ev.Object.(kube.ApisixGlobalRuleEvent)
+ namespace, name, err := cache.SplitMetaNamespaceKey(obj.Key)
+ if err != nil {
+ log.Errorf("invalid resource key: %s", obj.Key)
+ return err
+ }
+ var (
+ agr kube.ApisixGlobalRule
+ )
+ agr, err = c.ApisixGlobalRuleLister.ApisixGlobalRule(namespace, name)
+ if err != nil {
+ if !k8serrors.IsNotFound(err) {
+ log.Errorw("failed to get ApisixGlobalRule",
+ zap.String("version", obj.GroupVersion),
+ zap.String("key", obj.Key),
+ zap.Error(err),
+ )
+ return err
+ }
+
+ if ev.Type != types.EventDelete {
+ log.Warnw("ApisixGlobalRule was deleted before it can
be delivered",
+ zap.String("key", obj.Key),
+ zap.String("version", obj.GroupVersion),
+ )
+ return nil
+ }
+ }
+ if ev.Type == types.EventDelete {
+ if agr != nil {
+ // We still find the resource while we are processing
the DELETE event,
+ // that means object with same namespace and name was
created, discarding
+ // this stale DELETE event.
+ log.Warnw("discard the stale ApisixGlobalRule delete
event since the resource still exists",
+ zap.String("key", obj.Key),
+ )
+ return nil
+ }
+ agr = ev.Tombstone.(kube.ApisixGlobalRule)
+ }
+
+ tctx, err := c.translator.TranslateGlobalRule(agr)
+ if err != nil {
+ log.Errorw("failed to translate ApisixRoute v2",
+ zap.Error(err),
+ zap.Any("object", agr),
+ )
+ return err
+ }
+
+ m := &utils.Manifest{
+ GlobalRules: tctx.GlobalRules,
+ }
+
+ var (
+ added *utils.Manifest
+ updated *utils.Manifest
+ deleted *utils.Manifest
+ )
+
+ if ev.Type == types.EventDelete {
+ deleted = m
+ } else if ev.Type == types.EventAdd {
+ added = m
+ } else {
+ oldCtx, err := c.translator.TranslateGlobalRule(obj.OldObject)
+ if err != nil {
+ log.Errorw("failed to translate old ApisixGlobalRule",
+ zap.String("version", obj.GroupVersion),
+ zap.String("event", "update"),
+ zap.Error(err),
+ zap.Any("ApisixGlobalRule", agr),
+ )
+ } else {
+ om := &utils.Manifest{
+ GlobalRules: oldCtx.GlobalRules,
+ }
+ added, updated, deleted = m.Diff(om)
+ }
+ }
+ log.Debugw("sync ApisixGlaobalRule to cluster",
+ zap.String("event_type", ev.Type.String()),
+ zap.Any("add", added),
+ zap.Any("update", updated),
+ zap.Any("delete", deleted),
+ )
+ return c.SyncManifests(ctx, added, updated, deleted)
+}
+
+func (c *apisixGlobalRuleController) handleSyncErr(obj interface{}, errOrigin
error) {
+ ev := obj.(*types.Event)
+ event := ev.Object.(kube.ApisixGlobalRuleEvent)
+ if k8serrors.IsNotFound(errOrigin) && ev.Type != types.EventDelete {
+ log.Infow("sync ApisixGlobalRule but not found, ignore",
+ zap.String("event_type", ev.Type.String()),
+ zap.String("ApisixGlobalRule",
ev.Object.(kube.ApisixGlobalRuleEvent).Key),
+ )
+ c.workqueue.Forget(event)
+ return
+ }
+ namespace, name, errLocal := cache.SplitMetaNamespaceKey(event.Key)
+ if errLocal != nil {
+ log.Errorf("invalid resource key: %s", event.Key)
+ c.MetricsCollector.IncrSyncOperation("GlobalRule", "failure")
+ return
+ }
+ var agr kube.ApisixGlobalRule
+ switch event.GroupVersion {
+ case config.ApisixV2:
+ agr, errLocal = c.ApisixGlobalRuleLister.V2(namespace, name)
+ default:
+ errLocal = fmt.Errorf("unsupported ApisixGlobalRule group
version %s", event.GroupVersion)
+ }
+ if errOrigin == nil {
+ if ev.Type != types.EventDelete {
+ if errLocal == nil {
+ switch agr.GroupVersion() {
+ case config.ApisixV2:
+ c.RecordEvent(agr.V2(),
v1.EventTypeNormal, utils.ResourceSynced, nil)
+ c.recordStatus(agr.V2(),
utils.ResourceSynced, nil, metav1.ConditionTrue, agr.GetGeneration())
+ }
+ } else {
+ log.Errorw("failed list ApisixGlobalRule",
+ zap.Error(errLocal),
+ zap.String("name", name),
+ zap.String("namespace", namespace),
+ )
+ }
+ }
+ c.workqueue.Forget(obj)
+ c.MetricsCollector.IncrSyncOperation("GlobalRule", "success")
+ return
+ }
+ log.Warnw("sync ApisixGlobalRule failed, will retry",
+ zap.Any("object", obj),
+ zap.Error(errOrigin),
+ )
+ if errLocal == nil {
+ switch agr.GroupVersion() {
+ case config.ApisixV2:
+ c.RecordEvent(agr.V2(), v1.EventTypeWarning,
utils.ResourceSyncAborted, errOrigin)
+ c.recordStatus(agr.V2(), utils.ResourceSyncAborted,
errOrigin, metav1.ConditionFalse, agr.GetGeneration())
+ }
+ } else {
+ log.Errorw("failed list ApisixGlobalRule",
+ zap.Error(errLocal),
+ zap.String("name", name),
+ zap.String("namespace", namespace),
+ )
+ }
+ c.workqueue.AddRateLimited(obj)
+ c.MetricsCollector.IncrSyncOperation("GlobalRule", "failure")
+}
+
+func (c *apisixGlobalRuleController) onAdd(obj interface{}) {
+ key, err := cache.MetaNamespaceKeyFunc(obj)
+ if err != nil {
+ log.Errorf("found ApisixGlobalRule resource with bad meta
namespace key: %s", err)
+ return
+ }
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
+ return
+ }
+ log.Debugw("ApisixGlobalRule add event arrived",
+ zap.Any("object", obj))
+
+ agr := kube.MustNewApisixGlobalRule(obj)
+ c.workqueue.Add(&types.Event{
+ Type: types.EventAdd,
+ Object: kube.ApisixGlobalRuleEvent{
+ Key: key,
+ GroupVersion: agr.GroupVersion(),
+ },
+ })
+
+ c.MetricsCollector.IncrEvents("GlobalRule", "add")
+}
+
+func (c *apisixGlobalRuleController) onUpdate(oldObj, newObj interface{}) {
+ prev := kube.MustNewApisixGlobalRule(oldObj)
+ curr := kube.MustNewApisixGlobalRule(newObj)
+ if prev.ResourceVersion() >= curr.ResourceVersion() {
+ return
+ }
+ key, err := cache.MetaNamespaceKeyFunc(newObj)
+ if err != nil {
+ log.Errorf("found ApisixGlobalRule resource with bad meta
namespace key: %s", err)
+ return
+ }
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
+ return
+ }
+ log.Debugw("ApisixGlobalRule update event arrived",
+ zap.Any("new object", curr),
+ zap.Any("old object", prev),
+ )
+ c.workqueue.Add(&types.Event{
+ Type: types.EventUpdate,
+ Object: kube.ApisixGlobalRuleEvent{
+ Key: key,
+ GroupVersion: curr.GroupVersion(),
+ OldObject: prev,
+ },
+ })
+
+ c.MetricsCollector.IncrEvents("GlobalRule", "update")
+}
+
+func (c *apisixGlobalRuleController) onDelete(obj interface{}) {
+ agr, err := kube.NewApisixGlobalRule(obj)
+ if err != nil {
+ tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
+ if !ok {
+ return
+ }
+ agr = kube.MustNewApisixGlobalRule(tombstone)
+ }
+ key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
+ if err != nil {
+ log.Errorf("found ApisixGlobalRule resource with bad meta
namesagre key: %s", err)
+ return
+ }
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
+ return
+ }
+ log.Debugw("ApisixGlobalRule delete event arrived",
+ zap.Any("final state", agr),
+ )
+ c.workqueue.Add(&types.Event{
+ Type: types.EventDelete,
+ Object: kube.ApisixGlobalRuleEvent{
+ Key: key,
+ GroupVersion: agr.GroupVersion(),
+ },
+ Tombstone: agr,
+ })
+
+ c.MetricsCollector.IncrEvents("GlobalRule", "delete")
+}
+
+func (c *apisixGlobalRuleController) ResourceSync() {
+ objs := c.ApisixGlobalRuleInformer.GetIndexer().List()
+ for _, obj := range objs {
+ key, err := cache.MetaNamespaceKeyFunc(obj)
+ if err != nil {
+ log.Errorw("ApisixGlobalRule sync failed, found
ApisixGlobalRule resource with bad meta namespace key", zap.String("error",
err.Error()))
+ continue
+ }
+ if !c.namespaceProvider.IsWatchingNamespace(key) {
+ continue
+ }
+ agr := kube.MustNewApisixGlobalRule(obj)
+ c.workqueue.Add(&types.Event{
+ Type: types.EventAdd,
+ Object: kube.ApisixGlobalRuleEvent{
+ Key: key,
+ GroupVersion: agr.GroupVersion(),
+ },
+ })
+ }
+}
+
+// recordStatus record resources status
+func (c *apisixGlobalRuleController) recordStatus(at interface{}, reason
string, err error, status metav1.ConditionStatus, generation int64) {
+ // build condition
+ message := utils.CommonSuccessMessage
+ if err != nil {
+ message = err.Error()
+ }
+ condition := metav1.Condition{
+ Type: utils.ConditionType,
+ Reason: reason,
+ Status: status,
+ Message: message,
+ ObservedGeneration: generation,
+ }
+ apisixClient := c.KubeClient.APISIXClient
+
+ if kubeObj, ok := at.(runtime.Object); ok {
+ at = kubeObj.DeepCopyObject()
+ }
+
+ switch v := at.(type) {
+ case *configv2.ApisixGlobalRule:
+ // set to status
+ if v.Status.Conditions == nil {
+ conditions := make([]metav1.Condition, 0)
+ v.Status.Conditions = conditions
+ }
+ if utils.VerifyGeneration(&v.Status.Conditions, condition) &&
!meta.IsStatusConditionPresentAndEqual(v.Status.Conditions, condition.Type,
condition.Status) {
+ meta.SetStatusCondition(&v.Status.Conditions, condition)
+ if _, errRecord :=
apisixClient.ApisixV2().ApisixGlobalRules(v.Namespace).
+ UpdateStatus(context.TODO(), v,
metav1.UpdateOptions{}); errRecord != nil {
+ log.Errorw("failed to record status change for
ApisixGlobalRule",
+ zap.Error(errRecord),
+ zap.String("name", v.Name),
+ zap.String("namespace", v.Namespace),
+ )
+ }
+ }
+ default:
+ // This should not be executed
+ log.Errorf("unsupported resource record: %s", v)
+ }
+}
diff --git a/pkg/providers/apisix/provider.go b/pkg/providers/apisix/provider.go
index 150da89c..503b0723 100644
--- a/pkg/providers/apisix/provider.go
+++ b/pkg/providers/apisix/provider.go
@@ -21,6 +21,7 @@ import (
corev1 "k8s.io/api/core/v1"
+ "github.com/apache/apisix-ingress-controller/pkg/config"
apisixtranslation
"github.com/apache/apisix-ingress-controller/pkg/providers/apisix/translation"
"github.com/apache/apisix-ingress-controller/pkg/providers/k8s/namespace"
"github.com/apache/apisix-ingress-controller/pkg/providers/translation"
@@ -65,6 +66,7 @@ type apisixProvider struct {
apisixClusterConfigController *apisixClusterConfigController
apisixConsumerController *apisixConsumerController
apisixPluginConfigController *apisixPluginConfigController
+ apisixGlobalRuleController *apisixGlobalRuleController
}
func NewProvider(common *providertypes.Common, namespaceProvider
namespace.WatchingNamespaceProvider,
@@ -94,6 +96,9 @@ func NewProvider(common *providertypes.Common,
namespaceProvider namespace.Watch
p.apisixClusterConfigController = newApisixClusterConfigController(c)
p.apisixConsumerController = newApisixConsumerController(c)
p.apisixPluginConfigController = newApisixPluginConfigController(c)
+ if p.common.Kubernetes.APIVersion == config.ApisixV2 {
+ p.apisixGlobalRuleController = newApisixGlobalRuleController(c)
+ }
return p, p.apisixTranslator, nil
}
@@ -119,6 +124,11 @@ func (p *apisixProvider) Run(ctx context.Context) {
e.Add(func() {
p.apisixPluginConfigController.run(ctx)
})
+ if p.common.Kubernetes.APIVersion == config.ApisixV2 {
+ e.Add(func() {
+ p.apisixGlobalRuleController.run(ctx)
+ })
+ }
e.Wait()
}
diff --git a/pkg/providers/apisix/translation/apisix_global_rule.go
b/pkg/providers/apisix/translation/apisix_global_rule.go
new file mode 100644
index 00000000..3afa76da
--- /dev/null
+++ b/pkg/providers/apisix/translation/apisix_global_rule.go
@@ -0,0 +1,77 @@
+// 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 (
+ "fmt"
+
+ "go.uber.org/zap"
+
+ "github.com/apache/apisix-ingress-controller/pkg/config"
+ "github.com/apache/apisix-ingress-controller/pkg/id"
+ "github.com/apache/apisix-ingress-controller/pkg/kube"
+ configv2
"github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2"
+ "github.com/apache/apisix-ingress-controller/pkg/log"
+ "github.com/apache/apisix-ingress-controller/pkg/providers/translation"
+ apisixv1
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
+
+func (t *translator) TranslateGlobalRule(agr kube.ApisixGlobalRule)
(*translation.TranslateContext, error) {
+ switch agr.GroupVersion() {
+ case config.ApisixV2:
+ return t.translateGlobalRuleV2(agr.V2())
+ default:
+ return nil, fmt.Errorf("translator: source group version not
supported: %s", agr.GroupVersion())
+ }
+}
+
+func (t *translator) translateGlobalRuleV2(config *configv2.ApisixGlobalRule)
(*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
+ pluginMap := make(apisixv1.Plugins)
+ if len(config.Spec.Plugins) > 0 {
+ for _, plugin := range config.Spec.Plugins {
+ if !plugin.Enable {
+ continue
+ }
+
+ if plugin.Config != nil {
+ // Here, it will override same key.
+ if t, ok := pluginMap[plugin.Name]; ok {
+ log.Infow("TranslateGlobalRuleV2
override same plugin key",
+ zap.String("key", plugin.Name),
+ zap.Any("old", t),
+ zap.Any("new", plugin.Config),
+ )
+ }
+ pluginMap[plugin.Name] = plugin.Config
+ } else {
+ pluginMap[plugin.Name] =
make(map[string]interface{})
+ }
+ }
+ }
+ pc := apisixv1.NewDefaultGlobalRule()
+ pc.ID = id.GenID(apisixv1.ComposeGlobalRuleName(config.Namespace,
config.Name))
+ pc.Plugins = pluginMap
+ ctx.AddGlobalRule(pc)
+ return ctx, nil
+}
+
+func (t *translator) GenerateGlobalRuleV2DeleteMark(config
*configv2.ApisixGlobalRule) (*translation.TranslateContext, error) {
+ ctx := translation.DefaultEmptyTranslateContext()
+ pc := apisixv1.NewDefaultGlobalRule()
+ pc.ID = id.GenID(apisixv1.ComposeGlobalRuleName(config.Namespace,
config.Name))
+ ctx.AddGlobalRule(pc)
+ return ctx, nil
+}
diff --git a/pkg/providers/apisix/translation/translator.go
b/pkg/providers/apisix/translation/translator.go
index faed02ce..192f4cd7 100644
--- a/pkg/providers/apisix/translation/translator.go
+++ b/pkg/providers/apisix/translation/translator.go
@@ -92,6 +92,8 @@ type ApisixTranslator interface {
// TranslateApisixUpstreamExternalNodes translates an ApisixUpstream
with external nodes to APISIX nodes.
TranslateApisixUpstreamExternalNodes(au *configv2.ApisixUpstream)
([]apisixv1.UpstreamNode, error)
+
+ TranslateGlobalRule(kube.ApisixGlobalRule)
(*translation.TranslateContext, error)
}
func NewApisixTranslator(opts *TranslatorOptions, t translation.Translator)
ApisixTranslator {
diff --git a/pkg/providers/controller.go b/pkg/providers/controller.go
index 592d49cb..463609c0 100644
--- a/pkg/providers/controller.go
+++ b/pkg/providers/controller.go
@@ -237,6 +237,7 @@ func (c *Controller) initSharedInformers()
*providertypes.ListerInformer {
apisixConsumerInformer cache.SharedIndexInformer
apisixTlsInformer cache.SharedIndexInformer
apisixClusterConfigInformer cache.SharedIndexInformer
+ ApisixGlobalRuleInformer cache.SharedIndexInformer
apisixRouteListerV2beta3 v2beta3.ApisixRouteLister
apisixUpstreamListerV2beta3 v2beta3.ApisixUpstreamLister
@@ -251,6 +252,7 @@ func (c *Controller) initSharedInformers()
*providertypes.ListerInformer {
apisixClusterConfigListerV2 v2.ApisixClusterConfigLister
apisixConsumerListerV2 v2.ApisixConsumerLister
apisixPluginConfigListerV2 v2.ApisixPluginConfigLister
+ ApisixGlobalRuleListerV2 v2.ApisixGlobalRuleLister
)
switch c.cfg.Kubernetes.APIVersion {
@@ -275,6 +277,7 @@ func (c *Controller) initSharedInformers()
*providertypes.ListerInformer {
apisixConsumerInformer =
apisixFactory.Apisix().V2().ApisixConsumers().Informer()
apisixPluginConfigInformer =
apisixFactory.Apisix().V2().ApisixPluginConfigs().Informer()
apisixUpstreamInformer =
apisixFactory.Apisix().V2().ApisixUpstreams().Informer()
+ ApisixGlobalRuleInformer =
apisixFactory.Apisix().V2().ApisixGlobalRules().Informer()
apisixRouteListerV2 =
apisixFactory.Apisix().V2().ApisixRoutes().Lister()
apisixUpstreamListerV2 =
apisixFactory.Apisix().V2().ApisixUpstreams().Lister()
@@ -282,6 +285,8 @@ func (c *Controller) initSharedInformers()
*providertypes.ListerInformer {
apisixClusterConfigListerV2 =
apisixFactory.Apisix().V2().ApisixClusterConfigs().Lister()
apisixConsumerListerV2 =
apisixFactory.Apisix().V2().ApisixConsumers().Lister()
apisixPluginConfigListerV2 =
apisixFactory.Apisix().V2().ApisixPluginConfigs().Lister()
+ ApisixGlobalRuleListerV2 =
apisixFactory.Apisix().V2().ApisixGlobalRules().Lister()
+
default:
panic(fmt.Errorf("unsupported API version %v",
c.cfg.Kubernetes.APIVersion))
}
@@ -292,6 +297,7 @@ func (c *Controller) initSharedInformers()
*providertypes.ListerInformer {
apisixClusterConfigLister :=
kube.NewApisixClusterConfigLister(apisixClusterConfigListerV2beta3,
apisixClusterConfigListerV2)
apisixConsumerLister :=
kube.NewApisixConsumerLister(apisixConsumerListerV2beta3,
apisixConsumerListerV2)
apisixPluginConfigLister :=
kube.NewApisixPluginConfigLister(apisixPluginConfigListerV2beta3,
apisixPluginConfigListerV2)
+ ApisixGlobalRuleLister :=
kube.NewApisixGlobalRuleLister(c.cfg.Kubernetes.APIVersion,
ApisixGlobalRuleListerV2)
epLister, epInformer := kube.NewEndpointListerAndInformer(kubeFactory,
c.cfg.Kubernetes.WatchEndpointSlices)
svcInformer := kubeFactory.Core().V1().Services().Informer()
@@ -343,6 +349,7 @@ func (c *Controller) initSharedInformers()
*providertypes.ListerInformer {
ApisixTlsLister: apisixTlsLister,
ApisixPluginConfigLister: apisixPluginConfigLister,
ApisixClusterConfigLister: apisixClusterConfigLister,
+ ApisixGlobalRuleLister: ApisixGlobalRuleLister,
ApisixUpstreamInformer: apisixUpstreamInformer,
ApisixPluginConfigInformer: apisixPluginConfigInformer,
@@ -350,6 +357,7 @@ func (c *Controller) initSharedInformers()
*providertypes.ListerInformer {
ApisixClusterConfigInformer: apisixClusterConfigInformer,
ApisixConsumerInformer: apisixConsumerInformer,
ApisixTlsInformer: apisixTlsInformer,
+ ApisixGlobalRuleInformer: ApisixGlobalRuleInformer,
}
return listerInformer
diff --git a/pkg/providers/translation/context.go
b/pkg/providers/translation/context.go
index 7f5d032b..3a9744c6 100644
--- a/pkg/providers/translation/context.go
+++ b/pkg/providers/translation/context.go
@@ -24,6 +24,7 @@ type TranslateContext struct {
UpstreamMap map[string]struct{}
SSL []*apisix.Ssl
PluginConfigs []*apisix.PluginConfig
+ GlobalRules []*apisix.GlobalRule
}
func DefaultEmptyTranslateContext() *TranslateContext {
@@ -60,3 +61,7 @@ func (tc *TranslateContext) CheckUpstreamExist(name string)
(ok bool) {
func (tc *TranslateContext) AddPluginConfig(pc *apisix.PluginConfig) {
tc.PluginConfigs = append(tc.PluginConfigs, pc)
}
+
+func (tc *TranslateContext) AddGlobalRule(gr *apisix.GlobalRule) {
+ tc.GlobalRules = append(tc.GlobalRules, gr)
+}
diff --git a/pkg/providers/types/types.go b/pkg/providers/types/types.go
index 8dddd791..f55d3bdc 100644
--- a/pkg/providers/types/types.go
+++ b/pkg/providers/types/types.go
@@ -75,6 +75,7 @@ type ListerInformer struct {
ApisixConsumerInformer cache.SharedIndexInformer
ApisixTlsInformer cache.SharedIndexInformer
ApisixClusterConfigInformer cache.SharedIndexInformer
+ ApisixGlobalRuleInformer cache.SharedIndexInformer
ApisixRouteLister kube.ApisixRouteLister
ApisixUpstreamLister kube.ApisixUpstreamLister
@@ -82,6 +83,7 @@ type ListerInformer struct {
ApisixConsumerLister kube.ApisixConsumerLister
ApisixTlsLister kube.ApisixTlsLister
ApisixClusterConfigLister kube.ApisixClusterConfigLister
+ ApisixGlobalRuleLister kube.ApisixGlobalRuleLister
}
func (c *ListerInformer) StartAndWaitForCacheSync(ctx context.Context) bool {
diff --git a/pkg/providers/utils/manifest.go b/pkg/providers/utils/manifest.go
index 9a37aa52..a87f0dd4 100644
--- a/pkg/providers/utils/manifest.go
+++ b/pkg/providers/utils/manifest.go
@@ -191,6 +191,31 @@ func DiffPluginMetadatas(olds, news
[]*apisixv1.PluginMetadata) (added, updated,
return
}
+func DiffGlobalRules(olds, news []*apisixv1.GlobalRule) (added, updated,
deleted []*apisixv1.GlobalRule) {
+ oldMap := make(map[string]*apisixv1.GlobalRule, len(olds))
+ newMap := make(map[string]*apisixv1.GlobalRule, len(news))
+ for _, gr := range olds {
+ oldMap[gr.ID] = gr
+ }
+ for _, gr := range news {
+ newMap[gr.ID] = gr
+ }
+
+ for _, gr := range news {
+ if ou, ok := oldMap[gr.ID]; !ok {
+ added = append(added, gr)
+ } else if !reflect.DeepEqual(ou, gr) {
+ updated = append(updated, gr)
+ }
+ }
+ for _, gr := range olds {
+ if _, ok := newMap[gr.ID]; !ok {
+ deleted = append(deleted, gr)
+ }
+ }
+ return
+}
+
type Manifest struct {
Routes []*apisixv1.Route
Upstreams []*apisixv1.Upstream
@@ -198,6 +223,7 @@ type Manifest struct {
SSLs []*apisixv1.Ssl
PluginConfigs []*apisixv1.PluginConfig
PluginMetadatas []*apisixv1.PluginMetadata
+ GlobalRules []*apisixv1.GlobalRule
}
func (m *Manifest) Diff(om *Manifest) (added, updated, deleted *Manifest) {
@@ -207,6 +233,7 @@ func (m *Manifest) Diff(om *Manifest) (added, updated,
deleted *Manifest) {
asr, usr, dsr := DiffStreamRoutes(om.StreamRoutes, m.StreamRoutes)
apc, upc, dpc := DiffPluginConfigs(om.PluginConfigs, m.PluginConfigs)
apm, upm, dpm := DiffPluginMetadatas(om.PluginMetadatas,
m.PluginMetadatas)
+ agr, ugr, dgr := DiffGlobalRules(om.GlobalRules, m.GlobalRules)
added = &Manifest{
Routes: ar,
@@ -215,6 +242,7 @@ func (m *Manifest) Diff(om *Manifest) (added, updated,
deleted *Manifest) {
SSLs: sa,
PluginConfigs: apc,
PluginMetadatas: apm,
+ GlobalRules: agr,
}
updated = &Manifest{
Routes: ur,
@@ -223,6 +251,7 @@ func (m *Manifest) Diff(om *Manifest) (added, updated,
deleted *Manifest) {
SSLs: su,
PluginConfigs: upc,
PluginMetadatas: upm,
+ GlobalRules: ugr,
}
deleted = &Manifest{
Routes: dr,
@@ -231,6 +260,7 @@ func (m *Manifest) Diff(om *Manifest) (added, updated,
deleted *Manifest) {
SSLs: sd,
PluginConfigs: dpc,
PluginMetadatas: dpm,
+ GlobalRules: dgr,
}
return
}
@@ -271,6 +301,11 @@ func SyncManifests(ctx context.Context, apisix
apisix.APISIX, clusterName string
merr = multierror.Append(merr, err)
}
}
+ for _, gr := range added.GlobalRules {
+ if _, err :=
apisix.Cluster(clusterName).GlobalRule().Create(ctx, gr); err != nil {
+ merr = multierror.Append(merr, err)
+ }
+ }
}
if updated != nil {
for _, ssl := range updated.SSLs {
@@ -303,6 +338,11 @@ func SyncManifests(ctx context.Context, apisix
apisix.APISIX, clusterName string
merr = multierror.Append(merr, err)
}
}
+ for _, gr := range updated.GlobalRules {
+ if _, err :=
apisix.Cluster(clusterName).GlobalRule().Update(ctx, gr); err != nil {
+ merr = multierror.Append(merr, err)
+ }
+ }
}
if deleted != nil {
for _, ssl := range deleted.SSLs {
@@ -404,6 +444,11 @@ func SyncManifests(ctx context.Context, apisix
apisix.APISIX, clusterName string
merr = multierror.Append(merr, err)
}
}
+ for _, gr := range deleted.GlobalRules {
+ if err :=
apisix.Cluster(clusterName).GlobalRule().Delete(ctx, gr); err != nil {
+ merr = multierror.Append(merr, err)
+ }
+ }
}
if merr != nil {
return merr
diff --git a/pkg/types/apisix/v1/types.go b/pkg/types/apisix/v1/types.go
index e59a2f19..04ed3be5 100644
--- a/pkg/types/apisix/v1/types.go
+++ b/pkg/types/apisix/v1/types.go
@@ -474,8 +474,8 @@ type StreamRoute struct {
// GlobalRule represents the global_rule object in APISIX.
// +k8s:deepcopy-gen=true
type GlobalRule struct {
- ID string `json:"id,omitempty" yaml:"id,omitempty"`
- Plugins Plugins `json:"plugins,omitempty" yaml:"plugins,omitempty"`
+ ID string `json:"id" yaml:"id"`
+ Plugins Plugins `json:"plugins" yaml:"plugins"`
}
// Consumer represents the consumer object in APISIX.
@@ -567,6 +567,13 @@ func NewDefaultPluginConfig() *PluginConfig {
}
}
+// NewDefaultGlobalRule returns an empty PluginConfig with default values.
+func NewDefaultGlobalRule() *GlobalRule {
+ return &GlobalRule{
+ Plugins: make(Plugins),
+ }
+}
+
// ComposeUpstreamName uses namespace, name, subset (optional), port,
resolveGranularity info to compose
// the upstream name.
// the resolveGranularity is not composited in the upstream name when it is
endpoint.
@@ -657,7 +664,7 @@ func ComposeConsumerName(namespace, name string) string {
}
// ComposePluginConfigName uses namespace, name to compose
-// the route name.
+// the plugin_config name.
func ComposePluginConfigName(namespace, name string) string {
// FIXME Use sync.Pool to reuse this buffer if the upstream
// name composing code path is hot.
@@ -671,6 +678,21 @@ func ComposePluginConfigName(namespace, name string)
string {
return buf.String()
}
+// ComposeGlobalRuleName uses namespace, name to compose
+// the global_rule name.
+func ComposeGlobalRuleName(namespace, name string) string {
+ // FIXME Use sync.Pool to reuse this buffer if the upstream
+ // name composing code path is hot.
+ p := make([]byte, 0, len(namespace)+len(name)+1)
+ buf := bytes.NewBuffer(p)
+
+ buf.WriteString(namespace)
+ buf.WriteByte('_')
+ buf.WriteString(name)
+
+ return buf.String()
+}
+
// Schema represents the schema of APISIX objects.
type Schema struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
diff --git a/samples/deploy/crd/v1/ApisixGlobalRule.yaml
b/samples/deploy/crd/v1/ApisixGlobalRule.yaml
new file mode 100644
index 00000000..0c461db9
--- /dev/null
+++ b/samples/deploy/crd/v1/ApisixGlobalRule.yaml
@@ -0,0 +1,86 @@
+#
+# 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.
+#
+
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: apisixglobalrules.apisix.apache.org
+spec:
+ group: apisix.apache.org
+ scope: Namespaced
+ names:
+ plural: apisixglobalrules
+ singular: apisixglobalrule
+ kind: ApisixGlobalRule
+ shortNames:
+ - agr
+ versions:
+ - name: v2
+ served: true
+ storage: true
+ subresources:
+ status: {}
+ additionalPrinterColumns:
+ - jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ priority: 0
+ schema:
+ openAPIV3Schema:
+ type: object
+ properties:
+ spec:
+ type: object
+ required:
+ - plugins
+ properties:
+ plugins:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ minLength: 1
+ enable:
+ type: boolean
+ config:
+ type: object
+ x-kubernetes-preserve-unknown-fields: true # we have
to enable it since plugin config
+ secretRef:
+ type: string
+ required:
+ - name
+ - enable
+ status:
+ type: object
+ properties:
+ conditions:
+ type: array
+ items:
+ type: object
+ properties:
+ "type":
+ type: string
+ reason:
+ type: string
+ status:
+ type: string
+ message:
+ type: string
+ observedGeneration:
+ type: integer
diff --git a/samples/deploy/crd/v1/kustomization.yaml
b/samples/deploy/crd/v1/kustomization.yaml
index 3ef0cda2..5956f580 100644
--- a/samples/deploy/crd/v1/kustomization.yaml
+++ b/samples/deploy/crd/v1/kustomization.yaml
@@ -22,3 +22,4 @@ resources:
- ./ApisixClusterConfig.yaml
- ./ApisixConsumer.yaml
- ./ApisixPluginConfig.yaml
+ - ./ApisixGlobalRule.yaml
diff --git a/test/e2e/scaffold/ingress.go b/test/e2e/scaffold/ingress.go
index d0617bc9..87e639d9 100644
--- a/test/e2e/scaffold/ingress.go
+++ b/test/e2e/scaffold/ingress.go
@@ -171,6 +171,8 @@ rules:
- apisixconsumers/status
- apisixpluginconfigs
- apisixpluginconfigs/status
+ - apisixglobalrules
+ - apisixglobalrules/status
verbs:
- '*'
- apiGroups:
diff --git a/test/e2e/suite-features/global_rule.go
b/test/e2e/suite-features/global_rule.go
index a690d46f..95979911 100644
--- a/test/e2e/suite-features/global_rule.go
+++ b/test/e2e/suite-features/global_rule.go
@@ -88,3 +88,118 @@ spec:
suites(scaffold.NewDefaultV2Scaffold)
})
})
+
+var _ = ginkgo.Describe("suite-features: ApisiGlobalRule", func() {
+ s := scaffold.NewDefaultScaffold()
+
+ ginkgo.It("enable echo global rule in apisix", func() {
+ agr := `
+apiVersion: apisix.apache.org/v2
+kind: ApisixGlobalRule
+metadata:
+ name: test-agr-1
+spec:
+ plugins:
+ - name: echo
+ enable: true
+ config:
+ body: "hello, world!!"
+`
+ assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(agr),
"creating ApisixGlobalRule")
+ time.Sleep(6 * time.Second)
+
+ grs, err := s.ListApisixGlobalRules()
+ assert.Nil(ginkgo.GinkgoT(), err, "listing global_rules")
+ assert.Len(ginkgo.GinkgoT(), grs, 1)
+ assert.Len(ginkgo.GinkgoT(), grs[0].Plugins, 1)
+ _, ok := grs[0].Plugins["echo"]
+ assert.Equal(ginkgo.GinkgoT(), ok, true)
+
+
s.NewAPISIXClient().GET("/anything").Expect().Body().Contains("hello, world!!")
+
+
s.NewAPISIXClient().GET("/hello").Expect().Body().Contains("hello, world!!")
+ })
+
+ ginkgo.It("disable echo global rule in apisix", func() {
+ agr := `
+apiVersion: apisix.apache.org/v2
+kind: ApisixGlobalRule
+metadata:
+ name: test-agr-1
+spec:
+ plugins:
+ - name: echo
+ enable: true
+ config:
+ body: "hello, world!!"
+`
+ assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(agr),
"creating ApisixGlobalRule")
+ time.Sleep(6 * time.Second)
+
+ grs, err := s.ListApisixGlobalRules()
+ assert.Nil(ginkgo.GinkgoT(), err, "listing global_rules")
+ assert.Len(ginkgo.GinkgoT(), grs, 1)
+ assert.Len(ginkgo.GinkgoT(), grs[0].Plugins, 1)
+ _, ok := grs[0].Plugins["echo"]
+ assert.Equal(ginkgo.GinkgoT(), ok, true)
+
+
s.NewAPISIXClient().GET("/anything").Expect().Body().Contains("hello, world!!")
+
s.NewAPISIXClient().GET("/hello").Expect().Body().Contains("hello, world!!")
+
+ agr = `
+apiVersion: apisix.apache.org/v2
+kind: ApisixGlobalRule
+metadata:
+ name: test-agr-1
+spec:
+ plugins:
+ - name: echo
+ enable: false
+ config:
+ body: "hello, world!!"
+`
+ assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(agr),
"creating ApisixGlobalRule")
+ time.Sleep(6 * time.Second)
+
+ grs, err = s.ListApisixGlobalRules()
+ assert.Nil(ginkgo.GinkgoT(), err, "listing global_rules")
+ assert.Len(ginkgo.GinkgoT(), grs, 1)
+ _, ok = grs[0].Plugins["echo"]
+ assert.Equal(ginkgo.GinkgoT(), ok, false)
+
+
s.NewAPISIXClient().GET("/anything").Expect().Body().NotContains("hello,
world!!")
+ })
+
+ ginkgo.It("delete global rule in apisix", func() {
+ agr := `
+apiVersion: apisix.apache.org/v2
+kind: ApisixGlobalRule
+metadata:
+ name: test-agr-1
+spec:
+ plugins:
+ - name: echo
+ enable: true
+ config:
+ body: "hello, world!!"
+`
+ assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(agr),
"creating ApisixGlobalRule")
+ time.Sleep(6 * time.Second)
+
+ grs, err := s.ListApisixGlobalRules()
+ assert.Nil(ginkgo.GinkgoT(), err, "listing global_rules")
+ assert.Len(ginkgo.GinkgoT(), grs, 1)
+ assert.Len(ginkgo.GinkgoT(), grs[0].Plugins, 1)
+ _, ok := grs[0].Plugins["echo"]
+ assert.Equal(ginkgo.GinkgoT(), ok, true)
+
+ assert.Nil(ginkgo.GinkgoT(), s.DeleteResourceFromString(agr),
"deleteing ApisixGlobalRule")
+ time.Sleep(6 * time.Second)
+
+ grs, err = s.ListApisixGlobalRules()
+ assert.Nil(ginkgo.GinkgoT(), err, "listing global_rules")
+ assert.Len(ginkgo.GinkgoT(), grs, 0)
+
+
s.NewAPISIXClient().GET("/anything").Expect().Body().NotContains("hello,
world!!")
+ })
+})