Skip to content

Commit 44516fc

Browse files
committed
wip
1 parent 2533d2c commit 44516fc

16 files changed

+1667
-9
lines changed

api/v1beta1/grafana_types.go

+10-9
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,16 @@ type GrafanaPreferences struct {
131131

132132
// GrafanaStatus defines the observed state of Grafana
133133
type GrafanaStatus struct {
134-
Stage OperatorStageName `json:"stage,omitempty"`
135-
StageStatus OperatorStageStatus `json:"stageStatus,omitempty"`
136-
LastMessage string `json:"lastMessage,omitempty"`
137-
AdminUrl string `json:"adminUrl,omitempty"`
138-
Dashboards NamespacedResourceList `json:"dashboards,omitempty"`
139-
Datasources NamespacedResourceList `json:"datasources,omitempty"`
140-
Folders NamespacedResourceList `json:"folders,omitempty"`
141-
LibraryPanels NamespacedResourceList `json:"libraryPanels,omitempty"`
142-
Version string `json:"version,omitempty"`
134+
Stage OperatorStageName `json:"stage,omitempty"`
135+
StageStatus OperatorStageStatus `json:"stageStatus,omitempty"`
136+
LastMessage string `json:"lastMessage,omitempty"`
137+
AdminUrl string `json:"adminUrl,omitempty"`
138+
Dashboards NamespacedResourceList `json:"dashboards,omitempty"`
139+
Datasources NamespacedResourceList `json:"datasources,omitempty"`
140+
ServiceAccounts NamespacedResourceList `json:"serviceaccounts,omitempty"`
141+
Folders NamespacedResourceList `json:"folders,omitempty"`
142+
LibraryPanels NamespacedResourceList `json:"libraryPanels,omitempty"`
143+
Version string `json:"version,omitempty"`
143144
}
144145

145146
// +kubebuilder:object:root=true
+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
Copyright 2025.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1beta1
18+
19+
import (
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
)
22+
23+
// GrafanaServiceAccountToken defines a token to be created for a Grafana service account.
24+
type GrafanaServiceAccountToken struct {
25+
// Name is the name of the Kubernetes Secret in which this token will be stored.
26+
// +kubebuilder:validation:Required
27+
Name string `json:"name"`
28+
29+
// Expires specifies the expiration timestamp (TTL) for this token. If set, the operator
30+
// will rotate or replace the token once the specified expiration time is reached.
31+
// If not set, the token does not expire (defaults to never expire).
32+
// +kubebuilder:validation:Optional
33+
Expires *metav1.Time `json:"expires,omitempty"`
34+
}
35+
36+
// GrafanaServiceAccountTokenStatus describes the current state of a token that was created in Grafana.
37+
type GrafanaServiceAccountTokenStatus struct {
38+
// Name is the name of the token, matching the one specified in .spec.tokens or generated automatically.
39+
Name string `json:"name"`
40+
41+
// TokenID is the numeric identifier of the token as returned by Grafana upon creation.
42+
TokenID int64 `json:"tokenId"`
43+
44+
// SecretName is the name of the Kubernetes Secret that stores the actual token value (Key).
45+
SecretName string `json:"secretName"`
46+
}
47+
48+
// GrafanaServiceAccountPermission defines a permission grant for a user or group related to this service account.
49+
type GrafanaServiceAccountPermission struct {
50+
// +kubebuilder:validation:Optional
51+
User string `json:"user"`
52+
53+
// +kubebuilder:validation:Optional
54+
Team string `json:"team"`
55+
56+
// Permission is the level of access granted to that user or group for this service account
57+
// (e.g., "Edit" or "Admin"). Depending on the Grafana version, this might map to an RBAC role or other permissions.
58+
// +kubebuilder:validation:Required
59+
// +kubebuilder:validation:Enum=Viewer;Editor;Admin
60+
Permission string `json:"permission"`
61+
}
62+
63+
// GrafanaServiceAccountSpec defines the desired state of a GrafanaServiceAccount.
64+
type GrafanaServiceAccountSpec struct {
65+
GrafanaCommonSpec `json:",inline"`
66+
67+
// Name is the name of the service account in Grafana.
68+
// +kubebuilder:validation:Required
69+
Name string `json:"name,omitempty"`
70+
71+
// Role is the service account role in Grafana (Viewer, Editor, Admin, etc.).
72+
// +kubebuilder:validation:Required
73+
// +kubebuilder:validation:Enum=Viewer;Editor;Admin
74+
Role string `json:"role,omitempty"`
75+
76+
// IsDisabled indicates whether the service account should be disabled in Grafana.
77+
// +kubebuilder:validation:Optional
78+
IsDisabled bool `json:"isDisabled,omitempty"`
79+
80+
// Tokens is the list of tokens to create for this service account. For each token in the list,
81+
// the operator generates a Grafana access token and stores it in a Kubernetes Secret with the specified name.
82+
// If no tokens are specified and GenerateTokenSecret is true, the operator creates a default token
83+
// in a Secret with a default name.
84+
// +kubebuilder:validation:Optional
85+
Tokens []GrafanaServiceAccountToken `json:"tokens,omitempty"`
86+
87+
// Permissions specifies additional access permissions for users or teams in Grafana
88+
// related to this service account. This aligns with the UI where you can grant specific
89+
// users or groups Edit/Admin permissions on the service account.
90+
// +kubebuilder:validation:Optional
91+
Permissions []GrafanaServiceAccountPermission `json:"permissions,omitempty"`
92+
93+
// GenerateTokenSecret indicates whether the operator should automatically create a Kubernetes Secret
94+
// to store a token for this service account. If true (default), at least one Secret with a token will be created.
95+
// If false, no token is generated unless explicitly defined in Tokens.
96+
// +kubebuilder:default=true
97+
GenerateTokenSecret bool `json:"generateTokenSecret,omitempty"`
98+
}
99+
100+
// GrafanaServiceAccountStatus defines the observed state of a GrafanaServiceAccount.
101+
type GrafanaServiceAccountStatus struct {
102+
GrafanaCommonStatus `json:",inline"`
103+
104+
// ID is the numeric identifier of the service account in Grafana.
105+
ID int64 `json:"id,omitempty"`
106+
107+
// Tokens is a list of detailed information for each token created in Grafana.
108+
// +optional
109+
Tokens []GrafanaServiceAccountTokenStatus `json:"tokens,omitempty"`
110+
}
111+
112+
//+kubebuilder:object:root=true
113+
//+kubebuilder:subresource:status
114+
115+
// GrafanaServiceAccount is the Schema for the grafanaserviceaccounts API.
116+
// +kubebuilder:printcolumn:name="Last resync",type="date",format="date-time",JSONPath=".status.lastResync",description=""
117+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description=""
118+
// +kubebuilder:resource:categories={grafana-operator}
119+
type GrafanaServiceAccount struct {
120+
metav1.TypeMeta `json:",inline"`
121+
metav1.ObjectMeta `json:"metadata,omitempty"`
122+
123+
Spec GrafanaServiceAccountSpec `json:"spec,omitempty"`
124+
Status GrafanaServiceAccountStatus `json:"status,omitempty"`
125+
}
126+
127+
//+kubebuilder:object:root=true
128+
129+
// GrafanaServiceAccountList contains a list of GrafanaServiceAccount objects.
130+
type GrafanaServiceAccountList struct {
131+
metav1.TypeMeta `json:",inline"`
132+
metav1.ListMeta `json:"metadata,omitempty"`
133+
Items []GrafanaServiceAccount `json:"items"`
134+
}
135+
136+
// Find searches for a GrafanaServiceAccount by namespace/name in the list.
137+
func (in *GrafanaServiceAccountList) Find(namespace, name string) *GrafanaServiceAccount {
138+
for _, serviceAccount := range in.Items {
139+
if serviceAccount.Namespace == namespace && serviceAccount.Name == name {
140+
return &serviceAccount
141+
}
142+
}
143+
return nil
144+
}
145+
146+
// MatchLabels returns the LabelSelector (from GrafanaCommonSpec) to find matching Grafana instances.
147+
func (in *GrafanaServiceAccount) MatchLabels() *metav1.LabelSelector {
148+
return in.Spec.InstanceSelector
149+
}
150+
151+
// MatchNamespace returns the namespace where this service account is defined.
152+
func (in *GrafanaServiceAccount) MatchNamespace() string {
153+
return in.ObjectMeta.Namespace
154+
}
155+
156+
// AllowCrossNamespace indicates whether cross-namespace import is allowed for this resource.
157+
func (in *GrafanaServiceAccount) AllowCrossNamespace() bool {
158+
return in.Spec.AllowCrossNamespaceImport
159+
}
160+
161+
func init() {
162+
SchemeBuilder.Register(&GrafanaServiceAccount{}, &GrafanaServiceAccountList{})
163+
}

api/v1beta1/zz_generated.deepcopy.go

+162
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/grafana.integreatly.org_grafanas.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -9515,6 +9515,10 @@ spec:
95159515
items:
95169516
type: string
95179517
type: array
9518+
serviceaccounts:
9519+
items:
9520+
type: string
9521+
type: array
95189522
stage:
95199523
type: string
95209524
stageStatus:

0 commit comments

Comments
 (0)