Skip to content

Commit

Permalink
feat: support plugin metadata (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
lingsamuel committed Sep 15, 2023
1 parent c2c6ae0 commit 4f4d9f2
Show file tree
Hide file tree
Showing 29 changed files with 597 additions and 96 deletions.
20 changes: 13 additions & 7 deletions cmd/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,20 @@ func dumpConfiguration(cmd *cobra.Command) error {
return err
}

pluginMetadatas, err := cluster.PluginMetadata().List(context.Background())
if err != nil {
return err
}

conf := &types.Configuration{
Routes: routes,
Services: svcs,
Consumers: consumers,
SSLs: ssls,
GlobalRules: globalRules,
PluginConfigs: pluginConfigs,
ConsumerGroups: consumerGroups,
Routes: routes,
Services: svcs,
Consumers: consumers,
SSLs: ssls,
GlobalRules: globalRules,
PluginConfigs: pluginConfigs,
ConsumerGroups: consumerGroups,
PluginMetadatas: pluginMetadatas,
}

if save {
Expand Down
5 changes: 5 additions & 0 deletions cmd/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ func newValidateCmd() *cobra.Command {
msg += fmt.Sprintf(", consumer_groups: %v", len(d.ConsumerGroups))
changed = true
}
// TODO: enable this when APISIX supports
//if len(d.PluginMetadatas) > 0 {
// msg += fmt.Sprintf(", plugin_metadatas: %v", len(d.PluginMetadatas))
// changed = true
//}
if !changed {
msg += "nothing changed"
}
Expand Down
21 changes: 21 additions & 0 deletions internal/pkg/db/memdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ var schema = &memdb.DBSchema{
},
},
},
"plugin_metadatas": {
Name: "plugin_metadatas",
Indexes: map[string]*memdb.IndexSchema{
"id": {
Name: "id",
Unique: true,
Indexer: &memdb.StringFieldIndex{Field: "ID"},
},
},
},
},
}

Expand Down Expand Up @@ -151,6 +161,13 @@ func NewMemDB(config *types.Configuration) (*DB, error) {
}
}

for _, consumerGroup := range config.PluginMetadatas {
err = txn.Insert("plugin_metadatas", consumerGroup)
if err != nil {
return nil, err
}
}

txn.Commit()

return &DB{memDB: db}, nil
Expand Down Expand Up @@ -196,3 +213,7 @@ func (db *DB) GetPluginConfigByID(id string) (*types.PluginConfig, error) {
func (db *DB) GetConsumerGroupByID(id string) (*types.ConsumerGroup, error) {
return getByID[types.ConsumerGroup](db, "consumer_groups", id)
}

func (db *DB) GetPluginMetadataByID(id string) (*types.PluginMetadata, error) {
return getByID[types.PluginMetadata](db, "plugin_metadatas", id)
}
74 changes: 68 additions & 6 deletions internal/pkg/differ/differ.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,15 @@ var order = map[string]int{
_key(data.ConsumerGroupResourceType, data.CreateOption): _order(),

// no dependency
_key(data.SSLResourceType, data.DeleteOption): _order(),
_key(data.SSLResourceType, data.CreateOption): _order(),
_key(data.SSLResourceType, data.UpdateOption): _order(),
_key(data.GlobalRuleResourceType, data.DeleteOption): _order(),
_key(data.GlobalRuleResourceType, data.CreateOption): _order(),
_key(data.GlobalRuleResourceType, data.UpdateOption): _order(),
_key(data.SSLResourceType, data.DeleteOption): _order(),
_key(data.SSLResourceType, data.CreateOption): _order(),
_key(data.SSLResourceType, data.UpdateOption): _order(),
_key(data.GlobalRuleResourceType, data.DeleteOption): _order(),
_key(data.GlobalRuleResourceType, data.CreateOption): _order(),
_key(data.GlobalRuleResourceType, data.UpdateOption): _order(),
_key(data.PluginMetadataResourceType, data.DeleteOption): _order(),
_key(data.PluginMetadataResourceType, data.CreateOption): _order(),
_key(data.PluginMetadataResourceType, data.UpdateOption): _order(),
}

// Differ is the object of comparing two configurations.
Expand Down Expand Up @@ -123,12 +126,18 @@ func (d *Differ) Diff() ([]*data.Event, error) {
return nil, err
}

pluginMetadataEvents, err := d.diffPluginMetadata()
if err != nil {
return nil, err
}

events = append(events, serviceEvents...)
events = append(events, routeEvents...)
events = append(events, consumerEvents...)
events = append(events, sslEvents...)
events = append(events, globalRuleEvents...)
events = append(events, pluginConfigEvents...)
events = append(events, pluginMetadataEvents...)
events = append(events, consumerGroupEvents...)

sortEvents(events)
Expand Down Expand Up @@ -507,3 +516,56 @@ func (d *Differ) diffConsumerGroup() ([]*data.Event, error) {

return events, nil
}

// diffPluginMetadata compares the global_rules between local and remote.
func (d *Differ) diffPluginMetadata() ([]*data.Event, error) {
var events []*data.Event
var mark = make(map[string]bool)

for _, remotePluginMetadata := range d.remoteConfig.PluginMetadatas {
localPluginMetadata, err := d.localDB.GetPluginMetadataByID(remotePluginMetadata.ID)
if err != nil {
// we can't find in local config, should delete it
if err == db.NotFound {
e := data.Event{
ResourceType: data.PluginMetadataResourceType,
Option: data.DeleteOption,
OldValue: remotePluginMetadata,
}
events = append(events, &e)
continue
}

return nil, err
}

mark[localPluginMetadata.ID] = true
// skip when equals
if equal := reflect.DeepEqual(localPluginMetadata, remotePluginMetadata); equal {
continue
}

// otherwise update
events = append(events, &data.Event{
ResourceType: data.PluginMetadataResourceType,
Option: data.UpdateOption,
OldValue: remotePluginMetadata,
Value: localPluginMetadata,
})
}

// only in local, create
for _, pluginMetadata := range d.localConfig.PluginMetadatas {
if mark[pluginMetadata.ID] {
continue
}

events = append(events, &data.Event{
ResourceType: data.PluginMetadataResourceType,
Option: data.CreateOption,
Value: pluginMetadata,
})
}

return events, nil
}
9 changes: 9 additions & 0 deletions internal/pkg/validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,14 @@ func (v *Validator) Validate() []error {
}
}

