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!!")
+       })
+})

Reply via email to