mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-13 19:33:55 +03:00
cli: support api_limits
in metadata
GitOrigin-RevId: e0d2e30bb2775f761232218aa67cf3781df3e49a
This commit is contained in:
parent
7be8003a4b
commit
cc24e50515
@ -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
|
||||
|
||||
|
94
cli/internal/metadataobject/api_limits/api_limits.go
Normal file
94
cli/internal/metadataobject/api_limits/api_limits.go
Normal 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"
|
||||
}
|
136
cli/internal/metadataobject/api_limits/api_limits_test.go
Normal file
136
cli/internal/metadataobject/api_limits/api_limits_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
14
cli/internal/metadataobject/api_limits/testdata/metadata.json
vendored
Normal file
14
cli/internal/metadataobject/api_limits/testdata/metadata.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
6
cli/internal/metadataobject/api_limits/testdata/metadata/api_limits.yaml
vendored
Normal file
6
cli/internal/metadataobject/api_limits/testdata/metadata/api_limits.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
disabled: false
|
||||
rate_limit:
|
||||
per_role: {}
|
||||
global:
|
||||
unique_params: IP
|
||||
max_reqs_per_min: 1
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user