| // 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" |
| "sync" |
| |
| v1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" |
| ) |
| |
| // APISIX is the unified client tool to communicate with APISIX. |
| type APISIX interface { |
| // Cluster specifies the target cluster to talk. |
| Cluster(string) Cluster |
| // AddCluster adds a new cluster. |
| AddCluster(context.Context, *ClusterOptions) error |
| // UpdateCluster updates an existing cluster. |
| UpdateCluster(context.Context, *ClusterOptions) error |
| // ListClusters lists all APISIX clusters. |
| ListClusters() []Cluster |
| } |
| |
| // Cluster defines specific operations that can be applied in an APISIX |
| // cluster. |
| type Cluster interface { |
| // Route returns a Route interface that can operate Route resources. |
| Route() Route |
| // Upstream returns a Upstream interface that can operate Upstream resources. |
| Upstream() Upstream |
| // SSL returns a SSL interface that can operate SSL resources. |
| SSL() SSL |
| // StreamRoute returns a StreamRoute interface that can operate StreamRoute resources. |
| StreamRoute() StreamRoute |
| // GlobalRule returns a GlobalRule interface that can operate GlobalRule resources. |
| GlobalRule() GlobalRule |
| // String exposes the client information in human readable format. |
| String() string |
| // HasSynced checks whether all resources in APISIX cluster is synced to cache. |
| HasSynced(context.Context) error |
| // Consumer returns a Consumer interface that can operate Consumer resources. |
| Consumer() Consumer |
| // HealthCheck checks apisix cluster health in realtime. |
| HealthCheck(context.Context) error |
| // Plugin returns a Plugin interface that can operate Plugin resources. |
| Plugin() Plugin |
| // Schema returns a Schema interface that can fetch schema of APISIX objects. |
| Schema() Schema |
| } |
| |
| // Route is the specific client interface to take over the create, update, |
| // list and delete for APISIX Route resource. |
| type Route interface { |
| Get(context.Context, string) (*v1.Route, error) |
| List(context.Context) ([]*v1.Route, error) |
| Create(context.Context, *v1.Route) (*v1.Route, error) |
| Delete(context.Context, *v1.Route) error |
| Update(context.Context, *v1.Route) (*v1.Route, error) |
| } |
| |
| // SSL is the specific client interface to take over the create, update, |
| // list and delete for APISIX SSL resource. |
| type SSL interface { |
| Get(context.Context, string) (*v1.Ssl, error) |
| List(context.Context) ([]*v1.Ssl, error) |
| Create(context.Context, *v1.Ssl) (*v1.Ssl, error) |
| Delete(context.Context, *v1.Ssl) error |
| Update(context.Context, *v1.Ssl) (*v1.Ssl, error) |
| } |
| |
| // Upstream is the specific client interface to take over the create, update, |
| // list and delete for APISIX Upstream resource. |
| type Upstream interface { |
| Get(context.Context, string) (*v1.Upstream, error) |
| List(context.Context) ([]*v1.Upstream, error) |
| Create(context.Context, *v1.Upstream) (*v1.Upstream, error) |
| Delete(context.Context, *v1.Upstream) error |
| Update(context.Context, *v1.Upstream) (*v1.Upstream, error) |
| } |
| |
| // StreamRoute is the specific client interface to take over the create, update, |
| // list and delete for APISIX Stream Route resource. |
| type StreamRoute interface { |
| Get(context.Context, string) (*v1.StreamRoute, error) |
| List(context.Context) ([]*v1.StreamRoute, error) |
| Create(context.Context, *v1.StreamRoute) (*v1.StreamRoute, error) |
| Delete(context.Context, *v1.StreamRoute) error |
| 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 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) |
| } |
| |
| // Consumer is the specific client interface to take over the create, update, |
| // list and delete for APISIX Consumer resource. |
| type Consumer interface { |
| Get(context.Context, string) (*v1.Consumer, error) |
| List(context.Context) ([]*v1.Consumer, error) |
| Create(context.Context, *v1.Consumer) (*v1.Consumer, error) |
| Delete(context.Context, *v1.Consumer) error |
| Update(context.Context, *v1.Consumer) (*v1.Consumer, error) |
| } |
| |
| // Plugin is the specific client interface to fetch APISIX Plugin resource. |
| type Plugin interface { |
| List(context.Context) ([]string, error) |
| } |
| |
| // Schema is the specific client interface to fetch the schema of APISIX objects. |
| type Schema interface { |
| GetPluginSchema(context.Context, string) (*v1.Schema, error) |
| } |
| |
| type apisix struct { |
| mu sync.RWMutex |
| nonExistentCluster Cluster |
| clusters map[string]Cluster |
| } |
| |
| // NewClient creates an APISIX client to perform resources change pushing. |
| func NewClient() (APISIX, error) { |
| cli := &apisix{ |
| nonExistentCluster: newNonExistentCluster(), |
| clusters: make(map[string]Cluster), |
| } |
| return cli, nil |
| } |
| |
| // Cluster implements APISIX.Cluster method. |
| func (c *apisix) Cluster(name string) Cluster { |
| c.mu.RLock() |
| defer c.mu.RUnlock() |
| cluster, ok := c.clusters[name] |
| if !ok { |
| return c.nonExistentCluster |
| } |
| return cluster |
| } |
| |
| // ListClusters implements APISIX.ListClusters method. |
| func (c *apisix) ListClusters() []Cluster { |
| c.mu.RLock() |
| defer c.mu.RUnlock() |
| clusters := make([]Cluster, 0, len(c.clusters)) |
| for _, cluster := range c.clusters { |
| clusters = append(clusters, cluster) |
| } |
| return clusters |
| } |
| |
| // AddCluster implements APISIX.AddCluster method. |
| func (c *apisix) AddCluster(ctx context.Context, co *ClusterOptions) error { |
| c.mu.Lock() |
| defer c.mu.Unlock() |
| _, ok := c.clusters[co.Name] |
| if ok { |
| return ErrDuplicatedCluster |
| } |
| cluster, err := newCluster(ctx, co) |
| if err != nil { |
| return err |
| } |
| c.clusters[co.Name] = cluster |
| return nil |
| } |
| |
| func (c *apisix) UpdateCluster(ctx context.Context, co *ClusterOptions) error { |
| c.mu.Lock() |
| defer c.mu.Unlock() |
| if _, ok := c.clusters[co.Name]; !ok { |
| return ErrClusterNotExist |
| } |
| |
| cluster, err := newCluster(ctx, co) |
| if err != nil { |
| return err |
| } |
| |
| c.clusters[co.Name] = cluster |
| return nil |
| } |