This is an automated email from the ASF dual-hosted git repository. tokers pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git
The following commit(s) were added to refs/heads/master by this push: new 0460a09 feat: add ApisixClusterConfig CRD and global_rule type, client (#411) 0460a09 is described below commit 0460a092004d5029c3936be91fbfe667291f73ed Author: Alex Zhang <zchao1...@gmail.com> AuthorDate: Thu May 6 10:29:04 2021 +0800 feat: add ApisixClusterConfig CRD and global_rule type, client (#411) --- pkg/apisix/apisix.go | 10 + pkg/apisix/cache/cache.go | 8 + pkg/apisix/cache/memdb.go | 28 +++ pkg/apisix/cache/memdb_test.go | 43 ++++ pkg/apisix/cache/schema.go | 10 + pkg/apisix/cluster.go | 32 +++ pkg/apisix/global_rule.go | 223 +++++++++++++++++++++ pkg/apisix/global_rule_test.go | 199 ++++++++++++++++++ pkg/apisix/nonexistentclient.go | 28 +++ pkg/apisix/resource.go | 10 + pkg/kube/apisix/apis/config/v2alpha1/types.go | 72 +++++++ .../apis/config/v2alpha1/zz_generated.deepcopy.go | 152 ++++++++++++++ .../typed/config/v2alpha1/apisixclusterconfig.go | 168 ++++++++++++++++ .../typed/config/v2alpha1/config_client.go | 5 + .../v2alpha1/fake/fake_apisixclusterconfig.go | 122 +++++++++++ .../config/v2alpha1/fake/fake_config_client.go | 4 + .../typed/config/v2alpha1/generated_expansion.go | 2 + .../config/v2alpha1/apisixclusterconfig.go | 89 ++++++++ .../externalversions/config/v2alpha1/interface.go | 7 + .../client/informers/externalversions/generic.go | 2 + .../listers/config/v2alpha1/apisixclusterconfig.go | 68 +++++++ .../listers/config/v2alpha1/expansion_generated.go | 4 + pkg/types/apisix/v1/types.go | 9 +- pkg/types/apisix/v1/zz_generated.deepcopy.go | 17 ++ .../deploy/crd/v1beta1/ApisixClusterConfig.yaml | 71 +++++++ samples/deploy/crd/v1beta1/kustomization.yaml | 1 + 26 files changed, 1383 insertions(+), 1 deletion(-) diff --git a/pkg/apisix/apisix.go b/pkg/apisix/apisix.go index 0e88f43..e407b7e 100644 --- a/pkg/apisix/apisix.go +++ b/pkg/apisix/apisix.go @@ -87,6 +87,16 @@ type StreamRoute interface { Update(context.Context, *v1.StreamRoute) (*v1.StreamRoute, error) } +// GlobalRule is the specific client interface to take over the create, update, +// list and delete for APISIX's Global Rule resource. +type GlobalRule interface { + Get(context.Context, string) (*v1.GlobalRule, error) + List(context.Context) ([]*v1.GlobalRule, error) + Create(context.Context, *v1.GlobalRule) (*v1.GlobalRule, error) + Delete(context.Context, *v1.GlobalRule) error + Update(context.Context, *v1.GlobalRule) (*v1.GlobalRule, error) +} + type apisix struct { nonExistentCluster Cluster clusters map[string]Cluster diff --git a/pkg/apisix/cache/cache.go b/pkg/apisix/cache/cache.go index c527157..c213f3e 100644 --- a/pkg/apisix/cache/cache.go +++ b/pkg/apisix/cache/cache.go @@ -31,6 +31,8 @@ type Cache interface { InsertUpstream(*v1.Upstream) error // InsertStreamRoute adds or updates stream_route to cache. InsertStreamRoute(*v1.StreamRoute) error + // InsertGlobalRule adds or updates global_rule to cache. + InsertGlobalRule(*v1.GlobalRule) error // GetRoute finds the route from cache according to the primary index (id). GetRoute(string) (*v1.Route, error) @@ -40,6 +42,8 @@ type Cache interface { GetUpstream(string) (*v1.Upstream, error) // GetStreamRoute finds the stream_route from cache according to the primary index (id). GetStreamRoute(string) (*v1.StreamRoute, error) + // GetGlobalRule finds the global_rule from cache according to the primary index (id). + GetGlobalRule(string) (*v1.GlobalRule, error) // ListRoutes lists all routes in cache. ListRoutes() ([]*v1.Route, error) @@ -49,6 +53,8 @@ type Cache interface { ListUpstreams() ([]*v1.Upstream, error) // ListStreamRoutes lists all stream_route in cache. ListStreamRoutes() ([]*v1.StreamRoute, error) + // ListGlobalRules lists all global_rule objects in cache. + ListGlobalRules() ([]*v1.GlobalRule, error) // DeleteRoute deletes the specified route in cache. DeleteRoute(*v1.Route) error @@ -58,4 +64,6 @@ type Cache interface { DeleteUpstream(*v1.Upstream) error // DeleteStreamRoute deletes the specified stream_route in cache. DeleteStreamRoute(*v1.StreamRoute) error + // DeleteGlobalRule deletes the specified stream_route in cache. + DeleteGlobalRule(*v1.GlobalRule) error } diff --git a/pkg/apisix/cache/memdb.go b/pkg/apisix/cache/memdb.go index 481cfe7..18de938 100644 --- a/pkg/apisix/cache/memdb.go +++ b/pkg/apisix/cache/memdb.go @@ -62,6 +62,10 @@ func (c *dbCache) InsertStreamRoute(sr *v1.StreamRoute) error { return c.insert("stream_route", sr.DeepCopy()) } +func (c *dbCache) InsertGlobalRule(gr *v1.GlobalRule) error { + return c.insert("global_rule", gr.DeepCopy()) +} + func (c *dbCache) insert(table string, obj interface{}) error { txn := c.db.Txn(true) defer txn.Abort() @@ -104,6 +108,14 @@ func (c *dbCache) GetStreamRoute(id string) (*v1.StreamRoute, error) { return obj.(*v1.StreamRoute).DeepCopy(), nil } +func (c *dbCache) GetGlobalRule(id string) (*v1.GlobalRule, error) { + obj, err := c.get("global_rule", id) + if err != nil { + return nil, err + } + return obj.(*v1.GlobalRule).DeepCopy(), nil +} + func (c *dbCache) get(table, id string) (interface{}, error) { txn := c.db.Txn(false) defer txn.Abort() @@ -168,6 +180,18 @@ func (c *dbCache) ListStreamRoutes() ([]*v1.StreamRoute, error) { return streamRoutes, nil } +func (c *dbCache) ListGlobalRules() ([]*v1.GlobalRule, error) { + raws, err := c.list("global_rule") + if err != nil { + return nil, err + } + globalRules := make([]*v1.GlobalRule, 0, len(raws)) + for _, raw := range raws { + globalRules = append(globalRules, raw.(*v1.GlobalRule).DeepCopy()) + } + return globalRules, nil +} + func (c *dbCache) list(table string) ([]interface{}, error) { txn := c.db.Txn(false) defer txn.Abort() @@ -201,6 +225,10 @@ func (c *dbCache) DeleteStreamRoute(sr *v1.StreamRoute) error { return c.delete("stream_route", sr) } +func (c *dbCache) DeleteGlobalRule(gr *v1.GlobalRule) error { + return c.delete("global_rule", gr) +} + func (c *dbCache) delete(table string, obj interface{}) error { txn := c.db.Txn(true) defer txn.Abort() diff --git a/pkg/apisix/cache/memdb_test.go b/pkg/apisix/cache/memdb_test.go index 8e449ea..91858d7 100644 --- a/pkg/apisix/cache/memdb_test.go +++ b/pkg/apisix/cache/memdb_test.go @@ -259,3 +259,46 @@ func TestMemDBCacheStreamRoute(t *testing.T) { } assert.Error(t, ErrNotFound, c.DeleteStreamRoute(r4)) } + +func TestMemDBCacheGlobalRule(t *testing.T) { + c, err := NewMemDBCache() + assert.Nil(t, err, "NewMemDBCache") + + gr1 := &v1.GlobalRule{ + ID: "1", + } + assert.Nil(t, c.InsertGlobalRule(gr1), "inserting global rule 1") + + gr, err := c.GetGlobalRule("1") + assert.Nil(t, err) + assert.Equal(t, gr1, gr) + + gr2 := &v1.GlobalRule{ + ID: "2", + } + gr3 := &v1.GlobalRule{ + ID: "3", + } + assert.Nil(t, c.InsertGlobalRule(gr2), "inserting global_rule r2") + assert.Nil(t, c.InsertGlobalRule(gr3), "inserting global_rule r3") + + gr, err = c.GetGlobalRule("3") + assert.Nil(t, err) + assert.Equal(t, gr, gr) + + assert.Nil(t, c.DeleteGlobalRule(gr), "delete global_rule r3") + + grs, err := c.ListGlobalRules() + assert.Nil(t, err, "listing global rules") + + if grs[0].ID > grs[1].ID { + grs[0], grs[1] = grs[1], grs[0] + } + assert.Equal(t, grs[0], gr1) + assert.Equal(t, grs[1], gr2) + + gr4 := &v1.GlobalRule{ + ID: "4", + } + assert.Error(t, ErrNotFound, c.DeleteGlobalRule(gr4)) +} diff --git a/pkg/apisix/cache/schema.go b/pkg/apisix/cache/schema.go index 9db4ae7..c3e8877 100644 --- a/pkg/apisix/cache/schema.go +++ b/pkg/apisix/cache/schema.go @@ -86,6 +86,16 @@ var ( }, }, }, + "global_rule": { + Name: "global_rule", + Indexes: map[string]*memdb.IndexSchema{ + "id": { + Name: "id", + Unique: true, + Indexer: &memdb.StringFieldIndex{Field: "ID"}, + }, + }, + }, }, } ) diff --git a/pkg/apisix/cluster.go b/pkg/apisix/cluster.go index 362d5d5..bc31ee8 100644 --- a/pkg/apisix/cluster.go +++ b/pkg/apisix/cluster.go @@ -73,6 +73,7 @@ type cluster struct { upstream Upstream ssl SSL streamRoute StreamRoute + globalRules GlobalRule } func newCluster(o *ClusterOptions) (Cluster, error) { @@ -103,6 +104,7 @@ func newCluster(o *ClusterOptions) (Cluster, error) { c.upstream = newUpstreamClient(c) c.ssl = newSSLClient(c) c.streamRoute = newStreamRouteClient(c) + c.globalRules = newGlobalRuleClient(c) go c.syncCache() @@ -167,6 +169,16 @@ func (c *cluster) syncCacheOnce() (bool, error) { log.Errorf("failed to list ssl in APISIX: %s", err) return false, err } + streamRoutes, err := c.streamRoute.List(context.TODO()) + if err != nil { + log.Errorf("failed to list stream_routes in APISIX: %s", err) + return false, err + } + globalRules, err := c.globalRules.List(context.TODO()) + if err != nil { + log.Errorf("failed to list global_rules in APISIX: %s", err) + return false, err + } for _, r := range routes { if err := c.cache.InsertRoute(r); err != nil { @@ -198,6 +210,26 @@ func (c *cluster) syncCacheOnce() (bool, error) { return false, err } } + for _, sr := range streamRoutes { + if err := c.cache.InsertStreamRoute(sr); err != nil { + log.Errorw("failed to insert stream_route to cache", + zap.Any("stream_route", sr), + zap.String("cluster", c.name), + zap.String("error", err.Error()), + ) + return false, err + } + } + for _, gr := range globalRules { + if err := c.cache.InsertGlobalRule(gr); err != nil { + log.Errorw("failed to insert global_rule to cache", + zap.Any("global_rule", gr), + zap.String("cluster", c.name), + zap.String("error", err.Error()), + ) + return false, err + } + } return true, nil } diff --git a/pkg/apisix/global_rule.go b/pkg/apisix/global_rule.go new file mode 100644 index 0000000..7060354 --- /dev/null +++ b/pkg/apisix/global_rule.go @@ -0,0 +1,223 @@ +// 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 ( + "bytes" + "context" + "encoding/json" + + "github.com/apache/apisix-ingress-controller/pkg/apisix/cache" + "github.com/apache/apisix-ingress-controller/pkg/id" + "github.com/apache/apisix-ingress-controller/pkg/log" + v1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" + "go.uber.org/zap" +) + +type globalRuleClient struct { + url string + cluster *cluster +} + +func newGlobalRuleClient(c *cluster) GlobalRule { + return &globalRuleClient{ + url: c.baseURL + "/global_rules", + cluster: c, + } +} + +// Get returns the GlobalRule. +// FIXME, currently if caller pass a non-existent resource, the Get always passes +// through cache. +func (r *globalRuleClient) Get(ctx context.Context, name string) (*v1.GlobalRule, error) { + log.Debugw("try to look up global_rule", + zap.String("name", name), + zap.String("url", r.url), + zap.String("cluster", "default"), + ) + rid := id.GenID(name) + globalRule, err := r.cluster.cache.GetGlobalRule(rid) + if err == nil { + return globalRule, nil + } + if err != cache.ErrNotFound { + log.Errorw("failed to find global_rule in cache, will try to lookup from APISIX", + zap.String("name", name), + zap.Error(err), + ) + } else { + log.Debugw("failed to find global_rule in cache, will try to lookup from APISIX", + zap.String("name", name), + zap.Error(err), + ) + } + + // TODO Add mutex here to avoid dog-pile effect. + url := r.url + "/" + rid + resp, err := r.cluster.getResource(ctx, url) + if err != nil { + if err == cache.ErrNotFound { + log.Warnw("global_rule not found", + zap.String("name", name), + zap.String("url", url), + zap.String("cluster", "default"), + ) + } else { + log.Errorw("failed to get global_rule from APISIX", + zap.String("name", name), + zap.String("url", url), + zap.String("cluster", "default"), + zap.Error(err), + ) + } + return nil, err + } + + globalRule, err = resp.Item.globalRule() + if err != nil { + log.Errorw("failed to convert global_rule item", + zap.String("url", r.url), + zap.String("global_rule_key", resp.Item.Key), + zap.String("global_rule_value", string(resp.Item.Value)), + zap.Error(err), + ) + return nil, err + } + + if err := r.cluster.cache.InsertGlobalRule(globalRule); err != nil { + log.Errorf("failed to reflect global_rule create to cache: %s", err) + return nil, err + } + return globalRule, nil +} + +// List is only used in cache warming up. So here just pass through +// to APISIX. +func (r *globalRuleClient) List(ctx context.Context) ([]*v1.GlobalRule, error) { + log.Debugw("try to list global_rules in APISIX", + zap.String("cluster", "default"), + zap.String("url", r.url), + ) + globalRuleItems, err := r.cluster.listResource(ctx, r.url) + if err != nil { + log.Errorf("failed to list global_rules: %s", err) + return nil, err + } + + var items []*v1.GlobalRule + for i, item := range globalRuleItems.Node.Items { + globalRule, err := item.globalRule() + if err != nil { + log.Errorw("failed to convert global_rule item", + zap.String("url", r.url), + zap.String("global_rule_key", item.Key), + zap.String("global_rule_value", string(item.Value)), + zap.Error(err), + ) + return nil, err + } + + items = append(items, globalRule) + log.Debugf("list global_rule #%d, body: %s", i, string(item.Value)) + } + + return items, nil +} + +func (r *globalRuleClient) Create(ctx context.Context, obj *v1.GlobalRule) (*v1.GlobalRule, error) { + log.Debugw("try to create global_rule", + zap.String("id", obj.ID), + zap.Any("plugins", obj.Plugins), + zap.String("cluster", "default"), + zap.String("url", r.url), + ) + + if err := r.cluster.HasSynced(ctx); err != nil { + return nil, err + } + data, err := json.Marshal(obj) + if err != nil { + return nil, err + } + + url := r.url + "/" + obj.ID + log.Debugw("creating global_rule", zap.ByteString("body", data), zap.String("url", url)) + resp, err := r.cluster.createResource(ctx, url, bytes.NewReader(data)) + if err != nil { + log.Errorf("failed to create global_rule: %s", err) + return nil, err + } + + globalRules, err := resp.Item.globalRule() + if err != nil { + return nil, err + } + if err := r.cluster.cache.InsertGlobalRule(globalRules); err != nil { + log.Errorf("failed to reflect global_rules create to cache: %s", err) + return nil, err + } + return globalRules, nil +} + +func (r *globalRuleClient) Delete(ctx context.Context, obj *v1.GlobalRule) error { + log.Debugw("try to delete global_rule", + zap.String("id", obj.ID), + zap.String("cluster", "default"), + zap.String("url", r.url), + ) + if err := r.cluster.HasSynced(ctx); err != nil { + return err + } + url := r.url + "/" + obj.ID + if err := r.cluster.deleteResource(ctx, url); err != nil { + return err + } + if err := r.cluster.cache.DeleteGlobalRule(obj); err != nil { + log.Errorf("failed to reflect global_rule delete to cache: %s", err) + return err + } + return nil +} + +func (r *globalRuleClient) Update(ctx context.Context, obj *v1.GlobalRule) (*v1.GlobalRule, error) { + log.Debugw("try to update global_rule", + zap.String("id", obj.ID), + zap.Any("plugins", obj.Plugins), + zap.String("cluster", "default"), + zap.String("url", r.url), + ) + if err := r.cluster.HasSynced(ctx); err != nil { + return nil, err + } + body, err := json.Marshal(obj) + if err != nil { + return nil, err + } + url := r.url + "/" + obj.ID + log.Debugw("updating global_rule", zap.ByteString("body", body), zap.String("url", url)) + resp, err := r.cluster.updateResource(ctx, url, bytes.NewReader(body)) + if err != nil { + return nil, err + } + globalRule, err := resp.Item.globalRule() + if err != nil { + return nil, err + } + if err := r.cluster.cache.InsertGlobalRule(globalRule); err != nil { + log.Errorf("failed to reflect global_rule update to cache: %s", err) + return nil, err + } + return globalRule, nil +} diff --git a/pkg/apisix/global_rule_test.go b/pkg/apisix/global_rule_test.go new file mode 100644 index 0000000..01a4d38 --- /dev/null +++ b/pkg/apisix/global_rule_test.go @@ -0,0 +1,199 @@ +// 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" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "sort" + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "golang.org/x/net/nettest" + + v1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" +) + +type fakeAPISIXGlobalRuleSrv struct { + globalRule map[string]json.RawMessage +} + +func (srv *fakeAPISIXGlobalRuleSrv) ServeHTTP(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + + if !strings.HasPrefix(r.URL.Path, "/apisix/admin/global_rules") { + w.WriteHeader(http.StatusNotFound) + return + } + + if r.Method == http.MethodGet { + resp := fakeListResp{ + Count: strconv.Itoa(len(srv.globalRule)), + Node: fakeNode{ + Key: "/apisix/global_rules", + }, + } + var keys []string + for key := range srv.globalRule { + keys = append(keys, key) + } + sort.Strings(keys) + for _, key := range keys { + resp.Node.Items = append(resp.Node.Items, fakeItem{ + Key: key, + Value: srv.globalRule[key], + }) + } + w.WriteHeader(http.StatusOK) + data, _ := json.Marshal(resp) + _, _ = w.Write(data) + return + } + + if r.Method == http.MethodDelete { + id := strings.TrimPrefix(r.URL.Path, "/apisix/admin/global_rules/") + id = "/apisix/admin/global_rules/" + id + code := http.StatusNotFound + if _, ok := srv.globalRule[id]; ok { + delete(srv.globalRule, id) + code = http.StatusOK + } + w.WriteHeader(code) + } + + if r.Method == http.MethodPut { + paths := strings.Split(r.URL.Path, "/") + key := fmt.Sprintf("/apisix/admin/global_rules/%s", paths[len(paths)-1]) + data, _ := ioutil.ReadAll(r.Body) + srv.globalRule[key] = data + w.WriteHeader(http.StatusCreated) + resp := fakeCreateResp{ + Action: "create", + Node: fakeItem{ + Key: key, + Value: json.RawMessage(data), + }, + } + data, _ = json.Marshal(resp) + _, _ = w.Write(data) + return + } + + if r.Method == http.MethodPatch { + id := strings.TrimPrefix(r.URL.Path, "/apisix/admin/global_rules/") + id = "/apisix/global_rules/" + id + if _, ok := srv.globalRule[id]; !ok { + w.WriteHeader(http.StatusNotFound) + return + } + + data, _ := ioutil.ReadAll(r.Body) + srv.globalRule[id] = data + + w.WriteHeader(http.StatusOK) + output := fmt.Sprintf(`{"action": "compareAndSwap", "node": {"key": "%s", "value": %s}}`, id, string(data)) + _, _ = w.Write([]byte(output)) + return + } +} + +func runFakeGlobalRuleSrv(t *testing.T) *http.Server { + srv := &fakeAPISIXGlobalRuleSrv{ + globalRule: make(map[string]json.RawMessage), + } + + ln, _ := nettest.NewLocalListener("tcp") + + httpSrv := &http.Server{ + Addr: ln.Addr().String(), + Handler: srv, + } + + go func() { + if err := httpSrv.Serve(ln); err != nil && err != http.ErrServerClosed { + t.Errorf("failed to run http server: %s", err) + } + }() + + return httpSrv +} + +func TestGlobalRuleClient(t *testing.T) { + srv := runFakeGlobalRuleSrv(t) + defer func() { + assert.Nil(t, srv.Shutdown(context.Background())) + }() + + u := url.URL{ + Scheme: "http", + Host: srv.Addr, + Path: "/apisix/admin", + } + + closedCh := make(chan struct{}) + close(closedCh) + cli := newGlobalRuleClient(&cluster{ + baseURL: u.String(), + cli: http.DefaultClient, + cache: &dummyCache{}, + cacheSynced: closedCh, + }) + + // Create + obj, err := cli.Create(context.Background(), &v1.GlobalRule{ + ID: "1", + }) + assert.Nil(t, err) + assert.Equal(t, obj.ID, "1") + + obj, err = cli.Create(context.Background(), &v1.GlobalRule{ + ID: "2", + }) + assert.Nil(t, err) + assert.Equal(t, obj.ID, "2") + + // List + objs, err := cli.List(context.Background()) + assert.Nil(t, err) + assert.Len(t, objs, 2) + assert.Equal(t, objs[0].ID, "1") + assert.Equal(t, objs[1].ID, "2") + + // Delete then List + assert.Nil(t, cli.Delete(context.Background(), objs[0])) + objs, err = cli.List(context.Background()) + assert.Nil(t, err) + assert.Len(t, objs, 1) + assert.Equal(t, "2", objs[0].ID) + + // Patch then List + _, err = cli.Update(context.Background(), &v1.GlobalRule{ + ID: "2", + Plugins: map[string]interface{}{ + "prometheus": struct{}{}, + }, + }) + assert.Nil(t, err) + objs, err = cli.List(context.Background()) + assert.Nil(t, err) + assert.Len(t, objs, 1) + assert.Equal(t, "2", objs[0].ID) +} diff --git a/pkg/apisix/nonexistentclient.go b/pkg/apisix/nonexistentclient.go index 3113bae..d965cda 100644 --- a/pkg/apisix/nonexistentclient.go +++ b/pkg/apisix/nonexistentclient.go @@ -33,6 +33,7 @@ func newNonExistentCluster() *nonExistentCluster { ssl: &dummySSL{}, upstream: &dummyUpstream{}, streamRoute: &dummyStreamRoute{}, + globalRule: &dummyGlobalRule{}, }, } } @@ -42,6 +43,7 @@ type embedDummyResourceImplementer struct { ssl SSL upstream Upstream streamRoute StreamRoute + globalRule GlobalRule } type dummyRoute struct{} @@ -132,6 +134,28 @@ func (f *dummyStreamRoute) Update(_ context.Context, _ *v1.StreamRoute) (*v1.Str return nil, ErrClusterNotExist } +type dummyGlobalRule struct{} + +func (f *dummyGlobalRule) Get(_ context.Context, _ string) (*v1.GlobalRule, error) { + return nil, ErrClusterNotExist +} + +func (f *dummyGlobalRule) List(_ context.Context) ([]*v1.GlobalRule, error) { + return nil, ErrClusterNotExist +} + +func (f *dummyGlobalRule) Create(_ context.Context, _ *v1.GlobalRule) (*v1.GlobalRule, error) { + return nil, ErrClusterNotExist +} + +func (f *dummyGlobalRule) Delete(_ context.Context, _ *v1.GlobalRule) error { + return ErrClusterNotExist +} + +func (f *dummyGlobalRule) Update(_ context.Context, _ *v1.GlobalRule) (*v1.GlobalRule, error) { + return nil, ErrClusterNotExist +} + func (nc *nonExistentCluster) Route() Route { return nc.route } @@ -164,15 +188,19 @@ func (c *dummyCache) InsertRoute(_ *v1.Route) error { return func (c *dummyCache) InsertSSL(_ *v1.Ssl) error { return nil } func (c *dummyCache) InsertUpstream(_ *v1.Upstream) error { return nil } func (c *dummyCache) InsertStreamRoute(_ *v1.StreamRoute) error { return nil } +func (c *dummyCache) InsertGlobalRule(_ *v1.GlobalRule) error { return nil } func (c *dummyCache) GetRoute(_ string) (*v1.Route, error) { return nil, cache.ErrNotFound } func (c *dummyCache) GetSSL(_ string) (*v1.Ssl, error) { return nil, cache.ErrNotFound } func (c *dummyCache) GetUpstream(_ string) (*v1.Upstream, error) { return nil, cache.ErrNotFound } func (c *dummyCache) GetStreamRoute(_ string) (*v1.StreamRoute, error) { return nil, cache.ErrNotFound } +func (c *dummyCache) GetGlobalRule(_ string) (*v1.GlobalRule, error) { return nil, cache.ErrNotFound } func (c *dummyCache) ListRoutes() ([]*v1.Route, error) { return nil, nil } func (c *dummyCache) ListSSL() ([]*v1.Ssl, error) { return nil, nil } func (c *dummyCache) ListUpstreams() ([]*v1.Upstream, error) { return nil, nil } func (c *dummyCache) ListStreamRoutes() ([]*v1.StreamRoute, error) { return nil, nil } +func (c *dummyCache) ListGlobalRules() ([]*v1.GlobalRule, error) { return nil, nil } func (c *dummyCache) DeleteRoute(_ *v1.Route) error { return nil } func (c *dummyCache) DeleteSSL(_ *v1.Ssl) error { return nil } func (c *dummyCache) DeleteUpstream(_ *v1.Upstream) error { return nil } func (c *dummyCache) DeleteStreamRoute(_ *v1.StreamRoute) error { return nil } +func (c *dummyCache) DeleteGlobalRule(_ *v1.GlobalRule) error { return nil } diff --git a/pkg/apisix/resource.go b/pkg/apisix/resource.go index 5526a66..d24791f 100644 --- a/pkg/apisix/resource.go +++ b/pkg/apisix/resource.go @@ -137,3 +137,13 @@ func (i *item) ssl() (*v1.Ssl, error) { } return &ssl, nil } + +// globalRule decodes item.Value and converts it to v1.GlobalRule. +func (i *item) globalRule() (*v1.GlobalRule, error) { + log.Debugf("got global_rule: %s", string(i.Value)) + var globalRule v1.GlobalRule + if err := json.Unmarshal(i.Value, &globalRule); err != nil { + return nil, err + } + return &globalRule, nil +} diff --git a/pkg/kube/apisix/apis/config/v2alpha1/types.go b/pkg/kube/apisix/apis/config/v2alpha1/types.go index 926addb..2c01b6f 100644 --- a/pkg/kube/apisix/apis/config/v2alpha1/types.go +++ b/pkg/kube/apisix/apis/config/v2alpha1/types.go @@ -232,8 +232,80 @@ type ApisixRouteTCPBackend struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ApisixRouteList contains a list of ApisixRoute. type ApisixRouteList struct { metav1.TypeMeta `json:",inline" yaml:",inline"` metav1.ListMeta `json:"metadata" yaml:"metadata"` Items []ApisixRoute `json:"items,omitempty" yaml:"items,omitempty"` } + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:subresource:status + +// ApisixClusterConfig is the Schema for the ApisixClusterConfig resource. +// An ApisixClusterConfig is used to identify an APISIX cluster, it's a +// ClusterScoped resource so the name is unique. +// It also contains some cluster-level configurations like monitoring. +type ApisixClusterConfig struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ObjectMeta `json:"metadata" yaml:"metadata"` + + // Spec defines the desired state of ApisixClusterConfigSpec. + Spec ApisixClusterConfigSpec `json:"spec" yaml:"spec"` +} + +// ApisixClusterConfigSpec defines the desired state of ApisixClusterConfigSpec. +type ApisixClusterConfigSpec struct { + // Monitoring categories all monitoring related features. + // +optional + Monitoring *ApisixClusterMonitoringConfig `json:"monitoring" yaml:"monitoring"` + // Admin contains the Admin API information about APISIX cluster. + // +optional + Admin *ApisixClusterAdminConfig `json:"admin" yaml:"admin"` +} + +// ApisixClusterMonitoringConfig categories all monitoring related features. +type ApisixClusterMonitoringConfig struct { + // Prometheus is the config for using Prometheus in APISIX Cluster. + // +optional + Prometheus ApisixClusterPrometheusConfig + // Skywalking is the config for using Skywalking in APISIX Cluster. + // +optional + Skywalking ApisixClusterSkywalkingConfig +} + +// ApisixClusterPrometheusConfig is the config for using Prometheus in APISIX Cluster. +type ApisixClusterPrometheusConfig struct { + // Enable means whether enable Prometheus or not. + Enable bool `json:"enable" yaml:"enable"` +} + +// ApisixClusterSkywalkingConfig is the config for using Skywalking in APISIX Cluster. +type ApisixClusterSkywalkingConfig struct { + // Enable means whether enable Skywalking or not. + Enable bool `json:"enable" yaml:"enable"` + // SampleRatio means the ratio to collect + SampleRatio float64 `json:"sampleRatio" yaml:"sampleRatio"` +} + +// ApisixClusterAdminConfig is the admin config for the corresponding APISIX Cluster. +type ApisixClusterAdminConfig struct { + // BaseURL is the base URL for the APISIX Admin API. + // It looks like "http://apisix-admin.default.svc.cluster.local:9080/apisix/admin" + BaseURL string + // AdminKey is used to verify the admin API user. + AdminKey string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ApisixClusterConfigList contains a list of ApisixClusterConfig. +type ApisixClusterConfigList struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ListMeta `json:"metadata" yaml:"metadata"` + + Items []ApisixClusterConfig `json:"items" yaml:"items"` +} diff --git a/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go b/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go index 16cedce..c11e22c 100644 --- a/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go +++ b/pkg/kube/apisix/apis/config/v2alpha1/zz_generated.deepcopy.go @@ -26,6 +26,158 @@ import ( ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixClusterAdminConfig) DeepCopyInto(out *ApisixClusterAdminConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixClusterAdminConfig. +func (in *ApisixClusterAdminConfig) DeepCopy() *ApisixClusterAdminConfig { + if in == nil { + return nil + } + out := new(ApisixClusterAdminConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixClusterConfig) DeepCopyInto(out *ApisixClusterConfig) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixClusterConfig. +func (in *ApisixClusterConfig) DeepCopy() *ApisixClusterConfig { + if in == nil { + return nil + } + out := new(ApisixClusterConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApisixClusterConfig) 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 *ApisixClusterConfigList) DeepCopyInto(out *ApisixClusterConfigList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ApisixClusterConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixClusterConfigList. +func (in *ApisixClusterConfigList) DeepCopy() *ApisixClusterConfigList { + if in == nil { + return nil + } + out := new(ApisixClusterConfigList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApisixClusterConfigList) 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 *ApisixClusterConfigSpec) DeepCopyInto(out *ApisixClusterConfigSpec) { + *out = *in + if in.Monitoring != nil { + in, out := &in.Monitoring, &out.Monitoring + *out = new(ApisixClusterMonitoringConfig) + **out = **in + } + if in.Admin != nil { + in, out := &in.Admin, &out.Admin + *out = new(ApisixClusterAdminConfig) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixClusterConfigSpec. +func (in *ApisixClusterConfigSpec) DeepCopy() *ApisixClusterConfigSpec { + if in == nil { + return nil + } + out := new(ApisixClusterConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixClusterMonitoringConfig) DeepCopyInto(out *ApisixClusterMonitoringConfig) { + *out = *in + out.Prometheus = in.Prometheus + out.Skywalking = in.Skywalking + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixClusterMonitoringConfig. +func (in *ApisixClusterMonitoringConfig) DeepCopy() *ApisixClusterMonitoringConfig { + if in == nil { + return nil + } + out := new(ApisixClusterMonitoringConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixClusterPrometheusConfig) DeepCopyInto(out *ApisixClusterPrometheusConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixClusterPrometheusConfig. +func (in *ApisixClusterPrometheusConfig) DeepCopy() *ApisixClusterPrometheusConfig { + if in == nil { + return nil + } + out := new(ApisixClusterPrometheusConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApisixClusterSkywalkingConfig) DeepCopyInto(out *ApisixClusterSkywalkingConfig) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApisixClusterSkywalkingConfig. +func (in *ApisixClusterSkywalkingConfig) DeepCopy() *ApisixClusterSkywalkingConfig { + if in == nil { + return nil + } + out := new(ApisixClusterSkywalkingConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ApisixRoute) DeepCopyInto(out *ApisixRoute) { *out = *in out.TypeMeta = in.TypeMeta diff --git a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/apisixclusterconfig.go b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/apisixclusterconfig.go new file mode 100644 index 0000000..bcd8c56 --- /dev/null +++ b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/apisixclusterconfig.go @@ -0,0 +1,168 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v2alpha1 + +import ( + "context" + "time" + + v2alpha1 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1" + 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" +) + +// ApisixClusterConfigsGetter has a method to return a ApisixClusterConfigInterface. +// A group's client should implement this interface. +type ApisixClusterConfigsGetter interface { + ApisixClusterConfigs() ApisixClusterConfigInterface +} + +// ApisixClusterConfigInterface has methods to work with ApisixClusterConfig resources. +type ApisixClusterConfigInterface interface { + Create(ctx context.Context, apisixClusterConfig *v2alpha1.ApisixClusterConfig, opts v1.CreateOptions) (*v2alpha1.ApisixClusterConfig, error) + Update(ctx context.Context, apisixClusterConfig *v2alpha1.ApisixClusterConfig, opts v1.UpdateOptions) (*v2alpha1.ApisixClusterConfig, 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) (*v2alpha1.ApisixClusterConfig, error) + List(ctx context.Context, opts v1.ListOptions) (*v2alpha1.ApisixClusterConfigList, 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 *v2alpha1.ApisixClusterConfig, err error) + ApisixClusterConfigExpansion +} + +// apisixClusterConfigs implements ApisixClusterConfigInterface +type apisixClusterConfigs struct { + client rest.Interface +} + +// newApisixClusterConfigs returns a ApisixClusterConfigs +func newApisixClusterConfigs(c *ApisixV2alpha1Client) *apisixClusterConfigs { + return &apisixClusterConfigs{ + client: c.RESTClient(), + } +} + +// Get takes name of the apisixClusterConfig, and returns the corresponding apisixClusterConfig object, and an error if there is any. +func (c *apisixClusterConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2alpha1.ApisixClusterConfig, err error) { + result = &v2alpha1.ApisixClusterConfig{} + err = c.client.Get(). + Resource("apisixclusterconfigs"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ApisixClusterConfigs that match those selectors. +func (c *apisixClusterConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v2alpha1.ApisixClusterConfigList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v2alpha1.ApisixClusterConfigList{} + err = c.client.Get(). + Resource("apisixclusterconfigs"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested apisixClusterConfigs. +func (c *apisixClusterConfigs) 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(). + Resource("apisixclusterconfigs"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a apisixClusterConfig and creates it. Returns the server's representation of the apisixClusterConfig, and an error, if there is any. +func (c *apisixClusterConfigs) Create(ctx context.Context, apisixClusterConfig *v2alpha1.ApisixClusterConfig, opts v1.CreateOptions) (result *v2alpha1.ApisixClusterConfig, err error) { + result = &v2alpha1.ApisixClusterConfig{} + err = c.client.Post(). + Resource("apisixclusterconfigs"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(apisixClusterConfig). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a apisixClusterConfig and updates it. Returns the server's representation of the apisixClusterConfig, and an error, if there is any. +func (c *apisixClusterConfigs) Update(ctx context.Context, apisixClusterConfig *v2alpha1.ApisixClusterConfig, opts v1.UpdateOptions) (result *v2alpha1.ApisixClusterConfig, err error) { + result = &v2alpha1.ApisixClusterConfig{} + err = c.client.Put(). + Resource("apisixclusterconfigs"). + Name(apisixClusterConfig.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(apisixClusterConfig). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the apisixClusterConfig and deletes it. Returns an error if one occurs. +func (c *apisixClusterConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("apisixclusterconfigs"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *apisixClusterConfigs) 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(). + Resource("apisixclusterconfigs"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched apisixClusterConfig. +func (c *apisixClusterConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2alpha1.ApisixClusterConfig, err error) { + result = &v2alpha1.ApisixClusterConfig{} + err = c.client.Patch(pt). + Resource("apisixclusterconfigs"). + 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/v2alpha1/config_client.go b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/config_client.go index ade8d12..1197eb0 100644 --- a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/config_client.go +++ b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/config_client.go @@ -26,6 +26,7 @@ import ( type ApisixV2alpha1Interface interface { RESTClient() rest.Interface + ApisixClusterConfigsGetter ApisixRoutesGetter } @@ -34,6 +35,10 @@ type ApisixV2alpha1Client struct { restClient rest.Interface } +func (c *ApisixV2alpha1Client) ApisixClusterConfigs() ApisixClusterConfigInterface { + return newApisixClusterConfigs(c) +} + func (c *ApisixV2alpha1Client) ApisixRoutes(namespace string) ApisixRouteInterface { return newApisixRoutes(c, namespace) } diff --git a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_apisixclusterconfig.go b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_apisixclusterconfig.go new file mode 100644 index 0000000..cc22ad7 --- /dev/null +++ b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_apisixclusterconfig.go @@ -0,0 +1,122 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v2alpha1 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1" + 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" +) + +// FakeApisixClusterConfigs implements ApisixClusterConfigInterface +type FakeApisixClusterConfigs struct { + Fake *FakeApisixV2alpha1 +} + +var apisixclusterconfigsResource = schema.GroupVersionResource{Group: "apisix.apache.org", Version: "v2alpha1", Resource: "apisixclusterconfigs"} + +var apisixclusterconfigsKind = schema.GroupVersionKind{Group: "apisix.apache.org", Version: "v2alpha1", Kind: "ApisixClusterConfig"} + +// Get takes name of the apisixClusterConfig, and returns the corresponding apisixClusterConfig object, and an error if there is any. +func (c *FakeApisixClusterConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v2alpha1.ApisixClusterConfig, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(apisixclusterconfigsResource, name), &v2alpha1.ApisixClusterConfig{}) + if obj == nil { + return nil, err + } + return obj.(*v2alpha1.ApisixClusterConfig), err +} + +// List takes label and field selectors, and returns the list of ApisixClusterConfigs that match those selectors. +func (c *FakeApisixClusterConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v2alpha1.ApisixClusterConfigList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(apisixclusterconfigsResource, apisixclusterconfigsKind, opts), &v2alpha1.ApisixClusterConfigList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v2alpha1.ApisixClusterConfigList{ListMeta: obj.(*v2alpha1.ApisixClusterConfigList).ListMeta} + for _, item := range obj.(*v2alpha1.ApisixClusterConfigList).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 apisixClusterConfigs. +func (c *FakeApisixClusterConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(apisixclusterconfigsResource, opts)) +} + +// Create takes the representation of a apisixClusterConfig and creates it. Returns the server's representation of the apisixClusterConfig, and an error, if there is any. +func (c *FakeApisixClusterConfigs) Create(ctx context.Context, apisixClusterConfig *v2alpha1.ApisixClusterConfig, opts v1.CreateOptions) (result *v2alpha1.ApisixClusterConfig, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(apisixclusterconfigsResource, apisixClusterConfig), &v2alpha1.ApisixClusterConfig{}) + if obj == nil { + return nil, err + } + return obj.(*v2alpha1.ApisixClusterConfig), err +} + +// Update takes the representation of a apisixClusterConfig and updates it. Returns the server's representation of the apisixClusterConfig, and an error, if there is any. +func (c *FakeApisixClusterConfigs) Update(ctx context.Context, apisixClusterConfig *v2alpha1.ApisixClusterConfig, opts v1.UpdateOptions) (result *v2alpha1.ApisixClusterConfig, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(apisixclusterconfigsResource, apisixClusterConfig), &v2alpha1.ApisixClusterConfig{}) + if obj == nil { + return nil, err + } + return obj.(*v2alpha1.ApisixClusterConfig), err +} + +// Delete takes name of the apisixClusterConfig and deletes it. Returns an error if one occurs. +func (c *FakeApisixClusterConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(apisixclusterconfigsResource, name), &v2alpha1.ApisixClusterConfig{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeApisixClusterConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(apisixclusterconfigsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v2alpha1.ApisixClusterConfigList{}) + return err +} + +// Patch applies the patch and returns the patched apisixClusterConfig. +func (c *FakeApisixClusterConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v2alpha1.ApisixClusterConfig, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(apisixclusterconfigsResource, name, pt, data, subresources...), &v2alpha1.ApisixClusterConfig{}) + if obj == nil { + return nil, err + } + return obj.(*v2alpha1.ApisixClusterConfig), err +} diff --git a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_config_client.go b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_config_client.go index 448bafe..16cabaf 100644 --- a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_config_client.go +++ b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/fake/fake_config_client.go @@ -28,6 +28,10 @@ type FakeApisixV2alpha1 struct { *testing.Fake } +func (c *FakeApisixV2alpha1) ApisixClusterConfigs() v2alpha1.ApisixClusterConfigInterface { + return &FakeApisixClusterConfigs{c} +} + func (c *FakeApisixV2alpha1) ApisixRoutes(namespace string) v2alpha1.ApisixRouteInterface { return &FakeApisixRoutes{c, namespace} } diff --git a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/generated_expansion.go b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/generated_expansion.go index 980dad5..b1775c9 100644 --- a/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/generated_expansion.go +++ b/pkg/kube/apisix/client/clientset/versioned/typed/config/v2alpha1/generated_expansion.go @@ -18,4 +18,6 @@ limitations under the License. package v2alpha1 +type ApisixClusterConfigExpansion interface{} + type ApisixRouteExpansion interface{} diff --git a/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/apisixclusterconfig.go b/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/apisixclusterconfig.go new file mode 100644 index 0000000..4744d8a --- /dev/null +++ b/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/apisixclusterconfig.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v2alpha1 + +import ( + "context" + time "time" + + configv2alpha1 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1" + 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" + v2alpha1 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/client/listers/config/v2alpha1" + 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" +) + +// ApisixClusterConfigInformer provides access to a shared informer and lister for +// ApisixClusterConfigs. +type ApisixClusterConfigInformer interface { + Informer() cache.SharedIndexInformer + Lister() v2alpha1.ApisixClusterConfigLister +} + +type apisixClusterConfigInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewApisixClusterConfigInformer constructs a new informer for ApisixClusterConfig 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 NewApisixClusterConfigInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredApisixClusterConfigInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredApisixClusterConfigInformer constructs a new informer for ApisixClusterConfig 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 NewFilteredApisixClusterConfigInformer(client versioned.Interface, 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.ApisixV2alpha1().ApisixClusterConfigs().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApisixV2alpha1().ApisixClusterConfigs().Watch(context.TODO(), options) + }, + }, + &configv2alpha1.ApisixClusterConfig{}, + resyncPeriod, + indexers, + ) +} + +func (f *apisixClusterConfigInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredApisixClusterConfigInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *apisixClusterConfigInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&configv2alpha1.ApisixClusterConfig{}, f.defaultInformer) +} + +func (f *apisixClusterConfigInformer) Lister() v2alpha1.ApisixClusterConfigLister { + return v2alpha1.NewApisixClusterConfigLister(f.Informer().GetIndexer()) +} diff --git a/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/interface.go b/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/interface.go index 620edb7..a787523 100644 --- a/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/interface.go +++ b/pkg/kube/apisix/client/informers/externalversions/config/v2alpha1/interface.go @@ -24,6 +24,8 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { + // ApisixClusterConfigs returns a ApisixClusterConfigInformer. + ApisixClusterConfigs() ApisixClusterConfigInformer // ApisixRoutes returns a ApisixRouteInformer. ApisixRoutes() ApisixRouteInformer } @@ -39,6 +41,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } +// ApisixClusterConfigs returns a ApisixClusterConfigInformer. +func (v *version) ApisixClusterConfigs() ApisixClusterConfigInformer { + return &apisixClusterConfigInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + // ApisixRoutes returns a ApisixRouteInformer. func (v *version) ApisixRoutes() ApisixRouteInformer { return &apisixRouteInformer{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 8c2e73e..e24f2f8 100644 --- a/pkg/kube/apisix/client/informers/externalversions/generic.go +++ b/pkg/kube/apisix/client/informers/externalversions/generic.go @@ -62,6 +62,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Apisix().V1().ApisixUpstreams().Informer()}, nil // Group=apisix.apache.org, Version=v2alpha1 + case v2alpha1.SchemeGroupVersion.WithResource("apisixclusterconfigs"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Apisix().V2alpha1().ApisixClusterConfigs().Informer()}, nil case v2alpha1.SchemeGroupVersion.WithResource("apisixroutes"): return &genericInformer{resource: resource.GroupResource(), informer: f.Apisix().V2alpha1().ApisixRoutes().Informer()}, nil diff --git a/pkg/kube/apisix/client/listers/config/v2alpha1/apisixclusterconfig.go b/pkg/kube/apisix/client/listers/config/v2alpha1/apisixclusterconfig.go new file mode 100644 index 0000000..296e181 --- /dev/null +++ b/pkg/kube/apisix/client/listers/config/v2alpha1/apisixclusterconfig.go @@ -0,0 +1,68 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v2alpha1 + +import ( + v2alpha1 "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/apis/config/v2alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// ApisixClusterConfigLister helps list ApisixClusterConfigs. +// All objects returned here must be treated as read-only. +type ApisixClusterConfigLister interface { + // List lists all ApisixClusterConfigs in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v2alpha1.ApisixClusterConfig, err error) + // Get retrieves the ApisixClusterConfig from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v2alpha1.ApisixClusterConfig, error) + ApisixClusterConfigListerExpansion +} + +// apisixClusterConfigLister implements the ApisixClusterConfigLister interface. +type apisixClusterConfigLister struct { + indexer cache.Indexer +} + +// NewApisixClusterConfigLister returns a new ApisixClusterConfigLister. +func NewApisixClusterConfigLister(indexer cache.Indexer) ApisixClusterConfigLister { + return &apisixClusterConfigLister{indexer: indexer} +} + +// List lists all ApisixClusterConfigs in the indexer. +func (s *apisixClusterConfigLister) List(selector labels.Selector) (ret []*v2alpha1.ApisixClusterConfig, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v2alpha1.ApisixClusterConfig)) + }) + return ret, err +} + +// Get retrieves the ApisixClusterConfig from the index for a given name. +func (s *apisixClusterConfigLister) Get(name string) (*v2alpha1.ApisixClusterConfig, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v2alpha1.Resource("apisixclusterconfig"), name) + } + return obj.(*v2alpha1.ApisixClusterConfig), nil +} diff --git a/pkg/kube/apisix/client/listers/config/v2alpha1/expansion_generated.go b/pkg/kube/apisix/client/listers/config/v2alpha1/expansion_generated.go index e26b85d..5d5ca57 100644 --- a/pkg/kube/apisix/client/listers/config/v2alpha1/expansion_generated.go +++ b/pkg/kube/apisix/client/listers/config/v2alpha1/expansion_generated.go @@ -18,6 +18,10 @@ limitations under the License. package v2alpha1 +// ApisixClusterConfigListerExpansion allows custom methods to be added to +// ApisixClusterConfigLister. +type ApisixClusterConfigListerExpansion interface{} + // ApisixRouteListerExpansion allows custom methods to be added to // ApisixRouteLister. type ApisixRouteListerExpansion interface{} diff --git a/pkg/types/apisix/v1/types.go b/pkg/types/apisix/v1/types.go index 6ab1aa0..7acbf92 100644 --- a/pkg/types/apisix/v1/types.go +++ b/pkg/types/apisix/v1/types.go @@ -323,7 +323,7 @@ type TrafficSplitConfigRuleWeightedUpstream struct { Weight int `json:"weight"` } -// StreamRoute represents the stream route object in APISIX. +// StreamRoute represents the stream_route object in APISIX. // +k8s:deepcopy-gen=true type StreamRoute struct { // TODO metadata should use Metadata type @@ -334,6 +334,13 @@ type StreamRoute struct { UpstreamId string `json:"upstream_id,omitempty" yaml:"upstream_id,omitempty"` } +// 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"` +} + // NewDefaultUpstream returns an empty Upstream with default values. func NewDefaultUpstream() *Upstream { return &Upstream{ diff --git a/pkg/types/apisix/v1/zz_generated.deepcopy.go b/pkg/types/apisix/v1/zz_generated.deepcopy.go index 8fa8c11..a264ac0 100644 --- a/pkg/types/apisix/v1/zz_generated.deepcopy.go +++ b/pkg/types/apisix/v1/zz_generated.deepcopy.go @@ -21,6 +21,23 @@ limitations under the License. package v1 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GlobalRule) DeepCopyInto(out *GlobalRule) { + *out = *in + in.Plugins.DeepCopyInto(&out.Plugins) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalRule. +func (in *GlobalRule) DeepCopy() *GlobalRule { + if in == nil { + return nil + } + out := new(GlobalRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Metadata) DeepCopyInto(out *Metadata) { *out = *in if in.Labels != nil { diff --git a/samples/deploy/crd/v1beta1/ApisixClusterConfig.yaml b/samples/deploy/crd/v1beta1/ApisixClusterConfig.yaml new file mode 100644 index 0000000..b1d11d1 --- /dev/null +++ b/samples/deploy/crd/v1beta1/ApisixClusterConfig.yaml @@ -0,0 +1,71 @@ +# +# 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/v1beta1 +kind: CustomResourceDefinition +metadata: + name: apisixclusterconfigs.apisix.apache.org +spec: + group: apisix.apache.org + versions: + - name: v2alpha1 + served: true + storage: true + scope: Cluster + names: + plural: apisixclusterconfigs + singular: apisixclusterconfig + kind: ApisixClusterConfig + shortNames: + - acc + preserveUnknownFields: false + subresources: + status: {} + validation: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + admin: + type: object + required: + - baseURL + properties: + baseURL: + type: string + pattern: "https?://[^:]+:(\\d+)" + adminKey: + type: string + monitoring: + type: object + properties: + prometheus: + type: object + properties: + enable: + type: boolean + skywalking: + type: object + properties: + enable: + type: boolean + sampleRatio: + type: number + minimum: 0.00001 + maximum: 1 diff --git a/samples/deploy/crd/v1beta1/kustomization.yaml b/samples/deploy/crd/v1beta1/kustomization.yaml index 27a979f..1a2b65c 100644 --- a/samples/deploy/crd/v1beta1/kustomization.yaml +++ b/samples/deploy/crd/v1beta1/kustomization.yaml @@ -19,3 +19,4 @@ resources: - ./ApisixRoute.yaml - ./ApisixUpstream.yaml - ./ApisixTls.yaml + - ./ApisixClusterConfig.yaml