@@ -26,15 +26,16 @@ type OperatorStageName string
26
26
type OperatorStageStatus string
27
27
28
28
const (
29
- OperatorStageGrafanaConfig OperatorStageName = "config"
30
- OperatorStageAdminUser OperatorStageName = "admin user"
31
- OperatorStagePvc OperatorStageName = "pvc"
32
- OperatorStageServiceAccount OperatorStageName = "service account"
33
- OperatorStageService OperatorStageName = "service"
34
- OperatorStageIngress OperatorStageName = "ingress"
35
- OperatorStagePlugins OperatorStageName = "plugins"
36
- OperatorStageDeployment OperatorStageName = "deployment"
37
- OperatorStageComplete OperatorStageName = "complete"
29
+ OperatorStageGrafanaConfig OperatorStageName = "config"
30
+ OperatorStageAdminUser OperatorStageName = "admin user"
31
+ OperatorStagePvc OperatorStageName = "pvc"
32
+ OperatorStageServiceAccount OperatorStageName = "service account"
33
+ OperatorStageService OperatorStageName = "service"
34
+ OperatorStageIngress OperatorStageName = "ingress"
35
+ OperatorStagePlugins OperatorStageName = "plugins"
36
+ OperatorStageDeployment OperatorStageName = "deployment"
37
+ OperatorStageGrafanaServiceAccounts OperatorStageName = "grafana service-accounts"
38
+ OperatorStageComplete OperatorStageName = "complete"
38
39
)
39
40
40
41
const (
@@ -52,6 +53,50 @@ type OperatorReconcileVars struct {
52
53
Plugins string
53
54
}
54
55
56
+ // GrafanaServiceAccountTokenSpec describes a token to create.
57
+ type GrafanaServiceAccountTokenSpec struct {
58
+ // Name is the name of the Kubernetes Secret (and token identifier in Grafana). The secret will contain the token value.
59
+ // +kubebuilder:validation:Required
60
+ Name string `json:"name"`
61
+
62
+ // Expires is the optional expiration time for the token. After this time, the operator may rotate the token.
63
+ // +kubebuilder:validation:Optional
64
+ Expires * metav1.Time `json:"expires,omitempty"`
65
+ }
66
+
67
+ // GrafanaServiceAccountSpec defines the desired state of a GrafanaServiceAccount.
68
+ type GrafanaServiceAccountSpec struct {
69
+ // ID is a kind of unique identifier to distinguish between service accounts if the name is changed.
70
+ // +kubebuilder:validation:Required
71
+ ID string `json:"id"`
72
+
73
+ // Name is the desired name of the service account in Grafana.
74
+ // +kubebuilder:validation:Required
75
+ Name string `json:"name"`
76
+
77
+ // Role is the Grafana role for the service account (Viewer, Editor, Admin).
78
+ // +kubebuilder:validation:Required
79
+ // +kubebuilder:validation:Enum=Viewer;Editor;Admin
80
+ Role string `json:"role"`
81
+
82
+ // IsDisabled indicates if the service account should be disabled in Grafana.
83
+ // +kubebuilder:validation:Optional
84
+ IsDisabled bool `json:"isDisabled,omitempty"`
85
+
86
+ // Tokens defines API tokens to create for this service account. Each token will be stored in a Kubernetes Secret with the given name.
87
+ // +kubebuilder:validation:Optional
88
+ Tokens []GrafanaServiceAccountTokenSpec `json:"tokens,omitempty"`
89
+ }
90
+
91
+ type GrafanaServiceAccounts struct {
92
+ Accounts []GrafanaServiceAccountSpec `json:"accounts,omitempty"`
93
+
94
+ // GenerateTokenSecret, if true, will create one default API token in a Secret if no Tokens are specified.
95
+ // If false, no token is created unless explicitly listed in Tokens.
96
+ // +kubebuilder:default=true
97
+ GenerateTokenSecret bool `json:"generateTokenSecret,omitempty"`
98
+ }
99
+
55
100
// GrafanaSpec defines the desired state of Grafana
56
101
type GrafanaSpec struct {
57
102
// +kubebuilder:pruning:PreserveUnknownFields
@@ -80,6 +125,8 @@ type GrafanaSpec struct {
80
125
Preferences * GrafanaPreferences `json:"preferences,omitempty"`
81
126
// DisableDefaultAdminSecret prevents operator from creating default admin-credentials secret
82
127
DisableDefaultAdminSecret bool `json:"disableDefaultAdminSecret,omitempty"`
128
+ // Grafana Service Accounts
129
+ GrafanaServiceAccounts * GrafanaServiceAccounts `json:"grafanaServiceAccounts,omitempty"`
83
130
}
84
131
85
132
type External struct {
@@ -131,18 +178,59 @@ type GrafanaPreferences struct {
131
178
HomeDashboardUID string `json:"homeDashboardUid,omitempty"`
132
179
}
133
180
181
+ // GrafanaServiceAccountTokenStatus describes a token created in Grafana.
182
+ type GrafanaServiceAccountTokenStatus struct {
183
+ // Name is the name of the Kubernetes Secret. The secret will contain the token value.
184
+ Name string `json:"name"`
185
+
186
+ // Expires is the expiration time for the token.
187
+ // N.B. There's possible discrepancy with the expiration time in spec.
188
+ // It happens because Grafana API accepts TTL in seconds then calculates the expiration time against the current time.
189
+ Expires * metav1.Time `json:"expires,omitempty"`
190
+
191
+ // ID is the Grafana-assigned ID of the token.
192
+ ID int64 `json:"tokenId"`
193
+
194
+ // SecretName is the name of the Kubernetes Secret that stores the actual token value.
195
+ // This may seem redundant if the Secret name usually matches the token's Name,
196
+ // but it's stored explicitly in Status for clarity and future flexibility.
197
+ SecretName string `json:"secretName"`
198
+ }
199
+
200
+ // GrafanaServiceAccountStatus holds status for one Grafana instance.
201
+ type GrafanaServiceAccountStatus struct {
202
+ // SpecID is a kind of unique identifier to distinguish between service accounts if the name is changed.
203
+ SpecID string `json:"specId"`
204
+
205
+ // Name is the name of the service account in Grafana.
206
+ Name string `json:"name"`
207
+
208
+ // ServiceAccountID is the numeric ID of the service account in this Grafana.
209
+ ServiceAccountID int64 `json:"serviceAccountId"`
210
+
211
+ // Role is the Grafana role for the service account (Viewer, Editor, Admin).
212
+ Role string `json:"role"`
213
+
214
+ // IsDisabled indicates if the service account is disabled.
215
+ IsDisabled bool `json:"isDisabled,omitempty"`
216
+
217
+ // Tokens is the status of tokens for this service account in Grafana.
218
+ Tokens []GrafanaServiceAccountTokenStatus `json:"tokens,omitempty"`
219
+ }
220
+
134
221
// GrafanaStatus defines the observed state of Grafana
135
222
type GrafanaStatus struct {
136
- Stage OperatorStageName `json:"stage,omitempty"`
137
- StageStatus OperatorStageStatus `json:"stageStatus,omitempty"`
138
- LastMessage string `json:"lastMessage,omitempty"`
139
- AdminURL string `json:"adminUrl,omitempty"`
140
- ContactPoints NamespacedResourceList `json:"contactPoints,omitempty"`
141
- Dashboards NamespacedResourceList `json:"dashboards,omitempty"`
142
- Datasources NamespacedResourceList `json:"datasources,omitempty"`
143
- Folders NamespacedResourceList `json:"folders,omitempty"`
144
- LibraryPanels NamespacedResourceList `json:"libraryPanels,omitempty"`
145
- Version string `json:"version,omitempty"`
223
+ Stage OperatorStageName `json:"stage,omitempty"`
224
+ StageStatus OperatorStageStatus `json:"stageStatus,omitempty"`
225
+ LastMessage string `json:"lastMessage,omitempty"`
226
+ AdminURL string `json:"adminUrl,omitempty"`
227
+ ContactPoints NamespacedResourceList `json:"contactPoints,omitempty"`
228
+ Dashboards NamespacedResourceList `json:"dashboards,omitempty"`
229
+ Datasources NamespacedResourceList `json:"datasources,omitempty"`
230
+ Folders NamespacedResourceList `json:"folders,omitempty"`
231
+ LibraryPanels NamespacedResourceList `json:"libraryPanels,omitempty"`
232
+ GrafanaServiceAccounts []GrafanaServiceAccountStatus `json:"serviceAccounts,omitempty"`
233
+ Version string `json:"version,omitempty"`
146
234
}
147
235
148
236
// +kubebuilder:object:root=true
0 commit comments