cli: support api_limits in metadata

GitOrigin-RevId: e0d2e30bb2775f761232218aa67cf3781df3e49a
This commit is contained in:
Aravind K P 2021-04-21 15:39:09 +05:30 committed by hasura-bot
parent 7be8003a4b
commit cc24e50515
7 changed files with 259 additions and 1 deletions

View File

@ -3,6 +3,9 @@
## Next release
(Add entries below in the order of: server, console, cli, docs, others)
- cli: fix regression - `metadata apply —dry-run` was overwriting local metadata files with metadata on server when it should just display the differences.
- cli: add support for `api_limits` metadata object
## v2.0.0-alpha.9
### Support comparing columns across related tables in permission's boolean expressions
@ -22,7 +25,6 @@ only when there are enough present in the items inventory.
- server: an inherited role's limit will be the max limit of all the roles (#6671)
- console: add bigquery support (#1000)
- cli: add support for bigquery in metadata operations
- cli: fix regression - `metadata apply —dry-run` was overwriting local metadata files with metadata on server when it should just display the differences.
## v2.0.0-alpha.8

View File

@ -0,0 +1,94 @@
package apilimits
import (
"io/ioutil"
"path/filepath"
"github.com/sirupsen/logrus"
"github.com/hasura/graphql-engine/cli"
"gopkg.in/yaml.v2"
)
const (
MetadataFilename string = "api_limits.yaml"
)
type MetadataObject struct {
MetadataDir string
logger *logrus.Logger
}
func New(ec *cli.ExecutionContext, baseDir string) *MetadataObject {
return &MetadataObject{
MetadataDir: baseDir,
logger: ec.Logger,
}
}
func (o *MetadataObject) Validate() error {
return nil
}
func (o *MetadataObject) CreateFiles() error {
var v interface{}
data, err := yaml.Marshal(v)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(o.MetadataDir, MetadataFilename), data, 0644)
if err != nil {
return err
}
return nil
}
func (o *MetadataObject) Build(metadata *yaml.MapSlice) error {
data, err := ioutil.ReadFile(filepath.Join(o.MetadataDir, MetadataFilename))
if err != nil {
return err
}
item := yaml.MapItem{
Key: o.Name(),
}
var obj yaml.MapSlice
err = yaml.Unmarshal(data, &obj)
if err != nil {
return err
}
if len(obj) > 0 {
item.Value = obj
*metadata = append(*metadata, item)
}
return nil
}
func (o *MetadataObject) Export(metadata yaml.MapSlice) (map[string][]byte, error) {
var apiLimits interface{}
for _, item := range metadata {
k, ok := item.Key.(string)
if !ok || k != o.Name() {
continue
}
apiLimits = item.Value
}
if apiLimits == nil {
o.logger.WithFields(logrus.Fields{
"object": o.Name(),
"reason": "not found in metadata",
}).Debugf("skipped building %s", o.Name())
return nil, nil
}
data, err := yaml.Marshal(apiLimits)
if err != nil {
return nil, err
}
return map[string][]byte{
filepath.Join(o.MetadataDir, MetadataFilename): data,
}, nil
}
func (o *MetadataObject) Name() string {
return "api_limits"
}

View File

@ -0,0 +1,136 @@
package apilimits
import (
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"io/ioutil"
"testing"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
)
func TestMetadataObject_Build(t *testing.T) {
type fields struct {
MetadataDir string
logger *logrus.Logger
}
type args struct {
metadata *yaml.MapSlice
}
tests := []struct {
name string
fields fields
args args
want string
wantErr bool
}{
{
"can build from file",
fields{
MetadataDir: "testdata/metadata",
logger: logrus.New(),
},
args{
metadata: new(yaml.MapSlice),
},
`api_limits:
disabled: false
rate_limit:
per_role: {}
global:
unique_params: IP
max_reqs_per_min: 1
`,
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &MetadataObject{
MetadataDir: tt.fields.MetadataDir,
logger: tt.fields.logger,
}
err := m.Build(tt.args.metadata)
if tt.wantErr {
require.Error(t, err)
}else {
b, err := yaml.Marshal(tt.args.metadata)
assert.NoError(t, err)
assert.Equal(t, tt.want, string(b))
}
})
}
}
func TestMetadataObject_Export(t *testing.T) {
type fields struct {
MetadataDir string
logger *logrus.Logger
}
type args struct {
metadata yaml.MapSlice
}
tests := []struct {
name string
fields fields
args args
want map[string][]byte
wantErr bool
}{
{
"can export metadata with api_limits",
fields{
MetadataDir: "testdata/metadata",
logger: logrus.New(),
},
args{
metadata: func() yaml.MapSlice {
var metadata yaml.MapSlice
jsonb, err := ioutil.ReadFile("testdata/metadata.json")
assert.NoError(t, err)
assert.NoError(t, yaml.Unmarshal(jsonb, &metadata))
return metadata
}(),
},
map[string][]byte{
"testdata/metadata/api_limits.yaml": []byte(`disabled: false
rate_limit:
per_role: {}
global:
unique_params: IP
max_reqs_per_min: 1
`),
},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
obj := &MetadataObject{
MetadataDir: tt.fields.MetadataDir,
logger: tt.fields.logger,
}
got, err := obj.Export(tt.args.metadata)
if tt.wantErr {
require.Error(t, err)
}else {
require.NoError(t, err)
var wantContent = map[string]string{}
var gotContent = map[string]string{}
for k, v := range got {
gotContent[k] = string(v)
}
for k, v := range tt.want {
wantContent[k] = string(v)
}
assert.NoError(t, err)
assert.NoError(t, err)
if diff := cmp.Diff(wantContent, gotContent); diff != "" {
t.Errorf("Export() mismatch (-want +got):\n%s", diff)
}
}
})
}
}

View File

@ -0,0 +1,14 @@
{
"version": 3,
"sources": [],
"api_limits": {
"disabled": false,
"rate_limit": {
"per_role": {},
"global": {
"unique_params": "IP",
"max_reqs_per_min": 1
}
}
}
}

View File

@ -0,0 +1,6 @@
disabled: false
rate_limit:
per_role: {}
global:
unique_params: IP
max_reqs_per_min: 1

View File

@ -4,6 +4,7 @@ import (
"github.com/hasura/graphql-engine/cli"
"github.com/hasura/graphql-engine/cli/internal/metadataobject/actions"
"github.com/hasura/graphql-engine/cli/internal/metadataobject/allowlist"
apilimits "github.com/hasura/graphql-engine/cli/internal/metadataobject/api_limits"
crontriggers "github.com/hasura/graphql-engine/cli/internal/metadataobject/cron_triggers"
"github.com/hasura/graphql-engine/cli/internal/metadataobject/functions"
inheritedroles "github.com/hasura/graphql-engine/cli/internal/metadataobject/inherited_roles"
@ -43,6 +44,7 @@ func GetMetadataObjectsWithDir(ec *cli.ExecutionContext, dir ...string) Objects
objects = append(objects, crontriggers.New(ec, metadataDir))
objects = append(objects, restendpoints.New(ec, metadataDir))
objects = append(objects, inheritedroles.New(ec, metadataDir))
objects = append(objects, apilimits.New(ec, metadataDir))
if ec.HasMetadataV3 {
if ec.Config.Version >= cli.V3 {

View File

@ -8,6 +8,10 @@ import (
"gopkg.in/yaml.v2"
)
/*
V3MetadataTableConfig is responsible for exporting and applying "tables" metadata objects
in config v2 format on a server with v3 metadata
*/
type V3MetadataTableConfig struct {
*TableConfig
}