diff --git a/docs/sources/developers/kinds/core/serviceaccount/schema-reference.md b/docs/sources/developers/kinds/core/serviceaccount/schema-reference.md
new file mode 100644
index 00000000000..e668f64aa2f
--- /dev/null
+++ b/docs/sources/developers/kinds/core/serviceaccount/schema-reference.md
@@ -0,0 +1,38 @@
+---
+keywords:
+ - grafana
+ - schema
+title: Serviceaccount kind
+---
+> Both documentation generation and kinds schemas are in active development and subject to change without prior notice.
+
+# Serviceaccount kind
+
+## Maturity: merged
+## Version: 0.0
+
+## Properties
+
+| Property | Type | Required | Description |
+|-----------------|--------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------|
+| `avatarUrl` | string | **Yes** | AvatarUrl is the service account's avatar URL. It allows the frontend to display a picture in front
of the service account. |
+| `id` | integer | **Yes** | ID is the unique identifier of the service account in the database. |
+| `isDisabled` | boolean | **Yes** | IsDisabled indicates if the service account is disabled. |
+| `login` | string | **Yes** | Login of the service account. |
+| `name` | string | **Yes** | Name of the service account. |
+| `orgId` | integer | **Yes** | OrgId is the ID of an organisation the service account belongs to. |
+| `role` | string | **Yes** | OrgRole is a Grafana Organization Role which can be 'Viewer', 'Editor', 'Admin'. Possible values are: `Admin`, `Editor`, `Viewer`. |
+| `tokens` | integer | **Yes** | Tokens is the number of active tokens for the service account.
Tokens are used to authenticate the service account against Grafana. |
+| `accessControl` | [object](#accesscontrol) | No | AccessControl metadata associated with a given resource. |
+| `created` | integer | No | Created indicates when the service account was created. |
+| `teams` | string[] | No | Teams is a list of teams the service account belongs to. |
+| `updated` | integer | No | Updated indicates when the service account was updated. |
+
+## accessControl
+
+AccessControl metadata associated with a given resource.
+
+| Property | Type | Required | Description |
+|----------|------|----------|-------------|
+
+
diff --git a/kinds/serviceaccount/serviceaccount_kind.cue b/kinds/serviceaccount/serviceaccount_kind.cue
new file mode 100644
index 00000000000..befc567bc9a
--- /dev/null
+++ b/kinds/serviceaccount/serviceaccount_kind.cue
@@ -0,0 +1,46 @@
+package kind
+
+name: "Serviceaccount"
+maturity: "merged"
+
+lineage: seqs: [
+ {
+ schemas: [
+ // v0.0
+ {
+ // ID is the unique identifier of the service account in the database.
+ id: int64 @grafanamaturity(ToMetadata="sys")
+ // OrgId is the ID of an organisation the service account belongs to.
+ orgId: int64 @grafanamaturity(ToMetadata="sys")
+ // Name of the service account.
+ name: string
+ // Login of the service account.
+ login: string
+ // IsDisabled indicates if the service account is disabled.
+ isDisabled: bool
+ // Role is the Grafana organization role of the service account which can be 'Viewer', 'Editor', 'Admin'.
+ role: #OrgRole @grafanamaturity(ToMetadata="kind")
+ // Tokens is the number of active tokens for the service account.
+ // Tokens are used to authenticate the service account against Grafana.
+ tokens: int64 @grafanamaturity(ToMetadata="kind")
+ // AvatarUrl is the service account's avatar URL. It allows the frontend to display a picture in front
+ // of the service account.
+ avatarUrl: string @grafanamaturity(ToMetadata="kind")
+ // AccessControl metadata associated with a given resource.
+ accessControl?: {
+ [string]: bool @grafanamaturity(ToMetadata="sys")
+ }
+
+ // Teams is a list of teams the service account belongs to.
+ teams?: [...string] @grafanamaturity(ToMetadata="sys")
+ // Created indicates when the service account was created.
+ created?: int64 @grafanamaturity(ToMetadata="sys")
+ // Updated indicates when the service account was updated.
+ updated?: int64 @grafanamaturity(ToMetadata="sys")
+
+ // OrgRole is a Grafana Organization Role which can be 'Viewer', 'Editor', 'Admin'.
+ #OrgRole: "Admin" | "Editor" | "Viewer" @cuetsy(kind="type")
+ },
+ ]
+ },
+]
diff --git a/packages/grafana-schema/src/index.gen.ts b/packages/grafana-schema/src/index.gen.ts
index 9fdf476a0e4..6e9378c10c7 100644
--- a/packages/grafana-schema/src/index.gen.ts
+++ b/packages/grafana-schema/src/index.gen.ts
@@ -95,6 +95,15 @@ export type {
// Raw generated enums and default consts from playlist kind.
export { defaultPlaylist } from './raw/playlist/x/playlist_types.gen';
+// Raw generated types from Serviceaccount kind.
+export type {
+ Serviceaccount,
+ OrgRole
+} from './raw/serviceaccount/x/serviceaccount_types.gen';
+
+// Raw generated enums and default consts from serviceaccount kind.
+export { defaultServiceaccount } from './raw/serviceaccount/x/serviceaccount_types.gen';
+
// Raw generated types from Team kind.
export type { Team } from './raw/team/x/team_types.gen';
diff --git a/packages/grafana-schema/src/raw/serviceaccount/x/serviceaccount_types.gen.ts b/packages/grafana-schema/src/raw/serviceaccount/x/serviceaccount_types.gen.ts
new file mode 100644
index 00000000000..4abfa4f7cbc
--- /dev/null
+++ b/packages/grafana-schema/src/raw/serviceaccount/x/serviceaccount_types.gen.ts
@@ -0,0 +1,71 @@
+// Code generated - EDITING IS FUTILE. DO NOT EDIT.
+//
+// Generated by:
+// kinds/gen.go
+// Using jennies:
+// TSTypesJenny
+// LatestMajorsOrXJenny
+//
+// Run 'make gen-cue' from repository root to regenerate.
+
+/**
+ * OrgRole is a Grafana Organization Role which can be 'Viewer', 'Editor', 'Admin'.
+ */
+export type OrgRole = ('Admin' | 'Editor' | 'Viewer');
+
+export interface Serviceaccount {
+ /**
+ * AccessControl metadata associated with a given resource.
+ */
+ accessControl?: Record;
+ /**
+ * AvatarUrl is the service account's avatar URL. It allows the frontend to display a picture in front
+ * of the service account.
+ */
+ avatarUrl: string;
+ /**
+ * Created indicates when the service account was created.
+ */
+ created?: number;
+ /**
+ * ID is the unique identifier of the service account in the database.
+ */
+ id: number;
+ /**
+ * IsDisabled indicates if the service account is disabled.
+ */
+ isDisabled: boolean;
+ /**
+ * Login of the service account.
+ */
+ login: string;
+ /**
+ * Name of the service account.
+ */
+ name: string;
+ /**
+ * OrgId is the ID of an organisation the service account belongs to.
+ */
+ orgId: number;
+ /**
+ * Role is the Grafana organization role of the service account which can be 'Viewer', 'Editor', 'Admin'.
+ */
+ role: OrgRole;
+ /**
+ * Teams is a list of teams the service account belongs to.
+ */
+ teams?: Array;
+ /**
+ * Tokens is the number of active tokens for the service account.
+ * Tokens are used to authenticate the service account against Grafana.
+ */
+ tokens: number;
+ /**
+ * Updated indicates when the service account was updated.
+ */
+ updated?: number;
+}
+
+export const defaultServiceaccount: Partial = {
+ teams: [],
+};
diff --git a/pkg/kinds/serviceaccount/serviceaccount_kind_gen.go b/pkg/kinds/serviceaccount/serviceaccount_kind_gen.go
new file mode 100644
index 00000000000..097d21c12c1
--- /dev/null
+++ b/pkg/kinds/serviceaccount/serviceaccount_kind_gen.go
@@ -0,0 +1,113 @@
+// Code generated - EDITING IS FUTILE. DO NOT EDIT.
+//
+// Generated by:
+// kinds/gen.go
+// Using jennies:
+// CoreKindJenny
+//
+// Run 'make gen-cue' from repository root to regenerate.
+
+package serviceaccount
+
+import (
+ "github.com/grafana/grafana/pkg/kindsys"
+ "github.com/grafana/thema"
+ "github.com/grafana/thema/vmux"
+)
+
+// rootrel is the relative path from the grafana repository root to the
+// directory containing the .cue files in which this kind is declared. Necessary
+// for runtime errors related to the declaration and/or lineage to provide
+// a real path to the correct .cue file.
+const rootrel string = "kinds/serviceaccount"
+
+// TODO standard generated docs
+type Kind struct {
+ lin thema.ConvergentLineage[*Serviceaccount]
+ jcodec vmux.Codec
+ valmux vmux.ValueMux[*Serviceaccount]
+ decl kindsys.Decl[kindsys.CoreProperties]
+}
+
+// type guard
+var _ kindsys.Core = &Kind{}
+
+// TODO standard generated docs
+func NewKind(rt *thema.Runtime, opts ...thema.BindOption) (*Kind, error) {
+ decl, err := kindsys.LoadCoreKind(rootrel, rt.Context(), nil)
+ if err != nil {
+ return nil, err
+ }
+ k := &Kind{
+ decl: decl,
+ }
+
+ lin, err := decl.Some().BindKindLineage(rt, opts...)
+ if err != nil {
+ return nil, err
+ }
+
+ // Get the thema.Schema that the meta says is in the current version (which
+ // codegen ensures is always the latest)
+ cursch := thema.SchemaP(lin, k.decl.Properties.CurrentVersion)
+ tsch, err := thema.BindType[*Serviceaccount](cursch, &Serviceaccount{})
+ if err != nil {
+ // Should be unreachable, modulo bugs in the Thema->Go code generator
+ return nil, err
+ }
+
+ k.jcodec = vmux.NewJSONCodec("serviceaccount.json")
+ k.lin = tsch.ConvergentLineage()
+ k.valmux = vmux.NewValueMux(k.lin.TypedSchema(), k.jcodec)
+ return k, nil
+}
+
+// TODO standard generated docs
+func (k *Kind) Name() string {
+ return "serviceaccount"
+}
+
+// TODO standard generated docs
+func (k *Kind) MachineName() string {
+ return "serviceaccount"
+}
+
+// TODO standard generated docs
+func (k *Kind) Lineage() thema.Lineage {
+ return k.lin
+}
+
+// TODO standard generated docs
+func (k *Kind) ConvergentLineage() thema.ConvergentLineage[*Serviceaccount] {
+ return k.lin
+}
+
+// JSONValueMux is a version multiplexer that maps a []byte containing JSON data
+// at any schematized dashboard version to an instance of Serviceaccount.
+//
+// Validation and translation errors emitted from this func will identify the
+// input bytes as "dashboard.json".
+//
+// This is a thin wrapper around Thema's [vmux.ValueMux].
+func (k *Kind) JSONValueMux(b []byte) (*Serviceaccount, thema.TranslationLacunas, error) {
+ return k.valmux(b)
+}
+
+// TODO standard generated docs
+func (k *Kind) Maturity() kindsys.Maturity {
+ return k.decl.Properties.Maturity
+}
+
+// Decl returns the [kindsys.Decl] containing both CUE and Go representations of the
+// serviceaccount declaration in .cue files.
+func (k *Kind) Decl() kindsys.Decl[kindsys.CoreProperties] {
+ return k.decl
+}
+
+// Props returns a [kindsys.SomeKindProps], with underlying type [kindsys.CoreProperties],
+// representing the static properties declared in the serviceaccount kind.
+//
+// This method is identical to calling Decl().Props. It is provided to satisfy [kindsys.Interface].
+func (k *Kind) Props() kindsys.SomeKindProperties {
+ return k.decl.Properties
+}
diff --git a/pkg/kinds/serviceaccount/serviceaccount_types_gen.go b/pkg/kinds/serviceaccount/serviceaccount_types_gen.go
new file mode 100644
index 00000000000..c539cf24d1b
--- /dev/null
+++ b/pkg/kinds/serviceaccount/serviceaccount_types_gen.go
@@ -0,0 +1,64 @@
+// Code generated - EDITING IS FUTILE. DO NOT EDIT.
+//
+// Generated by:
+// kinds/gen.go
+// Using jennies:
+// GoTypesJenny
+// LatestJenny
+//
+// Run 'make gen-cue' from repository root to regenerate.
+
+package serviceaccount
+
+// Defines values for OrgRole.
+const (
+ OrgRoleAdmin OrgRole = "Admin"
+
+ OrgRoleEditor OrgRole = "Editor"
+
+ OrgRoleViewer OrgRole = "Viewer"
+)
+
+// OrgRole is a Grafana Organization Role which can be 'Viewer', 'Editor', 'Admin'.
+type OrgRole string
+
+// Serviceaccount defines model for serviceaccount.
+type Serviceaccount struct {
+ // AccessControl metadata associated with a given resource.
+ AccessControl map[string]bool `json:"accessControl,omitempty"`
+
+ // AvatarUrl is the service account's avatar URL. It allows the frontend to display a picture in front
+ // of the service account.
+ AvatarUrl string `json:"avatarUrl"`
+
+ // Created indicates when the service account was created.
+ Created *int64 `json:"created,omitempty"`
+
+ // ID is the unique identifier of the service account in the database.
+ Id int64 `json:"id"`
+
+ // IsDisabled indicates if the service account is disabled.
+ IsDisabled bool `json:"isDisabled"`
+
+ // Login of the service account.
+ Login string `json:"login"`
+
+ // Name of the service account.
+ Name string `json:"name"`
+
+ // OrgId is the ID of an organisation the service account belongs to.
+ OrgId int64 `json:"orgId"`
+
+ // OrgRole is a Grafana Organization Role which can be 'Viewer', 'Editor', 'Admin'.
+ Role OrgRole `json:"role"`
+
+ // Teams is a list of teams the service account belongs to.
+ Teams *[]string `json:"teams,omitempty"`
+
+ // Tokens is the number of active tokens for the service account.
+ // Tokens are used to authenticate the service account against Grafana.
+ Tokens int64 `json:"tokens"`
+
+ // Updated indicates when the service account was updated.
+ Updated *int64 `json:"updated,omitempty"`
+}
diff --git a/pkg/kindsys/report.go b/pkg/kindsys/report.go
index b853abbe97d..97f12d894fd 100644
--- a/pkg/kindsys/report.go
+++ b/pkg/kindsys/report.go
@@ -71,7 +71,7 @@ var plannedCoreKinds = []string{
"Folder",
"DataSource",
"APIKey",
- "ServiceAccount",
+ "Serviceaccount",
"Thumb",
"Query",
"QueryHistory",
diff --git a/pkg/kindsys/report.json b/pkg/kindsys/report.json
index 7ed9ccdc6b4..35d314c27c9 100644
--- a/pkg/kindsys/report.json
+++ b/pkg/kindsys/report.json
@@ -1299,24 +1299,29 @@
},
"serviceaccount": {
"category": "core",
- "codeowners": [],
+ "codeowners": [
+ "grafana/grafana-as-code",
+ "grafana/grafana-bi-squad",
+ "grafana/plugins-platform-frontend",
+ "grafana/user-essentials"
+ ],
"currentVersion": [
0,
0
],
- "grafanaMaturityCount": 0,
+ "grafanaMaturityCount": 9,
"lineageIsGroup": false,
"links": {
- "docs": "n/a",
- "go": "n/a",
- "schema": "n/a",
- "ts": "n/a"
+ "docs": "https://grafana.com/docs/grafana/next/developers/kinds/core/serviceaccount/schema-reference",
+ "go": "https://github.com/grafana/grafana/tree/main/pkg/kinds/serviceaccount",
+ "schema": "https://github.com/grafana/grafana/tree/main/kinds/serviceaccount/serviceaccount_kind.cue",
+ "ts": "https://github.com/grafana/grafana/tree/main/packages/grafana-schema/src/raw/serviceaccount/x/serviceaccount_types.gen.ts"
},
"machineName": "serviceaccount",
- "maturity": "planned",
- "name": "ServiceAccount",
+ "maturity": "merged",
+ "name": "Serviceaccount",
"pluralMachineName": "serviceaccounts",
- "pluralName": "ServiceAccounts"
+ "pluralName": "Serviceaccounts"
},
"statpanelcfg": {
"category": "composable",
@@ -1772,9 +1777,10 @@
"items": [
"alertgroupspanelcfg",
"playlist",
+ "serviceaccount",
"team"
],
- "count": 3
+ "count": 4
},
"planned": {
"name": "planned",
@@ -1826,7 +1832,6 @@
"prometheusdatasourcecfg",
"query",
"queryhistory",
- "serviceaccount",
"tableoldpanelcfg",
"tempodataquery",
"tempodatasourcecfg",
@@ -1840,7 +1845,7 @@
"zipkindataquery",
"zipkindatasourcecfg"
],
- "count": 60
+ "count": 59
},
"stable": {
"name": "stable",
diff --git a/pkg/registry/corekind/base_gen.go b/pkg/registry/corekind/base_gen.go
index 2e9753ed1a6..f3e52a08564 100644
--- a/pkg/registry/corekind/base_gen.go
+++ b/pkg/registry/corekind/base_gen.go
@@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/kinds/dashboard"
"github.com/grafana/grafana/pkg/kinds/playlist"
+ "github.com/grafana/grafana/pkg/kinds/serviceaccount"
"github.com/grafana/grafana/pkg/kinds/team"
"github.com/grafana/grafana/pkg/kindsys"
"github.com/grafana/thema"
@@ -30,16 +31,18 @@ import (
// Prefer All*() methods when performing operations generically across all kinds.
// For example, a validation HTTP middleware for any kind-schematized object type.
type Base struct {
- all []kindsys.Core
- dashboard *dashboard.Kind
- playlist *playlist.Kind
- team *team.Kind
+ all []kindsys.Core
+ dashboard *dashboard.Kind
+ playlist *playlist.Kind
+ serviceaccount *serviceaccount.Kind
+ team *team.Kind
}
// type guards
var (
_ kindsys.Core = &dashboard.Kind{}
_ kindsys.Core = &playlist.Kind{}
+ _ kindsys.Core = &serviceaccount.Kind{}
_ kindsys.Core = &team.Kind{}
)
@@ -53,6 +56,11 @@ func (b *Base) Playlist() *playlist.Kind {
return b.playlist
}
+// Serviceaccount returns the [kindsys.Interface] implementation for the serviceaccount kind.
+func (b *Base) Serviceaccount() *serviceaccount.Kind {
+ return b.serviceaccount
+}
+
// Team returns the [kindsys.Interface] implementation for the team kind.
func (b *Base) Team() *team.Kind {
return b.team
@@ -74,6 +82,12 @@ func doNewBase(rt *thema.Runtime) *Base {
}
reg.all = append(reg.all, reg.playlist)
+ reg.serviceaccount, err = serviceaccount.NewKind(rt)
+ if err != nil {
+ panic(fmt.Sprintf("error while initializing the serviceaccount Kind: %s", err))
+ }
+ reg.all = append(reg.all, reg.serviceaccount)
+
reg.team, err = team.NewKind(rt)
if err != nil {
panic(fmt.Sprintf("error while initializing the team Kind: %s", err))