diff --git a/.gitattributes b/.gitattributes index 98ab0bac..93950ba1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,5 @@ *_gen.go linguist-generated=true generated.go linguist-generated=true go.mod linguist-generated=true -go.sum linguist-generated=true \ No newline at end of file +go.sum linguist-generated=true +schema.graphql linguist-generated=true \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 9b200876..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "src/cloudgraphql"] - path = src/cloudgraphql - url = https://github.com/otterize/graphql diff --git a/src/cloudgraphql b/src/cloudgraphql deleted file mode 160000 index 4d044b48..00000000 --- a/src/cloudgraphql +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4d044b48dac3079db5a4e431f6b49fbc8fd40546 diff --git a/src/go.mod b/src/go.mod index 05f3b495..a98c2c4b 100644 --- a/src/go.mod +++ b/src/go.mod @@ -16,6 +16,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/spf13/viper v1.12.0 github.com/stretchr/testify v1.8.1 + github.com/suessflorian/gqlfetch v0.6.0 github.com/vektah/gqlparser/v2 v2.4.5 k8s.io/api v0.26.1 k8s.io/apimachinery v0.26.1 @@ -81,6 +82,7 @@ require ( github.com/urfave/cli/v2 v2.8.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.1 // indirect + github.com/vektah/gqlparser v1.3.1 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 // indirect diff --git a/src/go.sum b/src/go.sum index 6418b456..7175535a 100644 --- a/src/go.sum +++ b/src/go.sum @@ -348,6 +348,7 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.33.0 h1:2aKucr+rQV6gHpY3bpeZu69uYoQOzVhGT3J22Op6Cjk= github.com/samber/lo v1.33.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -384,6 +385,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= +github.com/suessflorian/gqlfetch v0.6.0 h1:6e+Oe9mWbbjSmJez+6I4tyskQMy6lQlFFQYj64gaCQU= +github.com/suessflorian/gqlfetch v0.6.0/go.mod h1:Xlz+o2ate8M/Hr237HJpFyJD0l05uh3NAX3zmXVmjxU= github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.8.1 h1:CGuYNZF9IKZY/rfBe3lJpccSoIY1ytfvmgQT90cNOl4= @@ -392,6 +395,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU= +github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74= github.com/vektah/gqlparser/v2 v2.4.0/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= github.com/vektah/gqlparser/v2 v2.4.5 h1:C02NsyEsL4TXJB7ndonqTfuQOL4XPIu0aAWugdmTgmc= github.com/vektah/gqlparser/v2 v2.4.5/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= @@ -614,6 +619,7 @@ golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= diff --git a/src/mapper/pkg/cloudclient/generate.go b/src/mapper/pkg/cloudclient/generate.go index 12a254de..13e759a5 100644 --- a/src/mapper/pkg/cloudclient/generate.go +++ b/src/mapper/pkg/cloudclient/generate.go @@ -1,4 +1,7 @@ package cloudclient +import _ "github.com/suessflorian/gqlfetch" + +//go:generate sh -c "go run github.com/suessflorian/gqlfetch/gqlfetch --endpoint https://app.staging.otterize.com/api/graphql/v1beta > schema.graphql" //go:generate go run github.com/Khan/genqlient ./genqlient.yaml //go:generate go run github.com/golang/mock/mockgen@v1.6.0 -destination=./mocks/mocks.go -package=cloudclientmocks -source=./cloud_client.go CloudClient diff --git a/src/mapper/pkg/cloudclient/generated.go b/src/mapper/pkg/cloudclient/generated.go index be39541d..cb38eced 100644 --- a/src/mapper/pkg/cloudclient/generated.go +++ b/src/mapper/pkg/cloudclient/generated.go @@ -104,6 +104,7 @@ func (v *KafkaConfigInput) GetOperations() []*KafkaOperation { return v.Operatio type KafkaOperation string const ( + KafkaOperationAll KafkaOperation = "ALL" KafkaOperationConsume KafkaOperation = "CONSUME" KafkaOperationProduce KafkaOperation = "PRODUCE" KafkaOperationCreate KafkaOperation = "CREATE" @@ -118,6 +119,7 @@ const ( // ReportComponentStatusResponse is returned by ReportComponentStatus on success. type ReportComponentStatusResponse struct { + // Report integration components status ReportIntegrationComponentStatus bool `json:"reportIntegrationComponentStatus"` } diff --git a/src/mapper/pkg/cloudclient/genqlient.yaml b/src/mapper/pkg/cloudclient/genqlient.yaml index a7d57948..4ccd6432 100644 --- a/src/mapper/pkg/cloudclient/genqlient.yaml +++ b/src/mapper/pkg/cloudclient/genqlient.yaml @@ -1,8 +1,7 @@ # genqlient config; for full documentation see: # https://github.com/Khan/genqlient/blob/main/docs/genqlient.yaml schema: - - '../../../cloudgraphql/*.graphql' - - '../../../cloudgraphql/federation/*.graphql' + - ./schema.graphql operations: - genqlient.graphql generated: ./generated.go diff --git a/src/mapper/pkg/cloudclient/schema.graphql b/src/mapper/pkg/cloudclient/schema.graphql new file mode 100644 index 00000000..7d33fee1 --- /dev/null +++ b/src/mapper/pkg/cloudclient/schema.graphql @@ -0,0 +1,735 @@ +"""Directs the executor to include this field or fragment only when the `if` argument is true.""" +directive @include( +"""Included when true.""" + if: Boolean! +) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"""Directs the executor to skip this field or fragment when the `if` argument is true.""" +directive @skip( +"""Skipped when true.""" + if: Boolean! +) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +"""Marks an element of a GraphQL schema as no longer supported.""" +directive @deprecated( +"""Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).""" + reason: String +) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE + +"""Exposes a URL that specifies the behavior of this scalar.""" +directive @specifiedBy( +"""The URL that specifies the behavior of this scalar.""" + url: String! +) on SCALAR + +type AccessGraph { + filter: AccessGraphFilter! +"""Clusters for which there are results""" + clusters: [Cluster!]! + serviceAccessGraphs: [ServiceAccessGraph!]! +} + +type AccessGraphEdge { + client: Service! + server: Service! + discoveredIntents: [Intent!]! + appliedIntents: [Intent!]! + accessStatus: EdgeAccessStatus! +} + +type AccessGraphFilter { + environmentIds: [ID!] + clusterIds: [ID!] + namespaceIds: [ID!] + serviceIds: [ID!] + lastSeenAfter: Time + includeServicesWithNoEdges: Boolean +} + +"""The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.""" +scalar ID + +"""The `Boolean` scalar type represents `true` or `false`.""" +scalar Boolean + +enum ApiFieldAction { +"""Do nothing, expose models to the REST API as id-only structs (Default behaviour)""" + COLLAPSE_MODEL +"""Expand model field, returning its full data and not just its ID""" + EXPAND_MODEL +"""Drop this field from the REST API""" + DROP_FIELD +} + +enum ApiMethod { + GET + POST + PUT + PATCH + DELETE +} + +input CertificateCustomization { + dnsNames: [String!] + ttl: Int +} + +"""The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.""" +scalar String + +"""The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.""" +scalar Int + +type CertificateInformation { + commonName: String! + dnsNames: [String!] + ttl: Int +} + +type Cluster { + id: ID! + integration: Integration + defaultEnvironment: Environment + name: String! + components: IntegrationComponents! + configuration: ClusterConfiguration + namespaces: [Namespace!]! + serviceCount: Int! +} + +type ClusterConfiguration { + globalDefaultDeny: Boolean! + useNetworkPoliciesInAccessGraphStates: Boolean! +} + +input ClusterConfigurationInput { + globalDefaultDeny: Boolean! + useNetworkPoliciesInAccessGraphStates: Boolean! +} + +type ComponentStatus { + type: ComponentStatusType! + lastSeen: Time +} + +enum ComponentStatusType { + NOT_INTEGRATED + CONNECTED + DISCONNECTED +} + +enum ComponentType { + INTENTS_OPERATOR + CREDENTIALS_OPERATOR + NETWORK_MAPPER +} + +type CredentialsOperatorComponent { + type: ComponentType! + status: ComponentStatus! +} + +"""The set of custom constraints supported by our API schema.""" +enum CustomConstraint { + CUSTOM_NAME + K8S_NAME + LABEL_NAME + NONEMPTY + ID +} + +input DiscoveredIntentInput { + discoveredAt: Time! + intent: IntentInput! +} + +type EdgeAccessStatus { + useNetworkPoliciesInAccessGraphStates: Boolean! + verdict: EdgeAccessStatusVerdict! + reason: EdgeAccessStatusReason! +} + +enum EdgeAccessStatusReason { + ALLOWED_BY_APPLIED_INTENTS + ALLOWED_BY_APPLIED_INTENTS_OVERLY_PERMISSIVE + BLOCKED_BY_DEFAULT_DENY + INTENTS_OPERATOR_NOT_ENFORCING + INTENTS_OPERATOR_NOT_ENFORCING_MISSING_APPLIED_INTENT + MISSING_APPLIED_INTENT + INTENTS_OPERATOR_NEVER_CONNECTED + NETWORK_MAPPER_NEVER_CONNECTED +} + +enum EdgeAccessStatusVerdict { + EXPLICITLY_ALLOWED + IMPLICITLY_ALLOWED + WOULD_BE_BLOCKED + BLOCKED + UNKNOWN +} + +type Environment { + id: ID! + appliedIntentsCount: Int! + name: String! + labels: [Label!] + namespaces: [Namespace!]! + serviceCount: Int! +} + +type HTTPConfig { + path: String + methods: [HTTPMethod!] +} + +input HTTPConfigInput { + path: String + method: HTTPMethod +} + +enum HTTPMethod { + GET + POST + PUT + DELETE + OPTIONS + TRACE + PATCH + CONNECT +} + +input InputAccessGraphFilter { + environmentIds: [ID!] + clusterIds: [ID!] + serviceIds: [ID!] + namespaceIds: [ID!] + lastSeenAfter: Time + includeServicesWithNoEdges: Boolean +} + +type Integration { + id: ID! + name: String! + type: IntegrationType! + credentials: IntegrationCredentials! + components: IntegrationComponents + defaultEnvironment: Environment + cluster: Cluster +} + +type IntegrationComponents { + clusterId: ID! + intentsOperator: IntentsOperatorComponent! + credentialsOperator: CredentialsOperatorComponent! + networkMapper: NetworkMapperComponent! +} + +type IntegrationCredentials { + clientId: String! + clientSecret: String! +} + +enum IntegrationType { + GENERIC + KUBERNETES +} + +type Intent { + id: ID! + server: Service! + client: Service! + type: IntentType + kafkaTopics: [KafkaConfig!] + httpResources: [HTTPConfig!] +} + +input IntentInput { + namespace: String! + clientName: String! + serverName: String! + serverNamespace: String + type: IntentType + topics: [KafkaConfigInput!] + resources: [HTTPConfigInput!] +} + +type IntentsOperatorComponent { + type: ComponentType! + status: ComponentStatus! + configuration: IntentsOperatorConfiguration +} + +type IntentsOperatorConfiguration { + globalEnforcementEnabled: Boolean! + networkPolicyEnforcementEnabled: Boolean! + kafkaACLEnforcementEnabled: Boolean! +} + +input IntentsOperatorConfigurationInput { + globalEnforcementEnabled: Boolean! + networkPolicyEnforcementEnabled: Boolean! + kafkaACLEnforcementEnabled: Boolean! +} + +enum IntentType { + HTTP + KAFKA +} + +type Invite { + id: ID! + email: String! + organization: Organization! + inviter: User! + created: Time! + acceptedAt: Time + status: InviteStatus! +} + +enum InviteStatus { + PENDING + ACCEPTED +} + +type KafkaConfig { + name: String! + operations: [KafkaOperation!] +} + +input KafkaConfigInput { + name: String! + operations: [KafkaOperation!] +} + +enum KafkaOperation { + ALL + CONSUME + PRODUCE + CREATE + ALTER + DELETE + DESCRIBE + CLUSTER_ACTION + DESCRIBE_CONFIGS + ALTER_CONFIGS + IDEMPOTENT_WRITE +} + +type KafkaServerConfig { + address: String + topics: [KafkaTopic!]! +} + +input KafkaServerConfigInput { + name: String! + namespace: String! + address: String! + topics: [KafkaTopicInput!]! +} + +type KafkaTopic { + clientIdentityRequired: Boolean! + intentsRequired: Boolean! + pattern: KafkaTopicPattern! + topic: String! +} + +input KafkaTopicInput { + clientIdentityRequired: Boolean! + intentsRequired: Boolean! + pattern: KafkaTopicPattern! + topic: String! +} + +enum KafkaTopicPattern { + LITERAL + PREFIX +} + +type KeyPair { + keyPEM: String! + caPEM: String! + certPEM: String! + rootCAPEM: String! + expiresAt: Int! +} + +type Label { + key: String! + value: String +} + +input LabelInput { + key: String! + value: String +} + +type Me { +"""The logged-in user details.""" + user: User! +"""The organizations to which the current logged-in user belongs.""" + organizations: [Organization!]! +"""Organizations to which the current logged-in user may join.""" + invites: [Invite!]! +"""The organization under which the current user request acts. +This is selected by the X-Otterize-Organization header, +or, for users with a single organization, this is that single selected organization.""" + selectedOrganization: Organization! +} + +type MeMutation { +"""Register the user defined by the active session token into the otterize users store.""" + registerUser: Me! +} + +type Mutation { +"""This is just a placeholder since currently GraphQL does not allow empty types""" + dummy: Boolean +"""Create a new organization""" + createOrganization: Organization! +"""Update organization""" + updateOrganization( + id: ID! + name: String + imageURL: String + ): Organization! +"""Remove user from organization""" + removeUserFromOrganization( + id: ID! + userId: ID! + ): ID! +"""Operate on the current logged-in user""" + me: MeMutation! +"""Create user invite""" + createInvite( + email: String! + ): Invite! +"""Delete user invite""" + deleteInvite( + id: ID! + ): ID! +"""Accept user invite""" + acceptInvite( + id: ID! + ): Invite! + reportIntentsOperatorConfiguration( + configuration: IntentsOperatorConfigurationInput! + ): Boolean! +"""Create a new generic integration""" + createGenericIntegration( + name: String! + ): Integration +"""Create a new Kubernetes integration""" + createKubernetesIntegration( + environmentId: ID + clusterId: ID! + ): Integration +"""Update Generic integration""" + updateGenericIntegration( + id: ID! + name: String + ): Integration +"""Update Kubernetes integration""" + updateKubernetesIntegration( + id: ID! + environmentId: ID + ): Integration +"""Delete integration""" + deleteIntegration( + id: ID! + ): ID! +"""Report integration components status""" + reportIntegrationComponentStatus( + component: ComponentType! + ): Boolean! + initializeOrganizationCAs( + organizationId: ID! + ): Boolean! + reportDiscoveredIntents( + intents: [DiscoveredIntentInput!]! + ): Boolean! + reportAppliedKubernetesIntents( + namespace: String! + intents: [IntentInput!]! + ): Boolean! + reportKafkaServerConfigs( + namespace: String! + serverConfigs: [KafkaServerConfigInput!]! + ): Boolean! +"""Register certificate-request details for kubernetes pod owner, returns the service associated with this pod owner""" + registerKubernetesPodOwnerCertificateRequest( + podOwner: NamespacedPodOwner! + certificateCustomization: CertificateCustomization + ): Service! +"""Report active pod owners to the cloud, as a result the cloud removes certificate requests of inactive pod owners """ + reportActiveCertificateRequesters( + activePodOwners: [NamespacedPodOwner!]! + ): Boolean! +"""Create a new environment""" + createEnvironment( + name: String! + labels: [LabelInput!] + ): Environment! +"""Update environment""" + updateEnvironment( + id: ID! + name: String + labels: [LabelInput!] + ): Environment! +"""Delete environment""" + deleteEnvironment( + id: ID! + ): ID! +"""Add label to environment""" + addEnvironmentLabel( + id: ID! + label: LabelInput! + ): Environment! +"""Remove label from environment""" + deleteEnvironmentLabel( + id: ID! + key: String! + ): Environment! +"""Associate namespace to environment""" + associateNamespaceToEnv( + id: ID! + environmentId: ID + ): Namespace! +"""Create cluster""" + createCluster( + name: String! + ): Cluster! +"""Delete cluster""" + deleteCluster( + id: ID! + ): ID! +"""Update cluster""" + updateCluster( + id: ID! + configuration: ClusterConfigurationInput + ): Cluster! +} + +type Namespace { + id: ID! + name: String! + cluster: Cluster! + environment: Environment! + services: [Service!]! + serviceCount: Int! +} + +input NamespacedPodOwner { + name: String! + namespace: String! +} + +type NetworkMapperComponent { + type: ComponentType! + status: ComponentStatus! +} + +type Organization { + id: ID! + name: String + imageURL: String +} + +type Query { +"""This is just a placeholder since currently GraphQL does not allow empty types""" + dummy: Boolean +"""List organizations""" + organizations: [Organization!]! +"""Get organization""" + organization( + id: ID! + ): Organization! +"""List users""" + users: [User!]! +"""Get user""" + user( + id: ID! + ): User! +"""Get information regarding the current logged-in user""" + me: Me! +"""List user invites""" + invites( + email: String + status: InviteStatus + ): [Invite!]! +"""Get user invite""" + invite( + id: ID! + ): Invite! +"""Get one user invite""" + oneInvite( + email: String + status: InviteStatus + ): Invite! +"""List integrations""" + integrations( + name: String + integrationType: IntegrationType + environmentId: ID + clusterId: ID + ): [Integration!]! +"""Get integration""" + integration( + id: ID! + ): Integration! +"""Get integration by filters""" + oneIntegration( + integrationType: IntegrationType + environmentId: ID + clusterId: ID + name: String + ): Integration! +"""Get intent""" + intent( + id: ID! + ): Intent! +"""List intents""" + intents( + environmentId: ID + clientId: ID + serverId: ID + ): [Intent!]! +"""Get service""" + service( + id: ID! + ): Service! +"""List services""" + services( + environmentId: ID + namespaceId: ID + name: String + ): [Service!]! +"""Get service by filters""" + oneService( + environmentId: ID + namespaceId: ID + name: String + ): Service +"""Get access graph""" + accessGraph( + filter: InputAccessGraphFilter + ): AccessGraph! +"""Get environment""" + environment( + id: ID! + ): Environment! +"""List environments""" + environments( + name: String + labels: [LabelInput!] + ): [Environment!]! +"""Get environment by filters""" + oneEnvironment( + name: String! + ): Environment! +"""Get namespace""" + namespace( + id: ID! + ): Namespace! +"""List namespaces""" + namespaces( + environmentId: ID + clusterId: ID + name: String + ): [Namespace!]! +"""Get one namespace""" + oneNamespace( + environmentId: ID + clusterId: ID + name: String + ): Namespace! +"""Get cluster""" + cluster( + id: ID! + ): Cluster! +"""List clusters""" + clusters( + name: String + ): [Cluster!]! +"""Get cluster by filters""" + oneCluster( + name: String! + ): Cluster +} + +type ServerBlockingStatus { + verdict: ServerBlockingStatusVerdict! + reason: ServerBlockingStatusReason! +} + +enum ServerBlockingStatusReason { + INTENTS_OPERATOR_NEVER_CONNECTED + NETWORK_MAPPER_NEVER_CONNECTED + INTENTS_IMPLICITLY_ALLOWED + ALL_INTENTS_APPLIED + MISSING_APPLIED_INTENTS + INTENTS_OPERATOR_NOT_ENFORCING +} + +enum ServerBlockingStatusVerdict { + UNKNOWN + NOT_BLOCKING + WOULD_BLOCK + BLOCKING +} + +type ServerProtectionStatus { + verdict: ServerProtectionStatusVerdict! + reason: ServerProtectionStatusReason! +} + +enum ServerProtectionStatusReason { + INTENTS_OPERATOR_NEVER_CONNECTED + INTENTS_OPERATOR_NOT_ENFORCING + SERVER_HAS_NO_NETWORK_POLICY + PROTECTED_BY_DEFAULT_DENY + PROTECTED_BY_SERVER_NETWORK_POLICY +} + +enum ServerProtectionStatusVerdict { + UNKNOWN + UNPROTECTED + PROTECTED +} + +type Service { + id: ID! + tlsKeyPair: KeyPair! + name: String! + namespace: Namespace + environment: Environment! +"""If service is Kafka, its KafkaServerConfig.""" + kafkaServerConfig: KafkaServerConfig + certificateInformation: CertificateInformation +} + +type ServiceAccessGraph { + service: Service! + accessStatus: ServiceAccessStatus! + calls: [AccessGraphEdge!]! + serves: [AccessGraphEdge!]! +} + +type ServiceAccessStatus { + useNetworkPoliciesInAccessGraphStates: Boolean! + protectionStatus: ServerProtectionStatus! + blockingStatus: ServerBlockingStatus! + hasAppliedIntents: Boolean! +} + +scalar Time + +type User { + id: ID! + email: String! + name: String! + imageURL: String! + authProviderUserId: String! +} + +