// TODO: enable this when APISIX supports
//for _, pluginMetadata := range v.localConfig.PluginMetadatas {
// pluginMetadata := pluginMetadata
// err := v.cluster.PluginMetadata().Validate(context.Background(), pluginMetadata)
// if err != nil {
// allErr = append(allErr, err)
// }
//}

return allErr
}
5 changes: 5 additions & 0 deletions pkg/api/apisix/apisix.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Cluster interface {
GlobalRule() GlobalRule
PluginConfig() PluginConfig
ConsumerGroup() ConsumerGroup
PluginMetadata() PluginMetadata
}

type ResourceClient[T any] interface {
Expand Down Expand Up @@ -52,3 +53,7 @@ type PluginConfig interface {
type ConsumerGroup interface {
ResourceClient[types.ConsumerGroup]
}

type PluginMetadata interface {
ResourceClient[types.PluginMetadata]
}
21 changes: 14 additions & 7 deletions pkg/api/apisix/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ type cluster struct {

cli *Client

route Route
service Service
consumer Consumer
ssl SSL
globalRule GlobalRule
pluginConfig PluginConfig
consumerGroup ConsumerGroup
route Route
service Service
consumer Consumer
ssl SSL
globalRule GlobalRule
pluginConfig PluginConfig
consumerGroup ConsumerGroup
pluginMetadata PluginMetadata
}

func NewCluster(ctx context.Context, url, adminKey string) Cluster {
Expand All @@ -35,6 +36,7 @@ func NewCluster(ctx context.Context, url, adminKey string) Cluster {
c.globalRule = newGlobalRule(cli)
c.pluginConfig = newPluginConfig(cli)
c.consumerGroup = newConsumerGroup(cli)
c.pluginMetadata = newPluginMetadata(cli)

return c
}
Expand Down Expand Up @@ -73,3 +75,8 @@ func (c *cluster) PluginConfig() PluginConfig {
func (c *cluster) ConsumerGroup() ConsumerGroup {
return c.consumerGroup
}

// PluginMetadata implements Cluster.PluginMetadata method.
func (c *cluster) PluginMetadata() PluginMetadata {
return c.pluginMetadata
}
26 changes: 26 additions & 0 deletions pkg/api/apisix/plugin_metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package apisix

import (
"context"

"github.com/api7/adc/pkg/api/apisix/types"
)

type pluginMetadataClient struct {
*resourceClient[types.PluginMetadata]
}

func newPluginMetadata(c *Client) PluginMetadata {
cli := newResourceClient[types.PluginMetadata](c, "plugin_metadata")
return &pluginMetadataClient{
resourceClient: cli,
}
}

func (u *pluginMetadataClient) Create(ctx context.Context, obj *types.PluginMetadata) (*types.PluginMetadata, error) {
return u.resourceClient.Create(ctx, obj.ID, obj)
}

func (u *pluginMetadataClient) Update(ctx context.Context, obj *types.PluginMetadata) (*types.PluginMetadata, error) {
return u.resourceClient.Update(ctx, obj.ID, obj)
}
23 changes: 12 additions & 11 deletions pkg/api/apisix/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,20 @@ func unmarshalItem[T any](i *item) (*T, error) {
return nil, fmt.Errorf("bad upstream config key: %s", i.Key)
}

var ups T
if err := json.Unmarshal(i.Value, &ups); err != nil {
var obj T
if err := json.Unmarshal(i.Value, &obj); err != nil {
return nil, err
}
return &ups, nil
}

// upstream decodes item.Value and converts it to types.Upstream.
func (i *item) upstream() (*types.Upstream, error) {
return unmarshalItem[types.Upstream](i)
}
// patch PluginMetadata since the response doesn't contain ID
switch any(obj).(type) {
case *types.PluginMetadata:
any(obj).(*types.PluginMetadata).ID = list[len(list)-1]
break
case types.PluginMetadata:
any(&obj).(*types.PluginMetadata).ID = list[len(list)-1]
break
}

// service decodes item.Value and converts it to types.Service.
func (i *item) service() (*types.Service, error) {
return unmarshalItem[types.Service](i)
return &obj, nil
}

0 comments on commit 4f4d9f2

Please sign in to comment.