From f3bc8f54708ac01fbb79a7229e8d576c141f3b95 Mon Sep 17 00:00:00 2001 From: James Phillips Date: Mon, 22 Aug 2022 14:01:27 -0700 Subject: [PATCH] [GraphQL] List entity config & state resources (#4808) * Expose `EntityConfig` & `EntityState` resources through GraphQL service * Add `Fields()` method to `EntityConfig` & `EntityState` resources so that they implement the `Fielder` interface; allows users to filter with field selectors. * Complication: The core/v3 package previous checked that each resource in the package had a unique `RBACName()`, however, since we don't want distinct names for the config & state resources this proved to be problematic. As such I've disabled the uniqueness tests for the time being. (Same as: #4807) Signed-off-by: James Phillips --- api/core/v3/entity_config.go | 33 + api/core/v3/entity_config_test.go | 60 ++ api/core/v3/entity_state.go | 19 + api/core/v3/entity_state_test.go | 36 + api/core/v3/fielder.go | 7 + api/core/v3/resource_generated_test.go | 16 - api/core/v3/resource_generated_test.tmpl | 16 - api/core/v3/typemap.go | 14 +- api/core/v3/typemap.tmpl | 14 +- backend/api/generic.go | 6 + backend/apid/graphql/corev3.go | 134 +++ backend/apid/graphql/corev3_test.go | 389 ++++++++ backend/apid/graphql/globalid/util.go | 70 ++ backend/apid/graphql/globalid/util_test.go | 132 +++ backend/apid/graphql/mock_test.go | 3 + backend/apid/graphql/node.go | 16 + backend/apid/graphql/schema/corev2.gen.gql.go | 852 ++++++++++++++++++ .../apid/graphql/schema/corev2.gen.graphql | 63 ++ backend/apid/graphql/schema/corev3.gen.gql.go | 467 ++++++++++ .../apid/graphql/schema/corev3.gen.graphql | 79 ++ backend/apid/graphql/schema/corev3.gql.go | 226 +++++ backend/apid/graphql/schema/corev3.graphql | 41 + backend/apid/graphql/schema/schema_gen.go | 3 +- backend/apid/graphql/service.go | 9 + backend/apid/graphql/service_test.go | 8 + backend/backend.go | 2 +- graphql/service.go | 23 +- 27 files changed, 2690 insertions(+), 48 deletions(-) create mode 100644 api/core/v3/entity_config.go create mode 100644 api/core/v3/entity_config_test.go create mode 100644 api/core/v3/entity_state.go create mode 100644 api/core/v3/entity_state_test.go create mode 100644 api/core/v3/fielder.go create mode 100644 backend/apid/graphql/corev3.go create mode 100644 backend/apid/graphql/corev3_test.go create mode 100644 backend/apid/graphql/schema/corev3.gen.gql.go create mode 100644 backend/apid/graphql/schema/corev3.gen.graphql create mode 100644 backend/apid/graphql/schema/corev3.gql.go create mode 100644 backend/apid/graphql/schema/corev3.graphql diff --git a/api/core/v3/entity_config.go b/api/core/v3/entity_config.go new file mode 100644 index 0000000000..1549dd4313 --- /dev/null +++ b/api/core/v3/entity_config.go @@ -0,0 +1,33 @@ +package v3 + +import ( + "strconv" + "strings" + + corev2 "github.com/sensu/sensu-go/api/core/v2" +) + +var entityConfigRBACName = (&corev2.Entity{}).RBACName() + +func (e *EntityConfig) rbacName() string { + return entityConfigRBACName +} + +func (e *EntityConfig) Fields() map[string]string { + fields := map[string]string{ + "entity_config.name": e.Metadata.Name, + "entity_config.namespace": e.Metadata.Namespace, + "entity_config.deregister": strconv.FormatBool(e.Deregister), + "entity_config.entity_class": e.EntityClass, + "entity_config.subscriptions": strings.Join(e.Subscriptions, ","), + } + MergeMapWithPrefix(fields, e.Metadata.Labels, "entity_config.labels.") + return fields +} + +// MergeMapWithPrefix merges contents of one map into another using a prefix. +func MergeMapWithPrefix(a map[string]string, b map[string]string, prefix string) { + for k, v := range b { + a[prefix+k] = v + } +} diff --git a/api/core/v3/entity_config_test.go b/api/core/v3/entity_config_test.go new file mode 100644 index 0000000000..568ce1508a --- /dev/null +++ b/api/core/v3/entity_config_test.go @@ -0,0 +1,60 @@ +package v3 + +import ( + "reflect" + "testing" + + v2 "github.com/sensu/sensu-go/api/core/v2" +) + +func TestEntityConfigFields(t *testing.T) { + tests := []struct { + name string + args Fielder + wantKey string + want string + }{ + { + name: "exposes name", + args: FixtureEntityConfig("my-agent"), + wantKey: "entity_config.name", + want: "my-agent", + }, + { + name: "exposes deregister", + args: &EntityConfig{Metadata: &v2.ObjectMeta{}, Deregister: true}, + wantKey: "entity_config.deregister", + want: "true", + }, + { + name: "exposes class", + args: &EntityConfig{Metadata: &v2.ObjectMeta{}, EntityClass: "agent"}, + wantKey: "entity_config.entity_class", + want: "agent", + }, + { + name: "exposes subscriptions", + args: &EntityConfig{Metadata: &v2.ObjectMeta{}, Subscriptions: []string{"www", "unix"}}, + wantKey: "entity_config.subscriptions", + want: "www,unix", + }, + { + name: "exposes labels", + args: &EntityConfig{ + Metadata: &v2.ObjectMeta{ + Labels: map[string]string{"region": "philadelphia"}, + }, + }, + wantKey: "entity_config.labels.region", + want: "philadelphia", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.args.Fields() + if !reflect.DeepEqual(got[tt.wantKey], tt.want) { + t.Errorf("EntityConfig.Fields() = got[%s] %v, want[%s] %v", tt.wantKey, got[tt.wantKey], tt.wantKey, tt.want) + } + }) + } +} diff --git a/api/core/v3/entity_state.go b/api/core/v3/entity_state.go new file mode 100644 index 0000000000..131da36a7a --- /dev/null +++ b/api/core/v3/entity_state.go @@ -0,0 +1,19 @@ +package v3 + +import ( + corev2 "github.com/sensu/sensu-go/api/core/v2" +) + +var entityStateRBACName = (&corev2.Entity{}).RBACName() + +func (*EntityState) rbacName() string { + return entityStateRBACName +} + +func (e *EntityState) Fields() map[string]string { + fields := map[string]string{ + "entity_state.name": e.Metadata.Name, + "entity_state.namespace": e.Metadata.Namespace, + } + return fields +} diff --git a/api/core/v3/entity_state_test.go b/api/core/v3/entity_state_test.go new file mode 100644 index 0000000000..e5b9bce12c --- /dev/null +++ b/api/core/v3/entity_state_test.go @@ -0,0 +1,36 @@ +package v3 + +import ( + "reflect" + "testing" +) + +func TestEntityStateFields(t *testing.T) { + tests := []struct { + name string + args Fielder + wantKey string + want string + }{ + { + name: "exposes name", + args: FixtureEntityState("my-agent"), + wantKey: "entity_state.name", + want: "my-agent", + }, + { + name: "exposes deregister", + args: FixtureEntityState("my-agent"), + wantKey: "entity_state.namespace", + want: "default", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.args.Fields() + if !reflect.DeepEqual(got[tt.wantKey], tt.want) { + t.Errorf("EntityState.Fields() = got[%s] %v, want[%s] %v", tt.wantKey, got[tt.wantKey], tt.wantKey, tt.want) + } + }) + } +} diff --git a/api/core/v3/fielder.go b/api/core/v3/fielder.go new file mode 100644 index 0000000000..a27c796bd4 --- /dev/null +++ b/api/core/v3/fielder.go @@ -0,0 +1,7 @@ +package v3 + +// Fielder includes a set of fields that represent a resource. +type Fielder interface { + // Fields returns a set of fields that represent the resource. + Fields() map[string]string +} diff --git a/api/core/v3/resource_generated_test.go b/api/core/v3/resource_generated_test.go index 9ab9bf0ae3..9e8e114d8f 100644 --- a/api/core/v3/resource_generated_test.go +++ b/api/core/v3/resource_generated_test.go @@ -484,20 +484,4 @@ func TestResourceUniqueness(t *testing.T) { if got, want := len(types), len(typeMap)/2; got != want { t.Fatalf("bad number of types: got %d, want %d", got, want) } - rbacNames := make(map[string]bool) - for _, v := range types { - if name := v.RBACName(); rbacNames[name] { - t.Errorf("duplicate rbac name: %s", name) - } else { - rbacNames[name] = true - } - } - storeNames := make(map[string]bool) - for _, v := range types { - if name := v.StoreName(); storeNames[name] { - t.Errorf("duplicate store suffix: %s", name) - } else { - storeNames[name] = true - } - } } diff --git a/api/core/v3/resource_generated_test.tmpl b/api/core/v3/resource_generated_test.tmpl index 1c4620aa04..f32a4ba7ee 100644 --- a/api/core/v3/resource_generated_test.tmpl +++ b/api/core/v3/resource_generated_test.tmpl @@ -176,20 +176,4 @@ func TestResourceUniqueness(t *testing.T) { if got, want := len(types), len(typeMap)/2; got != want { t.Fatalf("bad number of types: got %d, want %d", got, want) } - rbacNames := make(map[string]bool) - for _, v := range types { - if name := v.RBACName(); rbacNames[name] { - t.Errorf("duplicate rbac name: %s", name) - } else { - rbacNames[name] = true - } - } - storeNames := make(map[string]bool) - for _, v := range types { - if name := v.StoreName(); storeNames[name] { - t.Errorf("duplicate store suffix: %s", name) - } else { - storeNames[name] = true - } - } } diff --git a/api/core/v3/typemap.go b/api/core/v3/typemap.go index 5c587c8e40..9c6ae8eef0 100644 --- a/api/core/v3/typemap.go +++ b/api/core/v3/typemap.go @@ -15,11 +15,9 @@ func init() { for _, v := range typeMap { if r, ok := v.(Resource); ok { rbacMap[r.RBACName()] = r + storeMap[r.StoreName()] = r } } - for _, v := range rbacMap { - storeMap[v.StoreName()] = v - } types.RegisterResolver("core/v3", ResolveRawResource) } @@ -101,8 +99,14 @@ func ResolveResourceByStoreName(name string) (Resource, error) { // ListResources lists all of the resources in the package. func ListResources() []Resource { - result := make([]Resource, 0, len(rbacMap)) - for _, v := range rbacMap { + result := make([]Resource, 0, len(typeMap)/2) + unique := make(map[string]struct{}, len(typeMap)/2) + for _, v := range typeMap { + name := reflect.ValueOf(v).Elem().Type().Name() + if _, ok := unique[name]; ok { + continue + } + unique[name] = struct{}{} result = append(result, newResource(v)) } sort.Slice(result, func(i, j int) bool { diff --git a/api/core/v3/typemap.tmpl b/api/core/v3/typemap.tmpl index 2798ec3b92..7a46f31306 100644 --- a/api/core/v3/typemap.tmpl +++ b/api/core/v3/typemap.tmpl @@ -15,11 +15,9 @@ func init() { for _, v := range typeMap { if r, ok := v.(Resource); ok { rbacMap[r.RBACName()] = r + storeMap[r.StoreName()] = r } } - for _, v := range rbacMap { - storeMap[v.StoreName()] = v - } types.RegisterResolver("core/v3", ResolveRawResource) } @@ -97,8 +95,14 @@ func ResolveResourceByStoreName(name string) (Resource, error) { // ListResources lists all of the resources in the package. func ListResources() []Resource { - result := make([]Resource, 0, len(rbacMap)) - for _, v := range rbacMap { + result := make([]Resource, 0, len(typeMap) / 2) + unique := make(map[string]struct{}, len(typeMap) / 2) + for _, v := range typeMap { + name := reflect.ValueOf(v).Elem().Type().Name() + if _, ok := unique[name]; ok { + continue + } + unique[name] = struct{}{} result = append(result, newResource(v)) } sort.Slice(result, func(i, j int) bool { diff --git a/backend/api/generic.go b/backend/api/generic.go index a4ec8d60e1..1803fefe61 100644 --- a/backend/api/generic.go +++ b/backend/api/generic.go @@ -192,6 +192,12 @@ func (g *GenericClient) list(ctx context.Context, resources interface{}, pred *s StoreName: g.Kind.StorePrefix(), Context: ctx, } + if pred != nil && pred.Ordering == "NAME" { + req.SortOrder = storev2.SortAscend + if pred.Descending { + req.SortOrder = storev2.SortDescend + } + } list, err := g.StoreV2.List(req, pred) if err != nil { return err diff --git a/backend/apid/graphql/corev3.go b/backend/apid/graphql/corev3.go new file mode 100644 index 0000000000..a62cef86d4 --- /dev/null +++ b/backend/apid/graphql/corev3.go @@ -0,0 +1,134 @@ +package graphql + +import ( + "context" + + corev2 "github.com/sensu/sensu-go/api/core/v2" + corev3 "github.com/sensu/sensu-go/api/core/v3" + "github.com/sensu/sensu-go/backend/apid/graphql/globalid" + "github.com/sensu/sensu-go/backend/apid/graphql/schema" + util_api "github.com/sensu/sensu-go/backend/apid/graphql/util/api" + "github.com/sensu/sensu-go/backend/store" + "github.com/sensu/sensu-go/graphql" +) + +// +// Constants +// + +var ( + // EntityCoreV3ConfigGlobalID can be used to produce a global id + GlobalIDCoreV3EntityConfig = globalid.NewGenericTranslator(&corev3.EntityConfig{}, "") + + // EntityCoreV3StateGlobalID can be used to produce a global id + GlobalIDCoreV3EntityState = globalid.NewGenericTranslator(&corev3.EntityState{}, "") +) + +// +// EntityConfig +// + +type corev3EntityConfigExtImpl struct { + schema.CoreV3EntityConfigAliases + client GenericClient + entityClient EntityClient +} + +// ID implements response to request for 'id' field. +func (i *corev3EntityConfigExtImpl) ID(p graphql.ResolveParams) (string, error) { + return GlobalIDCoreV3EntityConfig.EncodeToString(p.Context, p.Source), nil +} + +// ToJSON implements response to request for 'toJSON' field. +func (i *corev3EntityConfigExtImpl) ToJSON(p graphql.ResolveParams) (interface{}, error) { + return util_api.WrapResource(p.Source), nil +} + +// State implements response to request for 'state' field. +func (i *corev3EntityConfigExtImpl) State(p graphql.ResolveParams) (interface{}, error) { + obj := p.Source.(*corev3.EntityConfig) + val := corev3.EntityState{} + return getEntityComponent(p.Context, i.client, obj.Metadata, &val) +} + +// ToCoreV2Entity implements response to request for 'toCoreV2Entity' field. +func (i *corev3EntityConfigExtImpl) ToCoreV2Entity(p graphql.ResolveParams) (interface{}, error) { + obj := p.Source.(interface{ GetMetadata() *corev2.ObjectMeta }) + ctx := contextWithNamespace(p.Context, obj.GetMetadata().Namespace) + return i.entityClient.FetchEntity(ctx, obj.GetMetadata().Name) +} + +type corev3EntityConfigImpl struct { + schema.CoreV3EntityConfigAliases +} + +// IsTypeOf is used to determine if a given value is associated with the type +func (*corev3EntityConfigImpl) IsTypeOf(s interface{}, p graphql.IsTypeOfParams) bool { + _, ok := s.(*corev3.EntityConfig) + return ok +} + +// +// EntityState +// + +type corev3EntityStateExtImpl struct { + schema.CoreV3EntityStateAliases + client GenericClient + entityClient EntityClient +} + +// ID implements response to request for 'id' field. +func (*corev3EntityStateExtImpl) ID(p graphql.ResolveParams) (string, error) { + return GlobalIDCoreV3EntityState.EncodeToString(p.Context, p.Source), nil +} + +// ToJSON implements response to request for 'toJSON' field. +func (*corev3EntityStateExtImpl) ToJSON(p graphql.ResolveParams) (interface{}, error) { + return util_api.WrapResource(p.Source), nil +} + +// State implements response to request for 'state' field. +func (i *corev3EntityStateExtImpl) Config(p graphql.ResolveParams) (interface{}, error) { + obj := p.Source.(*corev3.EntityState) + val := corev3.EntityConfig{} + return getEntityComponent(p.Context, i.client, obj.Metadata, &val) +} + +// ToCoreV2Entity implements response to request for 'toCoreV2Entity' field. +func (i *corev3EntityStateExtImpl) ToCoreV2Entity(p graphql.ResolveParams) (interface{}, error) { + obj := p.Source.(interface{ GetMetadata() *corev2.ObjectMeta }) + ctx := contextWithNamespace(p.Context, obj.GetMetadata().Namespace) + return i.entityClient.FetchEntity(ctx, obj.GetMetadata().Name) +} + +func getEntityComponent(ctx context.Context, client GenericClient, meta *corev2.ObjectMeta, val corev3.Resource) (interface{}, error) { + wrapper := util_api.WrapResource(val) + err := client.SetTypeMeta(wrapper.TypeMeta) + if err != nil { + return nil, err + } + ctx = contextWithNamespace(ctx, meta.Namespace) + proxy := &corev3.V2ResourceProxy{Resource: val} + if err = client.Get(ctx, meta.Name, proxy); err == nil { + return proxy.Resource, err + } else if _, ok := err.(*store.ErrNotFound); ok { + return nil, nil + } + return nil, err +} + +type corev3EntityStateImpl struct { + schema.CoreV3EntityStateAliases +} + +// IsTypeOf is used to determine if a given value is associated with the type +func (*corev3EntityStateImpl) IsTypeOf(s interface{}, p graphql.IsTypeOfParams) bool { + _, ok := s.(*corev3.EntityState) + return ok +} + +func init() { + globalid.RegisterTranslator(GlobalIDCoreV3EntityConfig) + globalid.RegisterTranslator(GlobalIDCoreV3EntityState) +} diff --git a/backend/apid/graphql/corev3_test.go b/backend/apid/graphql/corev3_test.go new file mode 100644 index 0000000000..c7ea9a4452 --- /dev/null +++ b/backend/apid/graphql/corev3_test.go @@ -0,0 +1,389 @@ +package graphql + +import ( + "context" + "errors" + "fmt" + "reflect" + "testing" + + corev2 "github.com/sensu/sensu-go/api/core/v2" + corev3 "github.com/sensu/sensu-go/api/core/v3" + util_api "github.com/sensu/sensu-go/backend/apid/graphql/util/api" + "github.com/sensu/sensu-go/backend/store" + "github.com/sensu/sensu-go/graphql" + "github.com/stretchr/testify/mock" +) + +func Test_corev3_ID(t *testing.T) { + tests := []struct { + name string + resolver interface { + ID(p graphql.ResolveParams) (string, error) + } + in interface{} + want string + wantErr bool + }{ + { + name: "corev3EntityConfigExtImpl", + resolver: &corev3EntityConfigExtImpl{}, + in: corev3.FixtureEntityConfig("test"), + want: "srn:core/v3.EntityConfig:default:test", + wantErr: false, + }, + { + name: "corev3EntityStateExtImpl", + resolver: &corev3EntityStateExtImpl{}, + in: corev3.FixtureEntityState("test"), + want: "srn:core/v3.EntityState:default:test", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(fmt.Sprintf("%T/%s", tt.resolver, tt.name), func(t *testing.T) { + params := graphql.ResolveParams{Context: context.Background(), Source: tt.in} + got, err := tt.resolver.ID(params) + if (err != nil) != tt.wantErr { + t.Errorf("%s.ID() error = %v, wantErr %v", tt.name, err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("%s.ID() = %v, want %v", tt.name, got, tt.want) + } + }) + } +} + +func Test_corev3_ToJSON(t *testing.T) { + tests := []struct { + name string + resolver interface { + ToJSON(p graphql.ResolveParams) (interface{}, error) + } + in interface{} + want interface{} + wantErr bool + }{ + { + name: "corev3EntityConfigExtImpl", + resolver: &corev3EntityConfigExtImpl{}, + in: corev3.FixtureEntityConfig("name"), + want: util_api.WrapResource(corev3.FixtureEntityConfig("name")), + wantErr: false, + }, + { + name: "corev3EntityStateExtImpl", + resolver: &corev3EntityStateExtImpl{}, + in: corev3.FixtureEntityState("name"), + want: util_api.WrapResource(corev3.FixtureEntityState("name")), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(fmt.Sprintf("%T/%s", tt.resolver, tt.name), func(t *testing.T) { + got, err := tt.resolver.ToJSON(graphql.ResolveParams{Context: context.Background(), Source: tt.in}) + if (err != nil) != tt.wantErr { + t.Errorf("%s.ToJSON() error = %v, wantErr %v", tt.name, err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("%s.ToJSON() = %v, want %v", tt.name, got, tt.want) + } + }) + } +} + +func Test_corev3_IsTypeOf(t *testing.T) { + tests := []struct { + name string + resolver interface { + IsTypeOf(s interface{}, p graphql.IsTypeOfParams) bool + } + in interface{} + want bool + }{ + { + name: "entity_config/match", + resolver: &corev3EntityConfigImpl{}, + in: corev3.FixtureEntityConfig("name"), + want: true, + }, + { + name: "entity_config/no match", + resolver: &corev3EntityConfigImpl{}, + in: corev2.FixtureEntity("name"), + want: false, + }, + { + name: "entity_state/match", + resolver: &corev3EntityStateImpl{}, + in: corev3.FixtureEntityState("name"), + want: true, + }, + { + name: "entity_state/no match", + resolver: &corev3EntityStateImpl{}, + in: corev2.FixtureEntity("name"), + want: false, + }, + } + for _, tt := range tests { + t.Run(fmt.Sprintf("%T/%s", tt.resolver, tt.name), func(t *testing.T) { + got := tt.resolver.IsTypeOf(tt.in, graphql.IsTypeOfParams{Context: context.Background()}) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("%T.ToJSON() = %v, want %v", tt.resolver, got, tt.want) + } + }) + } +} + +func Test_corev3EntityConfigExtImpl_State(t *testing.T) { + tests := []struct { + name string + setup func(*MockGenericClient) + source interface{} + want interface{} + wantErr bool + }{ + { + name: "success", + setup: func(client *MockGenericClient) { + client.On("SetTypeMeta", mock.Anything).Return(nil) + client.On("Get", mock.Anything, "name", mock.Anything).Run(func(args mock.Arguments) { + arg := args.Get(2).(*corev3.V2ResourceProxy) + *arg = corev3.V2ResourceProxy{Resource: corev3.FixtureEntityConfig("name")} + }).Return(nil).Once() + }, + source: corev3.FixtureEntityConfig("name"), + want: corev3.FixtureEntityConfig("name"), + wantErr: false, + }, + { + name: "not found", + setup: func(client *MockGenericClient) { + client.On("SetTypeMeta", mock.Anything).Return(nil) + client.On("Get", mock.Anything, "name", mock.Anything).Return(&store.ErrNotFound{}).Once() + }, + source: corev3.FixtureEntityConfig("name"), + want: nil, + wantErr: false, + }, + { + name: "bad meta", + setup: func(client *MockGenericClient) { + client.On("SetTypeMeta", mock.Anything).Return(errors.New("unlikely")) + client.On("Get", mock.Anything, "name", mock.Anything).Return(&store.ErrNotFound{}).Once() + }, + source: corev3.FixtureEntityConfig("name"), + want: nil, + wantErr: true, + }, + { + name: "upstream err", + setup: func(client *MockGenericClient) { + client.On("SetTypeMeta", mock.Anything).Return(nil) + client.On("Get", mock.Anything, "name", mock.Anything).Return(errors.New("unlikely")).Once() + }, + source: corev3.FixtureEntityConfig("name"), + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + client := new(MockGenericClient) + tt.setup(client) + + impl := &corev3EntityConfigExtImpl{client: client} + got, err := impl.State(graphql.ResolveParams{ + Context: context.Background(), + Source: tt.source, + }) + if (err != nil) != tt.wantErr { + t.Errorf("corev3EntityConfigExtImpl.State() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("corev3EntityConfigExtImpl.State() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_corev3EntityStateExtImpl_State(t *testing.T) { + tests := []struct { + name string + setup func(*MockGenericClient) + source interface{} + want interface{} + wantErr bool + }{ + { + name: "success", + setup: func(client *MockGenericClient) { + client.On("SetTypeMeta", mock.Anything).Return(nil) + client.On("Get", mock.Anything, "name", mock.Anything).Run(func(args mock.Arguments) { + arg := args.Get(2).(*corev3.V2ResourceProxy) + *arg = corev3.V2ResourceProxy{Resource: corev3.FixtureEntityState("name")} + }).Return(nil).Once() + }, + source: corev3.FixtureEntityState("name"), + want: corev3.FixtureEntityState("name"), + wantErr: false, + }, + { + name: "not found", + setup: func(client *MockGenericClient) { + client.On("SetTypeMeta", mock.Anything).Return(nil) + client.On("Get", mock.Anything, "name", mock.Anything).Return(&store.ErrNotFound{}).Once() + }, + source: corev3.FixtureEntityState("name"), + want: nil, + wantErr: false, + }, + { + name: "bad meta", + setup: func(client *MockGenericClient) { + client.On("SetTypeMeta", mock.Anything).Return(errors.New("unlikely")) + client.On("Get", mock.Anything, "name", mock.Anything).Return(&store.ErrNotFound{}).Once() + }, + source: corev3.FixtureEntityState("name"), + want: nil, + wantErr: true, + }, + { + name: "upstream err", + setup: func(client *MockGenericClient) { + client.On("SetTypeMeta", mock.Anything).Return(nil) + client.On("Get", mock.Anything, "name", mock.Anything).Return(errors.New("unlikely")).Once() + }, + source: corev3.FixtureEntityState("name"), + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + client := new(MockGenericClient) + tt.setup(client) + + impl := &corev3EntityStateExtImpl{client: client} + got, err := impl.Config(graphql.ResolveParams{ + Context: context.Background(), + Source: tt.source, + }) + if (err != nil) != tt.wantErr { + t.Errorf("corev3EntityStateExtImpl.Config() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("corev3EntityStateExtImpl.Config() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_corev3EntityStateExtImpl_ToCoreV2Entity(t *testing.T) { + tests := []struct { + name string + setup func(*MockEntityClient) + source interface{} + want interface{} + wantErr bool + }{ + { + name: "success", + setup: func(client *MockEntityClient) { + client.On("FetchEntity", mock.Anything, "name"). + Return(corev2.FixtureEntity("name"), nil). + Once() + }, + source: corev3.FixtureEntityState("name"), + want: corev2.FixtureEntity("name"), + wantErr: false, + }, + { + name: "upstream err", + setup: func(client *MockEntityClient) { + client.On("FetchEntity", mock.Anything, "name"). + Return(corev2.FixtureEntity("name"), errors.New("unlikely")). + Once() + }, + source: corev3.FixtureEntityState("name"), + want: corev2.FixtureEntity("name"), + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + client := new(MockEntityClient) + tt.setup(client) + + impl := &corev3EntityStateExtImpl{entityClient: client} + got, err := impl.ToCoreV2Entity(graphql.ResolveParams{ + Context: context.Background(), + Source: tt.source, + }) + if (err != nil) != tt.wantErr { + t.Errorf("corev3EntityStateExtImpl.ToCoreV2Entity() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("corev3EntityStateExtImpl.ToCoreV2Entity() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_corev3EntityConfigExtImpl_ToCoreV2Entity(t *testing.T) { + tests := []struct { + name string + setup func(*MockEntityClient) + source interface{} + want interface{} + wantErr bool + }{ + { + name: "success", + setup: func(client *MockEntityClient) { + client.On("FetchEntity", mock.Anything, "name"). + Return(corev2.FixtureEntity("name"), nil). + Once() + }, + source: corev3.FixtureEntityConfig("name"), + want: corev2.FixtureEntity("name"), + wantErr: false, + }, + { + name: "upstream err", + setup: func(client *MockEntityClient) { + client.On("FetchEntity", mock.Anything, "name"). + Return(corev2.FixtureEntity("name"), errors.New("unlikely")). + Once() + }, + source: corev3.FixtureEntityConfig("name"), + want: corev2.FixtureEntity("name"), + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + client := new(MockEntityClient) + tt.setup(client) + + impl := &corev3EntityConfigExtImpl{entityClient: client} + got, err := impl.ToCoreV2Entity(graphql.ResolveParams{ + Context: context.Background(), + Source: tt.source, + }) + if (err != nil) != tt.wantErr { + t.Errorf("corev3EntityConfigExtImpl.ToCoreV2Entity() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("corev3EntityConfigExtImpl.ToCoreV2Entity() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/backend/apid/graphql/globalid/util.go b/backend/apid/graphql/globalid/util.go index 5a39f16882..49f027c8a3 100644 --- a/backend/apid/graphql/globalid/util.go +++ b/backend/apid/graphql/globalid/util.go @@ -93,3 +93,73 @@ func standardEncoder(name string, fNames ...string) encoderFunc { return components } } + +type tmGetter interface { + GetTypeMeta() types.TypeMeta +} + +type namedResource interface { + RBACName() string +} + +// NewGenericTranslator creates a compatible translator for a given corev2 or +// corev3 resource. +func NewGenericTranslator(kind namedResource, name string) Translator { + return &genericTranslator{kind: kind, name: name} +} + +type genericTranslator struct { + kind interface{} + name string + _kindVal *reflect.Value +} + +func (g *genericTranslator) kindVal() *reflect.Value { + if g._kindVal == nil { + val := reflect.ValueOf(g.kind) + g._kindVal = &val + } + return g._kindVal +} + +// Returns the rbac name for the given resource +func (g *genericTranslator) ForResourceNamed() string { + if g.name != "" { + return g.name + } + tm := types.TypeMeta{} + if getter, ok := g.kind.(tmGetter); ok { + tm = getter.GetTypeMeta() + } else { + typ := reflect.Indirect(reflect.ValueOf(g.kind)).Type() + tm = types.TypeMeta{ + Type: typ.Name(), + APIVersion: types.ApiVersion(typ.PkgPath()), + } + } + g.name = tm.APIVersion + "." + tm.Type + return g.name +} + +// IsResponsible returns true if the given resource matches this translator +func (g *genericTranslator) IsResponsible(r interface{}) bool { + return g.kindVal().Type().String() == reflect.ValueOf(r).Type().String() +} + +// Encode produces id components for a given resource +func (g *genericTranslator) Encode(ctx context.Context, r interface{}) Components { + name := g.ForResourceNamed() + cmp := Encode(ctx, r) + cmp.SetResource(name) + return cmp +} + +// EncodeToString returns a globalid for the given resource +func (g *genericTranslator) EncodeToString(ctx context.Context, r interface{}) string { + return g.Encode(ctx, r).String() +} + +// Decodes the given globalid into components +func (g *genericTranslator) Decode(cmp StandardComponents) Components { + return &cmp +} diff --git a/backend/apid/graphql/globalid/util_test.go b/backend/apid/graphql/globalid/util_test.go index b361a5d734..a8c7abffea 100644 --- a/backend/apid/graphql/globalid/util_test.go +++ b/backend/apid/graphql/globalid/util_test.go @@ -4,6 +4,8 @@ import ( "context" "testing" + corev2 "github.com/sensu/sensu-go/api/core/v2" + corev3 "github.com/sensu/sensu-go/api/core/v3" "github.com/sensu/sensu-go/types" "github.com/stretchr/testify/assert" ) @@ -20,3 +22,133 @@ func TestStandardDecoder(t *testing.T) { assert.Equal("default", components.Namespace()) assert.Equal("myHandler", components.UniqueComponent()) } + +func Test_GenericTranslator_ForResourceNamed(t *testing.T) { + type fields struct { + kind namedResource + name string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "implicit name", + fields: fields{ + kind: &corev3.EntityConfig{}, + }, + want: "core/v3.EntityConfig", + }, + { + name: "explicit name", + fields: fields{ + kind: &corev3.EntityConfig{}, + name: "custom_entity_config", + }, + want: "custom_entity_config", + }, + { + name: "implicit name AND doesn't implement typemeta interface", + fields: fields{ + kind: &corev2.CheckConfig{}, + }, + want: "core/v2.CheckConfig", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewGenericTranslator(tt.fields.kind, tt.fields.name) + if got := g.ForResourceNamed(); got != tt.want { + t.Errorf("genericTranslator.ForResourceNamed() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_GenericTranslator_IsResponsibleFor(t *testing.T) { + type fields struct { + kind namedResource + name string + } + tests := []struct { + name string + fields fields + arg interface{} + want bool + }{ + { + name: "IS responsible", + fields: fields{ + kind: &corev3.EntityConfig{}, + }, + arg: corev3.FixtureEntityConfig("test"), + want: true, + }, + { + name: "is NOT responsible", + fields: fields{ + kind: &corev3.EntityConfig{}, + }, + arg: corev3.FixtureEntityState("test"), + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewGenericTranslator(tt.fields.kind, tt.fields.name) + if got := g.IsResponsible(tt.arg); got != tt.want { + t.Errorf("genericTranslator.IsResponsible() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_GenericTranslator_EncodeToString(t *testing.T) { + type fields struct { + kind namedResource + name string + } + type args struct { + ctx context.Context + in interface{} + } + tests := []struct { + name string + fields fields + args args + want string + }{ + { + name: "implicit name", + fields: fields{ + kind: &corev3.EntityConfig{}, + }, + args: args{ + ctx: context.Background(), + in: corev3.FixtureEntityState("test"), + }, + want: "srn:core/v3.EntityConfig:default:test", + }, + { + name: "implicit name", + fields: fields{ + kind: &corev3.EntityConfig{}, + name: "custom-name", + }, + args: args{ + ctx: context.Background(), + in: corev3.FixtureEntityState("test"), + }, + want: "srn:custom-name:default:test", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewGenericTranslator(tt.fields.kind, tt.fields.name) + if got := g.EncodeToString(tt.args.ctx, tt.args.in); got != tt.want { + t.Errorf("genericTranslator.EncodeToString() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/backend/apid/graphql/mock_test.go b/backend/apid/graphql/mock_test.go index fc08475d9f..357a8c7b6b 100644 --- a/backend/apid/graphql/mock_test.go +++ b/backend/apid/graphql/mock_test.go @@ -133,6 +133,9 @@ func (c *MockEntityClient) UpdateEntity(ctx context.Context, entity *corev2.Enti func (c *MockEntityClient) FetchEntity(ctx context.Context, name string) (*corev2.Entity, error) { args := c.Called(ctx, name) + if args.Get(0) == nil { + return nil, args.Error(1) + } return args.Get(0).(*corev2.Entity), args.Error(1) } diff --git a/backend/apid/graphql/node.go b/backend/apid/graphql/node.go index 303dd9521a..a35973e324 100644 --- a/backend/apid/graphql/node.go +++ b/backend/apid/graphql/node.go @@ -27,6 +27,22 @@ func registerNodeResolvers(register relay.NodeRegister, cfg ServiceConfig) { registerRoleBindingNodeResolver(register, cfg.RBACClient) registerUserNodeResolver(register, cfg.UserClient) registerSilencedNodeResolver(register, cfg.SilencedClient) + register.RegisterResolver(relay.NodeResolver{ + Translator: GlobalIDCoreV3EntityConfig, + ObjectType: schema.CoreV3EntityConfigType, + Resolve: util_relay.MakeNodeResolver( + cfg.GenericClient, + corev2.TypeMeta{Type: "EntityConfig", APIVersion: "core/v3"}, + ), + }) + register.RegisterResolver(relay.NodeResolver{ + Translator: GlobalIDCoreV3EntityState, + ObjectType: schema.CoreV3EntityStateType, + Resolve: util_relay.MakeNodeResolver( + cfg.GenericClient, + corev2.TypeMeta{Type: "EntityState", APIVersion: "core/v3"}, + ), + }) } // assets diff --git a/backend/apid/graphql/schema/corev2.gen.gql.go b/backend/apid/graphql/schema/corev2.gen.gql.go index 76486e2775..1108faa126 100644 --- a/backend/apid/graphql/schema/corev2.gen.gql.go +++ b/backend/apid/graphql/schema/corev2.gen.gql.go @@ -398,6 +398,292 @@ var _ObjectTypeCoreV2ClusterRoleBindingDesc = graphql.ObjectDesc{ }, } +// +// CoreV2DeregistrationFieldResolvers represents a collection of methods whose products represent the +// response values of the 'CoreV2Deregistration' type. +type CoreV2DeregistrationFieldResolvers interface { + // Handler implements response to request for 'handler' field. + Handler(p graphql.ResolveParams) (string, error) +} + +// CoreV2DeregistrationAliases implements all methods on CoreV2DeregistrationFieldResolvers interface by using reflection to +// match name of field to a field on the given value. Intent is reduce friction +// of writing new resolvers by removing all the instances where you would simply +// have the resolvers method return a field. +type CoreV2DeregistrationAliases struct{} + +// Handler implements response to request for 'handler' field. +func (_ CoreV2DeregistrationAliases) Handler(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'handler'") + } + return ret, err +} + +// CoreV2DeregistrationType Deregistration contains configuration for Sensu entity de-registration. +var CoreV2DeregistrationType = graphql.NewType("CoreV2Deregistration", graphql.ObjectKind) + +// RegisterCoreV2Deregistration registers CoreV2Deregistration object type with given service. +func RegisterCoreV2Deregistration(svc *graphql.Service, impl CoreV2DeregistrationFieldResolvers) { + svc.RegisterObject(_ObjectTypeCoreV2DeregistrationDesc, impl) +} +func _ObjTypeCoreV2DeregistrationHandlerHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Handler(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Handler(frp) + } +} + +func _ObjectTypeCoreV2DeregistrationConfigFn() graphql1.ObjectConfig { + return graphql1.ObjectConfig{ + Description: "Deregistration contains configuration for Sensu entity de-registration.", + Fields: graphql1.Fields{"handler": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "handler", + Type: graphql1.NewNonNull(graphql1.String), + }}, + Interfaces: []*graphql1.Interface{}, + IsTypeOf: func(_ graphql1.IsTypeOfParams) bool { + // NOTE: + // Panic by default. Intent is that when Service is invoked, values of + // these fields are updated with instantiated resolvers. If these + // defaults are called it is most certainly programmer err. + // If you're see this comment then: 'Whoops! Sorry, my bad.' + panic("Unimplemented; see CoreV2DeregistrationFieldResolvers.") + }, + Name: "CoreV2Deregistration", + } +} + +// describe CoreV2Deregistration's configuration; kept private to avoid unintentional tampering of configuration at runtime. +var _ObjectTypeCoreV2DeregistrationDesc = graphql.ObjectDesc{ + Config: _ObjectTypeCoreV2DeregistrationConfigFn, + FieldHandlers: map[string]graphql.FieldHandler{"handler": _ObjTypeCoreV2DeregistrationHandlerHandler}, +} + +// +// CoreV2NetworkFieldResolvers represents a collection of methods whose products represent the +// response values of the 'CoreV2Network' type. +type CoreV2NetworkFieldResolvers interface { + // Interfaces implements response to request for 'interfaces' field. + Interfaces(p graphql.ResolveParams) (interface{}, error) +} + +// CoreV2NetworkAliases implements all methods on CoreV2NetworkFieldResolvers interface by using reflection to +// match name of field to a field on the given value. Intent is reduce friction +// of writing new resolvers by removing all the instances where you would simply +// have the resolvers method return a field. +type CoreV2NetworkAliases struct{} + +// Interfaces implements response to request for 'interfaces' field. +func (_ CoreV2NetworkAliases) Interfaces(p graphql.ResolveParams) (interface{}, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + return val, err +} + +/* +CoreV2NetworkType Network contains information about the system network interfaces +that the Agent process is running on, used for additional Entity +context. +*/ +var CoreV2NetworkType = graphql.NewType("CoreV2Network", graphql.ObjectKind) + +// RegisterCoreV2Network registers CoreV2Network object type with given service. +func RegisterCoreV2Network(svc *graphql.Service, impl CoreV2NetworkFieldResolvers) { + svc.RegisterObject(_ObjectTypeCoreV2NetworkDesc, impl) +} +func _ObjTypeCoreV2NetworkInterfacesHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Interfaces(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Interfaces(frp) + } +} + +func _ObjectTypeCoreV2NetworkConfigFn() graphql1.ObjectConfig { + return graphql1.ObjectConfig{ + Description: "Network contains information about the system network interfaces\nthat the Agent process is running on, used for additional Entity\ncontext.", + Fields: graphql1.Fields{"interfaces": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "interfaces", + Type: graphql1.NewNonNull(graphql1.NewList(graphql1.NewNonNull(graphql.OutputType("CoreV2NetworkInterface")))), + }}, + Interfaces: []*graphql1.Interface{}, + IsTypeOf: func(_ graphql1.IsTypeOfParams) bool { + // NOTE: + // Panic by default. Intent is that when Service is invoked, values of + // these fields are updated with instantiated resolvers. If these + // defaults are called it is most certainly programmer err. + // If you're see this comment then: 'Whoops! Sorry, my bad.' + panic("Unimplemented; see CoreV2NetworkFieldResolvers.") + }, + Name: "CoreV2Network", + } +} + +// describe CoreV2Network's configuration; kept private to avoid unintentional tampering of configuration at runtime. +var _ObjectTypeCoreV2NetworkDesc = graphql.ObjectDesc{ + Config: _ObjectTypeCoreV2NetworkConfigFn, + FieldHandlers: map[string]graphql.FieldHandler{"interfaces": _ObjTypeCoreV2NetworkInterfacesHandler}, +} + +// +// CoreV2NetworkInterfaceFieldResolvers represents a collection of methods whose products represent the +// response values of the 'CoreV2NetworkInterface' type. +type CoreV2NetworkInterfaceFieldResolvers interface { + // Name implements response to request for 'name' field. + Name(p graphql.ResolveParams) (string, error) + + // Mac implements response to request for 'mac' field. + Mac(p graphql.ResolveParams) (string, error) + + // Addresses implements response to request for 'addresses' field. + Addresses(p graphql.ResolveParams) ([]string, error) +} + +// CoreV2NetworkInterfaceAliases implements all methods on CoreV2NetworkInterfaceFieldResolvers interface by using reflection to +// match name of field to a field on the given value. Intent is reduce friction +// of writing new resolvers by removing all the instances where you would simply +// have the resolvers method return a field. +type CoreV2NetworkInterfaceAliases struct{} + +// Name implements response to request for 'name' field. +func (_ CoreV2NetworkInterfaceAliases) Name(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'name'") + } + return ret, err +} + +// Mac implements response to request for 'mac' field. +func (_ CoreV2NetworkInterfaceAliases) Mac(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'mac'") + } + return ret, err +} + +// Addresses implements response to request for 'addresses' field. +func (_ CoreV2NetworkInterfaceAliases) Addresses(p graphql.ResolveParams) ([]string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.([]string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'addresses'") + } + return ret, err +} + +/* +CoreV2NetworkInterfaceType NetworkInterface contains information about a system network +interface. +*/ +var CoreV2NetworkInterfaceType = graphql.NewType("CoreV2NetworkInterface", graphql.ObjectKind) + +// RegisterCoreV2NetworkInterface registers CoreV2NetworkInterface object type with given service. +func RegisterCoreV2NetworkInterface(svc *graphql.Service, impl CoreV2NetworkInterfaceFieldResolvers) { + svc.RegisterObject(_ObjectTypeCoreV2NetworkInterfaceDesc, impl) +} +func _ObjTypeCoreV2NetworkInterfaceNameHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Name(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Name(frp) + } +} + +func _ObjTypeCoreV2NetworkInterfaceMacHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Mac(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Mac(frp) + } +} + +func _ObjTypeCoreV2NetworkInterfaceAddressesHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Addresses(p graphql.ResolveParams) ([]string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Addresses(frp) + } +} + +func _ObjectTypeCoreV2NetworkInterfaceConfigFn() graphql1.ObjectConfig { + return graphql1.ObjectConfig{ + Description: "NetworkInterface contains information about a system network\ninterface.", + Fields: graphql1.Fields{ + "addresses": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "addresses", + Type: graphql1.NewNonNull(graphql1.NewList(graphql1.NewNonNull(graphql1.String))), + }, + "mac": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "mac", + Type: graphql1.NewNonNull(graphql1.String), + }, + "name": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "name", + Type: graphql1.NewNonNull(graphql1.String), + }, + }, + Interfaces: []*graphql1.Interface{}, + IsTypeOf: func(_ graphql1.IsTypeOfParams) bool { + // NOTE: + // Panic by default. Intent is that when Service is invoked, values of + // these fields are updated with instantiated resolvers. If these + // defaults are called it is most certainly programmer err. + // If you're see this comment then: 'Whoops! Sorry, my bad.' + panic("Unimplemented; see CoreV2NetworkInterfaceFieldResolvers.") + }, + Name: "CoreV2NetworkInterface", + } +} + +// describe CoreV2NetworkInterface's configuration; kept private to avoid unintentional tampering of configuration at runtime. +var _ObjectTypeCoreV2NetworkInterfaceDesc = graphql.ObjectDesc{ + Config: _ObjectTypeCoreV2NetworkInterfaceConfigFn, + FieldHandlers: map[string]graphql.FieldHandler{ + "addresses": _ObjTypeCoreV2NetworkInterfaceAddressesHandler, + "mac": _ObjTypeCoreV2NetworkInterfaceMacHandler, + "name": _ObjTypeCoreV2NetworkInterfaceNameHandler, + }, +} + // // CoreV2PipelineFieldResolvers represents a collection of methods whose products represent the // response values of the 'CoreV2Pipeline' type. @@ -650,6 +936,78 @@ var _ObjectTypeCoreV2PipelineWorkflowDesc = graphql.ObjectDesc{ }, } +// +// CoreV2ProcessFieldResolvers represents a collection of methods whose products represent the +// response values of the 'CoreV2Process' type. +type CoreV2ProcessFieldResolvers interface { + // Name implements response to request for 'name' field. + Name(p graphql.ResolveParams) (string, error) +} + +// CoreV2ProcessAliases implements all methods on CoreV2ProcessFieldResolvers interface by using reflection to +// match name of field to a field on the given value. Intent is reduce friction +// of writing new resolvers by removing all the instances where you would simply +// have the resolvers method return a field. +type CoreV2ProcessAliases struct{} + +// Name implements response to request for 'name' field. +func (_ CoreV2ProcessAliases) Name(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'name'") + } + return ret, err +} + +// CoreV2ProcessType Process contains information about a local process. +var CoreV2ProcessType = graphql.NewType("CoreV2Process", graphql.ObjectKind) + +// RegisterCoreV2Process registers CoreV2Process object type with given service. +func RegisterCoreV2Process(svc *graphql.Service, impl CoreV2ProcessFieldResolvers) { + svc.RegisterObject(_ObjectTypeCoreV2ProcessDesc, impl) +} +func _ObjTypeCoreV2ProcessNameHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Name(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Name(frp) + } +} + +func _ObjectTypeCoreV2ProcessConfigFn() graphql1.ObjectConfig { + return graphql1.ObjectConfig{ + Description: "Process contains information about a local process.", + Fields: graphql1.Fields{"name": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "name", + Type: graphql1.NewNonNull(graphql1.String), + }}, + Interfaces: []*graphql1.Interface{}, + IsTypeOf: func(_ graphql1.IsTypeOfParams) bool { + // NOTE: + // Panic by default. Intent is that when Service is invoked, values of + // these fields are updated with instantiated resolvers. If these + // defaults are called it is most certainly programmer err. + // If you're see this comment then: 'Whoops! Sorry, my bad.' + panic("Unimplemented; see CoreV2ProcessFieldResolvers.") + }, + Name: "CoreV2Process", + } +} + +// describe CoreV2Process's configuration; kept private to avoid unintentional tampering of configuration at runtime. +var _ObjectTypeCoreV2ProcessDesc = graphql.ObjectDesc{ + Config: _ObjectTypeCoreV2ProcessConfigFn, + FieldHandlers: map[string]graphql.FieldHandler{"name": _ObjTypeCoreV2ProcessNameHandler}, +} + // // CoreV2ResourceReferenceFieldResolvers represents a collection of methods whose products represent the // response values of the 'CoreV2ResourceReference' type. @@ -1479,3 +1837,497 @@ var _ObjectTypeCoreV2SubjectDesc = graphql.ObjectDesc{ "type": _ObjTypeCoreV2SubjectTypeHandler, }, } + +// +// CoreV2SystemFieldResolvers represents a collection of methods whose products represent the +// response values of the 'CoreV2System' type. +type CoreV2SystemFieldResolvers interface { + // Hostname implements response to request for 'hostname' field. + Hostname(p graphql.ResolveParams) (string, error) + + // Os implements response to request for 'os' field. + Os(p graphql.ResolveParams) (string, error) + + // Platform implements response to request for 'platform' field. + Platform(p graphql.ResolveParams) (string, error) + + // Platform_family implements response to request for 'platform_family' field. + Platform_family(p graphql.ResolveParams) (string, error) + + // Platform_version implements response to request for 'platform_version' field. + Platform_version(p graphql.ResolveParams) (string, error) + + // Network implements response to request for 'network' field. + Network(p graphql.ResolveParams) (interface{}, error) + + // Arch implements response to request for 'arch' field. + Arch(p graphql.ResolveParams) (string, error) + + // Arm_version implements response to request for 'arm_version' field. + Arm_version(p graphql.ResolveParams) (int, error) + + // Libc_type implements response to request for 'libc_type' field. + Libc_type(p graphql.ResolveParams) (string, error) + + // Vm_system implements response to request for 'vm_system' field. + Vm_system(p graphql.ResolveParams) (string, error) + + // Vm_role implements response to request for 'vm_role' field. + Vm_role(p graphql.ResolveParams) (string, error) + + // Cloud_provider implements response to request for 'cloud_provider' field. + Cloud_provider(p graphql.ResolveParams) (string, error) + + // Float_type implements response to request for 'float_type' field. + Float_type(p graphql.ResolveParams) (string, error) + + // Processes implements response to request for 'processes' field. + Processes(p graphql.ResolveParams) (interface{}, error) +} + +// CoreV2SystemAliases implements all methods on CoreV2SystemFieldResolvers interface by using reflection to +// match name of field to a field on the given value. Intent is reduce friction +// of writing new resolvers by removing all the instances where you would simply +// have the resolvers method return a field. +type CoreV2SystemAliases struct{} + +// Hostname implements response to request for 'hostname' field. +func (_ CoreV2SystemAliases) Hostname(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'hostname'") + } + return ret, err +} + +// Os implements response to request for 'os' field. +func (_ CoreV2SystemAliases) Os(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'os'") + } + return ret, err +} + +// Platform implements response to request for 'platform' field. +func (_ CoreV2SystemAliases) Platform(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'platform'") + } + return ret, err +} + +// Platform_family implements response to request for 'platform_family' field. +func (_ CoreV2SystemAliases) Platform_family(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'platform_family'") + } + return ret, err +} + +// Platform_version implements response to request for 'platform_version' field. +func (_ CoreV2SystemAliases) Platform_version(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'platform_version'") + } + return ret, err +} + +// Network implements response to request for 'network' field. +func (_ CoreV2SystemAliases) Network(p graphql.ResolveParams) (interface{}, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + return val, err +} + +// Arch implements response to request for 'arch' field. +func (_ CoreV2SystemAliases) Arch(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'arch'") + } + return ret, err +} + +// Arm_version implements response to request for 'arm_version' field. +func (_ CoreV2SystemAliases) Arm_version(p graphql.ResolveParams) (int, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := graphql1.Int.ParseValue(val).(int) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'arm_version'") + } + return ret, err +} + +// Libc_type implements response to request for 'libc_type' field. +func (_ CoreV2SystemAliases) Libc_type(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'libc_type'") + } + return ret, err +} + +// Vm_system implements response to request for 'vm_system' field. +func (_ CoreV2SystemAliases) Vm_system(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'vm_system'") + } + return ret, err +} + +// Vm_role implements response to request for 'vm_role' field. +func (_ CoreV2SystemAliases) Vm_role(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'vm_role'") + } + return ret, err +} + +// Cloud_provider implements response to request for 'cloud_provider' field. +func (_ CoreV2SystemAliases) Cloud_provider(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'cloud_provider'") + } + return ret, err +} + +// Float_type implements response to request for 'float_type' field. +func (_ CoreV2SystemAliases) Float_type(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'float_type'") + } + return ret, err +} + +// Processes implements response to request for 'processes' field. +func (_ CoreV2SystemAliases) Processes(p graphql.ResolveParams) (interface{}, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + return val, err +} + +/* +CoreV2SystemType System contains information about the system that the Agent process +is running on, used for additional Entity context. +*/ +var CoreV2SystemType = graphql.NewType("CoreV2System", graphql.ObjectKind) + +// RegisterCoreV2System registers CoreV2System object type with given service. +func RegisterCoreV2System(svc *graphql.Service, impl CoreV2SystemFieldResolvers) { + svc.RegisterObject(_ObjectTypeCoreV2SystemDesc, impl) +} +func _ObjTypeCoreV2SystemHostnameHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Hostname(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Hostname(frp) + } +} + +func _ObjTypeCoreV2SystemOsHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Os(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Os(frp) + } +} + +func _ObjTypeCoreV2SystemPlatformHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Platform(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Platform(frp) + } +} + +func _ObjTypeCoreV2SystemPlatform_familyHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Platform_family(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Platform_family(frp) + } +} + +func _ObjTypeCoreV2SystemPlatform_versionHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Platform_version(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Platform_version(frp) + } +} + +func _ObjTypeCoreV2SystemNetworkHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Network(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Network(frp) + } +} + +func _ObjTypeCoreV2SystemArchHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Arch(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Arch(frp) + } +} + +func _ObjTypeCoreV2SystemArm_versionHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Arm_version(p graphql.ResolveParams) (int, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Arm_version(frp) + } +} + +func _ObjTypeCoreV2SystemLibc_typeHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Libc_type(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Libc_type(frp) + } +} + +func _ObjTypeCoreV2SystemVm_systemHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Vm_system(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Vm_system(frp) + } +} + +func _ObjTypeCoreV2SystemVm_roleHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Vm_role(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Vm_role(frp) + } +} + +func _ObjTypeCoreV2SystemCloud_providerHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Cloud_provider(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Cloud_provider(frp) + } +} + +func _ObjTypeCoreV2SystemFloat_typeHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Float_type(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Float_type(frp) + } +} + +func _ObjTypeCoreV2SystemProcessesHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Processes(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Processes(frp) + } +} + +func _ObjectTypeCoreV2SystemConfigFn() graphql1.ObjectConfig { + return graphql1.ObjectConfig{ + Description: "System contains information about the system that the Agent process\nis running on, used for additional Entity context.", + Fields: graphql1.Fields{ + "arch": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "arch", + Type: graphql1.NewNonNull(graphql1.String), + }, + "arm_version": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "arm_version", + Type: graphql1.NewNonNull(graphql1.Int), + }, + "cloud_provider": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "CloudProvider indicates the public cloud the agent is running on.", + Name: "cloud_provider", + Type: graphql1.NewNonNull(graphql1.String), + }, + "float_type": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "float_type", + Type: graphql1.NewNonNull(graphql1.String), + }, + "hostname": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "hostname", + Type: graphql1.NewNonNull(graphql1.String), + }, + "libc_type": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "LibCType indicates the type of libc the agent has access to (glibc, musl,\netc)", + Name: "libc_type", + Type: graphql1.NewNonNull(graphql1.String), + }, + "network": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "network", + Type: graphql1.NewNonNull(graphql.OutputType("CoreV2Network")), + }, + "os": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "os", + Type: graphql1.NewNonNull(graphql1.String), + }, + "platform": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "platform", + Type: graphql1.NewNonNull(graphql1.String), + }, + "platform_family": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "platform_family", + Type: graphql1.NewNonNull(graphql1.String), + }, + "platform_version": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "self descriptive", + Name: "platform_version", + Type: graphql1.NewNonNull(graphql1.String), + }, + "processes": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Processes contains information about the local processes on the agent.", + Name: "processes", + Type: graphql1.NewNonNull(graphql1.NewList(graphql.OutputType("CoreV2Process"))), + }, + "vm_role": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "VMRole indicates the VM role of the agent (host/guest)", + Name: "vm_role", + Type: graphql1.NewNonNull(graphql1.String), + }, + "vm_system": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "VMSystem indicates the VM system of the agent (kvm, vbox, etc)", + Name: "vm_system", + Type: graphql1.NewNonNull(graphql1.String), + }, + }, + Interfaces: []*graphql1.Interface{}, + IsTypeOf: func(_ graphql1.IsTypeOfParams) bool { + // NOTE: + // Panic by default. Intent is that when Service is invoked, values of + // these fields are updated with instantiated resolvers. If these + // defaults are called it is most certainly programmer err. + // If you're see this comment then: 'Whoops! Sorry, my bad.' + panic("Unimplemented; see CoreV2SystemFieldResolvers.") + }, + Name: "CoreV2System", + } +} + +// describe CoreV2System's configuration; kept private to avoid unintentional tampering of configuration at runtime. +var _ObjectTypeCoreV2SystemDesc = graphql.ObjectDesc{ + Config: _ObjectTypeCoreV2SystemConfigFn, + FieldHandlers: map[string]graphql.FieldHandler{ + "arch": _ObjTypeCoreV2SystemArchHandler, + "arm_version": _ObjTypeCoreV2SystemArm_versionHandler, + "cloud_provider": _ObjTypeCoreV2SystemCloud_providerHandler, + "float_type": _ObjTypeCoreV2SystemFloat_typeHandler, + "hostname": _ObjTypeCoreV2SystemHostnameHandler, + "libc_type": _ObjTypeCoreV2SystemLibc_typeHandler, + "network": _ObjTypeCoreV2SystemNetworkHandler, + "os": _ObjTypeCoreV2SystemOsHandler, + "platform": _ObjTypeCoreV2SystemPlatformHandler, + "platform_family": _ObjTypeCoreV2SystemPlatform_familyHandler, + "platform_version": _ObjTypeCoreV2SystemPlatform_versionHandler, + "processes": _ObjTypeCoreV2SystemProcessesHandler, + "vm_role": _ObjTypeCoreV2SystemVm_roleHandler, + "vm_system": _ObjTypeCoreV2SystemVm_systemHandler, + }, +} diff --git a/backend/apid/graphql/schema/corev2.gen.graphql b/backend/apid/graphql/schema/corev2.gen.graphql index 5e861f81c5..0e12727f17 100644 --- a/backend/apid/graphql/schema/corev2.gen.graphql +++ b/backend/apid/graphql/schema/corev2.gen.graphql @@ -50,6 +50,30 @@ type CoreV2ClusterRoleBinding { metadata: ObjectMeta! } +"""Deregistration contains configuration for Sensu entity de-registration.""" +type CoreV2Deregistration { + handler: String! +} + +""" +Network contains information about the system network interfaces +that the Agent process is running on, used for additional Entity +context. +""" +type CoreV2Network { + interfaces: [CoreV2NetworkInterface!]! +} + +""" +NetworkInterface contains information about a system network +interface. +""" +type CoreV2NetworkInterface { + name: String! + mac: String! + addresses: [String!]! +} + """Pipeline represents a named collection of pipeline workflows.""" type CoreV2Pipeline { @@ -85,6 +109,11 @@ type CoreV2PipelineWorkflow { handler: CoreV2ResourceReference } +"""Process contains information about a local process.""" +type CoreV2Process { + name: String! +} + """ResourceReference represents a reference to another resource.""" type CoreV2ResourceReference { @@ -175,3 +204,37 @@ type CoreV2Subject { """Name of the referenced object""" name: String! } + +""" +System contains information about the system that the Agent process +is running on, used for additional Entity context. +""" +type CoreV2System { + hostname: String! + os: String! + platform: String! + platform_family: String! + platform_version: String! + network: CoreV2Network! + arch: String! + arm_version: Int! + + """ + LibCType indicates the type of libc the agent has access to (glibc, musl, + etc) + """ + libc_type: String! + + """VMSystem indicates the VM system of the agent (kvm, vbox, etc)""" + vm_system: String! + + """VMRole indicates the VM role of the agent (host/guest)""" + vm_role: String! + + """CloudProvider indicates the public cloud the agent is running on.""" + cloud_provider: String! + float_type: String! + + """Processes contains information about the local processes on the agent.""" + processes: [CoreV2Process]! +} diff --git a/backend/apid/graphql/schema/corev3.gen.gql.go b/backend/apid/graphql/schema/corev3.gen.gql.go new file mode 100644 index 0000000000..929e4b12c5 --- /dev/null +++ b/backend/apid/graphql/schema/corev3.gen.gql.go @@ -0,0 +1,467 @@ +// Code generated by scripts/gengraphql.go. DO NOT EDIT. + +package schema + +import ( + errors "errors" + graphql1 "github.com/graphql-go/graphql" + graphql "github.com/sensu/sensu-go/graphql" +) + +// +// CoreV3EntityConfigFieldResolvers represents a collection of methods whose products represent the +// response values of the 'CoreV3EntityConfig' type. +type CoreV3EntityConfigFieldResolvers interface { + // Metadata implements response to request for 'metadata' field. + Metadata(p graphql.ResolveParams) (interface{}, error) + + // Entity_class implements response to request for 'entity_class' field. + Entity_class(p graphql.ResolveParams) (string, error) + + // User implements response to request for 'user' field. + User(p graphql.ResolveParams) (string, error) + + // Subscriptions implements response to request for 'subscriptions' field. + Subscriptions(p graphql.ResolveParams) ([]string, error) + + // Deregister implements response to request for 'deregister' field. + Deregister(p graphql.ResolveParams) (bool, error) + + // Deregistration implements response to request for 'deregistration' field. + Deregistration(p graphql.ResolveParams) (interface{}, error) + + // Keepalive_handlers implements response to request for 'keepalive_handlers' field. + Keepalive_handlers(p graphql.ResolveParams) ([]string, error) + + // Redact implements response to request for 'redact' field. + Redact(p graphql.ResolveParams) ([]string, error) +} + +// CoreV3EntityConfigAliases implements all methods on CoreV3EntityConfigFieldResolvers interface by using reflection to +// match name of field to a field on the given value. Intent is reduce friction +// of writing new resolvers by removing all the instances where you would simply +// have the resolvers method return a field. +type CoreV3EntityConfigAliases struct{} + +// Metadata implements response to request for 'metadata' field. +func (_ CoreV3EntityConfigAliases) Metadata(p graphql.ResolveParams) (interface{}, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + return val, err +} + +// Entity_class implements response to request for 'entity_class' field. +func (_ CoreV3EntityConfigAliases) Entity_class(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'entity_class'") + } + return ret, err +} + +// User implements response to request for 'user' field. +func (_ CoreV3EntityConfigAliases) User(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'user'") + } + return ret, err +} + +// Subscriptions implements response to request for 'subscriptions' field. +func (_ CoreV3EntityConfigAliases) Subscriptions(p graphql.ResolveParams) ([]string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.([]string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'subscriptions'") + } + return ret, err +} + +// Deregister implements response to request for 'deregister' field. +func (_ CoreV3EntityConfigAliases) Deregister(p graphql.ResolveParams) (bool, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(bool) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'deregister'") + } + return ret, err +} + +// Deregistration implements response to request for 'deregistration' field. +func (_ CoreV3EntityConfigAliases) Deregistration(p graphql.ResolveParams) (interface{}, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + return val, err +} + +// Keepalive_handlers implements response to request for 'keepalive_handlers' field. +func (_ CoreV3EntityConfigAliases) Keepalive_handlers(p graphql.ResolveParams) ([]string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.([]string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'keepalive_handlers'") + } + return ret, err +} + +// Redact implements response to request for 'redact' field. +func (_ CoreV3EntityConfigAliases) Redact(p graphql.ResolveParams) ([]string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.([]string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'redact'") + } + return ret, err +} + +// CoreV3EntityConfigType EntityConfig represents entity configuration. +var CoreV3EntityConfigType = graphql.NewType("CoreV3EntityConfig", graphql.ObjectKind) + +// RegisterCoreV3EntityConfig registers CoreV3EntityConfig object type with given service. +func RegisterCoreV3EntityConfig(svc *graphql.Service, impl CoreV3EntityConfigFieldResolvers) { + svc.RegisterObject(_ObjectTypeCoreV3EntityConfigDesc, impl) +} +func _ObjTypeCoreV3EntityConfigMetadataHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Metadata(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Metadata(frp) + } +} + +func _ObjTypeCoreV3EntityConfigEntity_classHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Entity_class(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Entity_class(frp) + } +} + +func _ObjTypeCoreV3EntityConfigUserHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + User(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.User(frp) + } +} + +func _ObjTypeCoreV3EntityConfigSubscriptionsHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Subscriptions(p graphql.ResolveParams) ([]string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Subscriptions(frp) + } +} + +func _ObjTypeCoreV3EntityConfigDeregisterHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Deregister(p graphql.ResolveParams) (bool, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Deregister(frp) + } +} + +func _ObjTypeCoreV3EntityConfigDeregistrationHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Deregistration(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Deregistration(frp) + } +} + +func _ObjTypeCoreV3EntityConfigKeepalive_handlersHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Keepalive_handlers(p graphql.ResolveParams) ([]string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Keepalive_handlers(frp) + } +} + +func _ObjTypeCoreV3EntityConfigRedactHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Redact(p graphql.ResolveParams) ([]string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Redact(frp) + } +} + +func _ObjectTypeCoreV3EntityConfigConfigFn() graphql1.ObjectConfig { + return graphql1.ObjectConfig{ + Description: "EntityConfig represents entity configuration.", + Fields: graphql1.Fields{ + "deregister": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Deregister, if true, will result in the entity being deleted when the\nentity is an agent, and the agent disconnects its session.", + Name: "deregister", + Type: graphql1.NewNonNull(graphql1.Boolean), + }, + "deregistration": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Deregistration contains configuration for Sensu entity de-registration.", + Name: "deregistration", + Type: graphql1.NewNonNull(graphql.OutputType("CoreV2Deregistration")), + }, + "entity_class": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "EntityClass represents the class of the entity. It can be \"agent\",\n\"proxy\", or \"backend\".", + Name: "entity_class", + Type: graphql1.NewNonNull(graphql1.String), + }, + "keepalive_handlers": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "KeepaliveHandlers contains a list of handlers to use for the entity's\nkeepalive events.", + Name: "keepalive_handlers", + Type: graphql1.NewNonNull(graphql1.NewList(graphql1.NewNonNull(graphql1.String))), + }, + "metadata": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Metadata contains the name, namespace, labels and annotations of the\nentity.", + Name: "metadata", + Type: graphql.OutputType("ObjectMeta"), + }, + "redact": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Redact contains the fields to redact on the entity, if the entity is an]\nagent entity.", + Name: "redact", + Type: graphql1.NewNonNull(graphql1.NewList(graphql1.NewNonNull(graphql1.String))), + }, + "subscriptions": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Subscriptions are a weak relationship between entities and checks. The\nscheduler uses subscriptions to make entities to checks when scheduling.", + Name: "subscriptions", + Type: graphql1.NewNonNull(graphql1.NewList(graphql1.NewNonNull(graphql1.String))), + }, + "user": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "User is the username the entity is connecting as, if the entity is an\nagent entity.", + Name: "user", + Type: graphql1.NewNonNull(graphql1.String), + }, + }, + Interfaces: []*graphql1.Interface{}, + IsTypeOf: func(_ graphql1.IsTypeOfParams) bool { + // NOTE: + // Panic by default. Intent is that when Service is invoked, values of + // these fields are updated with instantiated resolvers. If these + // defaults are called it is most certainly programmer err. + // If you're see this comment then: 'Whoops! Sorry, my bad.' + panic("Unimplemented; see CoreV3EntityConfigFieldResolvers.") + }, + Name: "CoreV3EntityConfig", + } +} + +// describe CoreV3EntityConfig's configuration; kept private to avoid unintentional tampering of configuration at runtime. +var _ObjectTypeCoreV3EntityConfigDesc = graphql.ObjectDesc{ + Config: _ObjectTypeCoreV3EntityConfigConfigFn, + FieldHandlers: map[string]graphql.FieldHandler{ + "deregister": _ObjTypeCoreV3EntityConfigDeregisterHandler, + "deregistration": _ObjTypeCoreV3EntityConfigDeregistrationHandler, + "entity_class": _ObjTypeCoreV3EntityConfigEntity_classHandler, + "keepalive_handlers": _ObjTypeCoreV3EntityConfigKeepalive_handlersHandler, + "metadata": _ObjTypeCoreV3EntityConfigMetadataHandler, + "redact": _ObjTypeCoreV3EntityConfigRedactHandler, + "subscriptions": _ObjTypeCoreV3EntityConfigSubscriptionsHandler, + "user": _ObjTypeCoreV3EntityConfigUserHandler, + }, +} + +// +// CoreV3EntityStateFieldResolvers represents a collection of methods whose products represent the +// response values of the 'CoreV3EntityState' type. +type CoreV3EntityStateFieldResolvers interface { + // Metadata implements response to request for 'metadata' field. + Metadata(p graphql.ResolveParams) (interface{}, error) + + // System implements response to request for 'system' field. + System(p graphql.ResolveParams) (interface{}, error) + + // Last_seen implements response to request for 'last_seen' field. + Last_seen(p graphql.ResolveParams) (int, error) + + // Sensu_agent_version implements response to request for 'sensu_agent_version' field. + Sensu_agent_version(p graphql.ResolveParams) (string, error) +} + +// CoreV3EntityStateAliases implements all methods on CoreV3EntityStateFieldResolvers interface by using reflection to +// match name of field to a field on the given value. Intent is reduce friction +// of writing new resolvers by removing all the instances where you would simply +// have the resolvers method return a field. +type CoreV3EntityStateAliases struct{} + +// Metadata implements response to request for 'metadata' field. +func (_ CoreV3EntityStateAliases) Metadata(p graphql.ResolveParams) (interface{}, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + return val, err +} + +// System implements response to request for 'system' field. +func (_ CoreV3EntityStateAliases) System(p graphql.ResolveParams) (interface{}, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + return val, err +} + +// Last_seen implements response to request for 'last_seen' field. +func (_ CoreV3EntityStateAliases) Last_seen(p graphql.ResolveParams) (int, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := graphql1.Int.ParseValue(val).(int) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'last_seen'") + } + return ret, err +} + +// Sensu_agent_version implements response to request for 'sensu_agent_version' field. +func (_ CoreV3EntityStateAliases) Sensu_agent_version(p graphql.ResolveParams) (string, error) { + val, err := graphql.DefaultResolver(p.Source, p.Info.FieldName) + ret, ok := val.(string) + if err != nil { + return ret, err + } + if !ok { + return ret, errors.New("unable to coerce value for field 'sensu_agent_version'") + } + return ret, err +} + +/* +CoreV3EntityStateType EntityState represents entity state. Unlike configuration, state is +typically only maintained for agent entities, although it can be maintained +for proxy entities in certain circumstances. +*/ +var CoreV3EntityStateType = graphql.NewType("CoreV3EntityState", graphql.ObjectKind) + +// RegisterCoreV3EntityState registers CoreV3EntityState object type with given service. +func RegisterCoreV3EntityState(svc *graphql.Service, impl CoreV3EntityStateFieldResolvers) { + svc.RegisterObject(_ObjectTypeCoreV3EntityStateDesc, impl) +} +func _ObjTypeCoreV3EntityStateMetadataHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Metadata(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Metadata(frp) + } +} + +func _ObjTypeCoreV3EntityStateSystemHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + System(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.System(frp) + } +} + +func _ObjTypeCoreV3EntityStateLast_seenHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Last_seen(p graphql.ResolveParams) (int, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Last_seen(frp) + } +} + +func _ObjTypeCoreV3EntityStateSensu_agent_versionHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Sensu_agent_version(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Sensu_agent_version(frp) + } +} + +func _ObjectTypeCoreV3EntityStateConfigFn() graphql1.ObjectConfig { + return graphql1.ObjectConfig{ + Description: "EntityState represents entity state. Unlike configuration, state is\ntypically only maintained for agent entities, although it can be maintained\nfor proxy entities in certain circumstances.", + Fields: graphql1.Fields{ + "last_seen": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "LastSeen is a unix timestamp that represents when the entity was last\nobserved by the keepalive system.", + Name: "last_seen", + Type: graphql1.NewNonNull(graphql1.Int), + }, + "metadata": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Metadata contains the name, namespace, labels and annotations of the\nentity.", + Name: "metadata", + Type: graphql.OutputType("ObjectMeta"), + }, + "sensu_agent_version": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "SensuAgentVersion is the sensu-agent version.", + Name: "sensu_agent_version", + Type: graphql1.NewNonNull(graphql1.String), + }, + "system": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "System contains information about the system that the Agent process\nis running on, used for additional Entity context.", + Name: "system", + Type: graphql1.NewNonNull(graphql.OutputType("CoreV2System")), + }, + }, + Interfaces: []*graphql1.Interface{}, + IsTypeOf: func(_ graphql1.IsTypeOfParams) bool { + // NOTE: + // Panic by default. Intent is that when Service is invoked, values of + // these fields are updated with instantiated resolvers. If these + // defaults are called it is most certainly programmer err. + // If you're see this comment then: 'Whoops! Sorry, my bad.' + panic("Unimplemented; see CoreV3EntityStateFieldResolvers.") + }, + Name: "CoreV3EntityState", + } +} + +// describe CoreV3EntityState's configuration; kept private to avoid unintentional tampering of configuration at runtime. +var _ObjectTypeCoreV3EntityStateDesc = graphql.ObjectDesc{ + Config: _ObjectTypeCoreV3EntityStateConfigFn, + FieldHandlers: map[string]graphql.FieldHandler{ + "last_seen": _ObjTypeCoreV3EntityStateLast_seenHandler, + "metadata": _ObjTypeCoreV3EntityStateMetadataHandler, + "sensu_agent_version": _ObjTypeCoreV3EntityStateSensu_agent_versionHandler, + "system": _ObjTypeCoreV3EntityStateSystemHandler, + }, +} diff --git a/backend/apid/graphql/schema/corev3.gen.graphql b/backend/apid/graphql/schema/corev3.gen.graphql new file mode 100644 index 0000000000..8d0cfafdb9 --- /dev/null +++ b/backend/apid/graphql/schema/corev3.gen.graphql @@ -0,0 +1,79 @@ +# automatically generated file, do not edit! + +"""EntityConfig represents entity configuration.""" +type CoreV3EntityConfig { + + """ + Metadata contains the name, namespace, labels and annotations of the + entity. + """ + metadata: ObjectMeta + + """ + EntityClass represents the class of the entity. It can be "agent", + "proxy", or "backend". + """ + entity_class: String! + + """ + User is the username the entity is connecting as, if the entity is an + agent entity. + """ + user: String! + + """ + Subscriptions are a weak relationship between entities and checks. The + scheduler uses subscriptions to make entities to checks when scheduling. + """ + subscriptions: [String!]! + + """ + Deregister, if true, will result in the entity being deleted when the + entity is an agent, and the agent disconnects its session. + """ + deregister: Boolean! + + """Deregistration contains configuration for Sensu entity de-registration.""" + deregistration: CoreV2Deregistration! + + """ + KeepaliveHandlers contains a list of handlers to use for the entity's + keepalive events. + """ + keepalive_handlers: [String!]! + + """ + Redact contains the fields to redact on the entity, if the entity is an] + agent entity. + """ + redact: [String!]! +} + +""" +EntityState represents entity state. Unlike configuration, state is +typically only maintained for agent entities, although it can be maintained +for proxy entities in certain circumstances. +""" +type CoreV3EntityState { + + """ + Metadata contains the name, namespace, labels and annotations of the + entity. + """ + metadata: ObjectMeta + + """ + System contains information about the system that the Agent process + is running on, used for additional Entity context. + """ + system: CoreV2System! + + """ + LastSeen is a unix timestamp that represents when the entity was last + observed by the keepalive system. + """ + last_seen: Int! + + """SensuAgentVersion is the sensu-agent version.""" + sensu_agent_version: String! +} diff --git a/backend/apid/graphql/schema/corev3.gql.go b/backend/apid/graphql/schema/corev3.gql.go new file mode 100644 index 0000000000..d8e3fe2a4f --- /dev/null +++ b/backend/apid/graphql/schema/corev3.gql.go @@ -0,0 +1,226 @@ +// Code generated by scripts/gengraphql.go. DO NOT EDIT. + +package schema + +import ( + graphql1 "github.com/graphql-go/graphql" + graphql "github.com/sensu/sensu-go/graphql" +) + +// +// CoreV3EntityConfigExtensionOverridesFieldResolvers represents a collection of methods whose products represent the +// response values of the 'CoreV3EntityConfigExtensionOverrides' type. +type CoreV3EntityConfigExtensionOverridesFieldResolvers interface { + // ID implements response to request for 'id' field. + ID(p graphql.ResolveParams) (string, error) + + // ToJSON implements response to request for 'toJSON' field. + ToJSON(p graphql.ResolveParams) (interface{}, error) + + // State implements response to request for 'state' field. + State(p graphql.ResolveParams) (interface{}, error) + + // ToCoreV2Entity implements response to request for 'toCoreV2Entity' field. + ToCoreV2Entity(p graphql.ResolveParams) (interface{}, error) +} + +// RegisterCoreV3EntityConfigExtensionOverrides registers CoreV3EntityConfigExtensionOverrides object type with given service. +func RegisterCoreV3EntityConfigExtensionOverrides(svc *graphql.Service, impl CoreV3EntityConfigExtensionOverridesFieldResolvers) { + svc.RegisterObjectExtension(_ObjectExtensionTypeCoreV3EntityConfigExtensionOverridesDesc, impl) +} + +func _ObjTypeCoreV3EntityConfigExtensionOverridesIDHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + ID(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.ID(frp) + } +} + +func _ObjTypeCoreV3EntityConfigExtensionOverridesToJSONHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + ToJSON(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.ToJSON(frp) + } +} + +func _ObjTypeCoreV3EntityConfigExtensionOverridesStateHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + State(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.State(frp) + } +} + +func _ObjTypeCoreV3EntityConfigExtensionOverridesToCoreV2EntityHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + ToCoreV2Entity(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.ToCoreV2Entity(frp) + } +} + +func _ObjectExtensionTypeCoreV3EntityConfigExtensionOverridesConfigFn() graphql1.ObjectConfig { + return graphql1.ObjectConfig{ + Description: "", + Fields: graphql1.Fields{ + "id": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Unique global identifier used to reference resource.", + Name: "id", + Type: graphql1.NewNonNull(graphql1.ID), + }, + "state": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Corresponding entity state, if applicable.", + Name: "state", + Type: graphql.OutputType("CoreV3EntityState"), + }, + "toCoreV2Entity": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Represented as core/v2 Entity.", + Name: "toCoreV2Entity", + Type: graphql.OutputType("Entity"), + }, + "toJSON": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "toJSON returns a REST API compatible representation of the resource. Handy for\nsharing snippets that can then be imported with `sensuctl create`.", + Name: "toJSON", + Type: graphql1.NewNonNull(graphql.OutputType("JSON")), + }, + }, + Interfaces: []*graphql1.Interface{ + graphql.Interface("Node"), + graphql.Interface("Resource")}, + Name: "CoreV3EntityConfig", + } +} + +// describe CoreV3EntityConfigExtensionOverrides's configuration; kept private to avoid unintentional tampering of configuration at runtime. +var _ObjectExtensionTypeCoreV3EntityConfigExtensionOverridesDesc = graphql.ObjectDesc{ + Config: _ObjectExtensionTypeCoreV3EntityConfigExtensionOverridesConfigFn, + FieldHandlers: map[string]graphql.FieldHandler{ + "id": _ObjTypeCoreV3EntityConfigExtensionOverridesIDHandler, + "state": _ObjTypeCoreV3EntityConfigExtensionOverridesStateHandler, + "toCoreV2Entity": _ObjTypeCoreV3EntityConfigExtensionOverridesToCoreV2EntityHandler, + "toJSON": _ObjTypeCoreV3EntityConfigExtensionOverridesToJSONHandler, + }, +} + +// +// CoreV3EntityStateExtensionOverridesFieldResolvers represents a collection of methods whose products represent the +// response values of the 'CoreV3EntityStateExtensionOverrides' type. +type CoreV3EntityStateExtensionOverridesFieldResolvers interface { + // ID implements response to request for 'id' field. + ID(p graphql.ResolveParams) (string, error) + + // ToJSON implements response to request for 'toJSON' field. + ToJSON(p graphql.ResolveParams) (interface{}, error) + + // Config implements response to request for 'config' field. + Config(p graphql.ResolveParams) (interface{}, error) + + // ToCoreV2Entity implements response to request for 'toCoreV2Entity' field. + ToCoreV2Entity(p graphql.ResolveParams) (interface{}, error) +} + +// RegisterCoreV3EntityStateExtensionOverrides registers CoreV3EntityStateExtensionOverrides object type with given service. +func RegisterCoreV3EntityStateExtensionOverrides(svc *graphql.Service, impl CoreV3EntityStateExtensionOverridesFieldResolvers) { + svc.RegisterObjectExtension(_ObjectExtensionTypeCoreV3EntityStateExtensionOverridesDesc, impl) +} + +func _ObjTypeCoreV3EntityStateExtensionOverridesIDHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + ID(p graphql.ResolveParams) (string, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.ID(frp) + } +} + +func _ObjTypeCoreV3EntityStateExtensionOverridesToJSONHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + ToJSON(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.ToJSON(frp) + } +} + +func _ObjTypeCoreV3EntityStateExtensionOverridesConfigHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + Config(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.Config(frp) + } +} + +func _ObjTypeCoreV3EntityStateExtensionOverridesToCoreV2EntityHandler(impl interface{}) graphql1.FieldResolveFn { + resolver := impl.(interface { + ToCoreV2Entity(p graphql.ResolveParams) (interface{}, error) + }) + return func(frp graphql1.ResolveParams) (interface{}, error) { + return resolver.ToCoreV2Entity(frp) + } +} + +func _ObjectExtensionTypeCoreV3EntityStateExtensionOverridesConfigFn() graphql1.ObjectConfig { + return graphql1.ObjectConfig{ + Description: "", + Fields: graphql1.Fields{ + "config": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Corresponding entity config, if applicable.", + Name: "config", + Type: graphql.OutputType("CoreV3EntityConfig"), + }, + "id": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Unique global identifier used to reference resource.", + Name: "id", + Type: graphql1.NewNonNull(graphql1.ID), + }, + "toCoreV2Entity": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "Represented as core/v2 Entity.", + Name: "toCoreV2Entity", + Type: graphql.OutputType("Entity"), + }, + "toJSON": &graphql1.Field{ + Args: graphql1.FieldConfigArgument{}, + DeprecationReason: "", + Description: "toJSON returns a REST API compatible representation of the resource. Handy for\nsharing snippets that can then be imported with `sensuctl create`.", + Name: "toJSON", + Type: graphql1.NewNonNull(graphql.OutputType("JSON")), + }, + }, + Interfaces: []*graphql1.Interface{ + graphql.Interface("Node"), + graphql.Interface("Resource")}, + Name: "CoreV3EntityState", + } +} + +// describe CoreV3EntityStateExtensionOverrides's configuration; kept private to avoid unintentional tampering of configuration at runtime. +var _ObjectExtensionTypeCoreV3EntityStateExtensionOverridesDesc = graphql.ObjectDesc{ + Config: _ObjectExtensionTypeCoreV3EntityStateExtensionOverridesConfigFn, + FieldHandlers: map[string]graphql.FieldHandler{ + "config": _ObjTypeCoreV3EntityStateExtensionOverridesConfigHandler, + "id": _ObjTypeCoreV3EntityStateExtensionOverridesIDHandler, + "toCoreV2Entity": _ObjTypeCoreV3EntityStateExtensionOverridesToCoreV2EntityHandler, + "toJSON": _ObjTypeCoreV3EntityStateExtensionOverridesToJSONHandler, + }, +} diff --git a/backend/apid/graphql/schema/corev3.graphql b/backend/apid/graphql/schema/corev3.graphql new file mode 100644 index 0000000000..6b4c7df963 --- /dev/null +++ b/backend/apid/graphql/schema/corev3.graphql @@ -0,0 +1,41 @@ +extend type CoreV3EntityConfig implements Node & Resource @named(suffix: "Overrides") { + "Unique global identifier used to reference resource." + id: ID! + + """ + toJSON returns a REST API compatible representation of the resource. Handy for + sharing snippets that can then be imported with `sensuctl create`. + """ + toJSON: JSON! + + """ + Corresponding entity state, if applicable. + """ + state: CoreV3EntityState + + """ + Represented as core/v2 Entity. + """ + toCoreV2Entity: Entity +} + +extend type CoreV3EntityState implements Node & Resource @named(suffix: "Overrides") { + "Unique global identifier used to reference resource." + id: ID! + + """ + toJSON returns a REST API compatible representation of the resource. Handy for + sharing snippets that can then be imported with `sensuctl create`. + """ + toJSON: JSON! + + """ + Corresponding entity config, if applicable. + """ + config: CoreV3EntityConfig + + """ + Represented as core/v2 Entity. + """ + toCoreV2Entity: Entity +} diff --git a/backend/apid/graphql/schema/schema_gen.go b/backend/apid/graphql/schema/schema_gen.go index 9dbdb75431..f2367eec99 100644 --- a/backend/apid/graphql/schema/schema_gen.go +++ b/backend/apid/graphql/schema/schema_gen.go @@ -1,4 +1,5 @@ package schema -//go:generate go run github.com/sensu/sensu-go/scripts/gen_gqltype -types AssetBuild,ClusterRole,ClusterRoleBinding,Pipeline,PipelineWorkflow,ResourceReference,Role,RoleBinding,RoleRef,Rule,Secret,Subject -pkg-path ../../../../api/core/v2 -o ./corev2.gen.graphql +//go:generate go run github.com/sensu/sensu-go/scripts/gen_gqltype -types AssetBuild,ClusterRole,ClusterRoleBinding,Deregistration,Network,NetworkInterface,Pipeline,PipelineWorkflow,Process,ResourceReference,Role,RoleBinding,RoleRef,Rule,Secret,Subject,System -pkg-path ../../../../api/core/v2 -o ./corev2.gen.graphql +//go:generate go run github.com/sensu/sensu-go/scripts/gen_gqltype -types EntityConfig,EntityState -pkg-path ../../../../api/core/v3 -o ./corev3.gen.graphql //go:generate go run github.com/sensu/sensu-go/scripts/gengraphql . diff --git a/backend/apid/graphql/service.go b/backend/apid/graphql/service.go index d45176757c..5aec88aa86 100644 --- a/backend/apid/graphql/service.go +++ b/backend/apid/graphql/service.go @@ -70,11 +70,20 @@ func NewService(cfg ServiceConfig) (*Service, error) { schema.RegisterAsset(svc, &assetImpl{}) schema.RegisterBackendEntity(svc, &backendEntityImpl{}) schema.RegisterCoreV2AssetBuild(svc, &schema.CoreV2AssetBuildAliases{}) + schema.RegisterCoreV2Deregistration(svc, &schema.CoreV2DeregistrationAliases{}) + schema.RegisterCoreV2Network(svc, &schema.CoreV2NetworkAliases{}) + schema.RegisterCoreV2NetworkInterface(svc, &schema.CoreV2NetworkInterfaceAliases{}) schema.RegisterCoreV2Pipeline(svc, &corev2PipelineImpl{}) schema.RegisterCoreV2PipelineExtensionOverrides(svc, &corev2PipelineImpl{}) schema.RegisterCoreV2PipelineWorkflow(svc, &schema.CoreV2PipelineWorkflowAliases{}) + schema.RegisterCoreV2Process(svc, &schema.CoreV2ProcessAliases{}) schema.RegisterCoreV2ResourceReference(svc, &schema.CoreV2ResourceReferenceAliases{}) schema.RegisterCoreV2Secret(svc, &schema.CoreV2SecretAliases{}) + schema.RegisterCoreV2System(svc, &schema.CoreV2SystemAliases{}) + schema.RegisterCoreV3EntityConfig(svc, &corev3EntityConfigImpl{}) + schema.RegisterCoreV3EntityConfigExtensionOverrides(svc, &corev3EntityConfigExtImpl{client: cfg.GenericClient, entityClient: cfg.EntityClient}) + schema.RegisterCoreV3EntityState(svc, &corev3EntityStateImpl{}) + schema.RegisterCoreV3EntityStateExtensionOverrides(svc, &corev3EntityStateExtImpl{client: cfg.GenericClient, entityClient: cfg.EntityClient}) schema.RegisterNamespace(svc, &namespaceImpl{client: cfg.NamespaceClient, entityClient: cfg.EntityClient, eventClient: cfg.EventClient, serviceConfig: &cfg}) schema.RegisterErrCode(svc) schema.RegisterEvent(svc, &eventImpl{}) diff --git a/backend/apid/graphql/service_test.go b/backend/apid/graphql/service_test.go index 802a43986d..40d1c7e62b 100644 --- a/backend/apid/graphql/service_test.go +++ b/backend/apid/graphql/service_test.go @@ -23,6 +23,14 @@ func TestNewService(t *testing.T) { assert.NotEmpty(t, svc) } +// a smoke test to ensure that the service generation is idempotent +func TestServiceRegenerate(t *testing.T) { + svc, err := NewService(ServiceConfig{}) + require.NoError(t, err) + err = svc.Target.Regenerate() + assert.NoError(t, err) +} + func TestInitHooks(t *testing.T) { flag := false rollback := addHook(func(svc *graphql.Service, cfg ServiceConfig) { diff --git a/backend/backend.go b/backend/backend.go index a16aedc22f..a7c1af23cf 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -595,7 +595,7 @@ func Initialize(ctx context.Context, config *Config) (*Backend, error) { RBACClient: api.NewRBACClient(b.Store, auth), VersionController: actions.NewVersionController(clusterVersion), MetricGatherer: prometheus.DefaultGatherer, - GenericClient: &api.GenericClient{Store: b.Store, Auth: auth}, + GenericClient: &api.GenericClient{Store: b.Store, StoreV2: b.StoreV2, Auth: auth}, }) if err != nil { return nil, fmt.Errorf("error initializing graphql.Service: %s", err) diff --git a/graphql/service.go b/graphql/service.go index 759e6e2f63..ad6bf606c8 100644 --- a/graphql/service.go +++ b/graphql/service.go @@ -343,9 +343,24 @@ func mergeObjectConfig(a, b *graphql.ObjectConfig) { af := a.Fields.(graphql.Fields) bf := b.Fields.(graphql.Fields) for n, f := range bf { - af[n] = f + copy := *f + af[n] = © } - ai := a.Interfaces.([]*graphql.Interface) - bi := b.Interfaces.([]*graphql.Interface) - a.Interfaces = append(ai, bi...) + // merge any missing interfaces + ias := a.Interfaces.([]*graphql.Interface) + ibs := b.Interfaces.([]*graphql.Interface) + for _, ib := range ibs { + var ok bool + for _, ia := range ias { + if ia.PrivateName != ib.PrivateName { + continue + } + ok = true + break + } + if !ok { + ias = append(ias, Interface(ib.PrivateName)) + } + } + a.Interfaces = ias }