Skip to content

Commit e1872a1

Browse files
Add grafana_service_account_permission_item resource
Part of #1000 Just like #1465
1 parent e58c3df commit e1872a1

File tree

8 files changed

+454
-0
lines changed

8 files changed

+454
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "grafana_service_account_permission_item Resource - terraform-provider-grafana"
4+
subcategory: "Grafana OSS"
5+
description: |-
6+
Manages a single permission item for a service account. Conflicts with the "grafanaserviceaccount_permission" resource which manages the entire set of permissions for a service account.
7+
* Official documentation https://grafana.com/docs/grafana/latest/administration/service-accounts/#manage-users-and-teams-permissions-for-a-service-account-in-grafana
8+
---
9+
10+
# grafana_service_account_permission_item (Resource)
11+
12+
Manages a single permission item for a service account. Conflicts with the "grafana_service_account_permission" resource which manages the entire set of permissions for a service account.
13+
* [Official documentation](https://grafana.com/docs/grafana/latest/administration/service-accounts/#manage-users-and-teams-permissions-for-a-service-account-in-grafana)
14+
15+
## Example Usage
16+
17+
```terraform
18+
resource "grafana_team" "team" {
19+
name = "Team Name"
20+
}
21+
22+
resource "grafana_user" "user" {
23+
24+
login = "user.name"
25+
password = "my-password"
26+
}
27+
28+
resource "grafana_folder" "collection" {
29+
title = "Folder Title"
30+
}
31+
32+
resource "grafana_service_account_permission_item" "on_team" {
33+
service_account_id = grafana_service_account.service_account.id
34+
team = grafana_team.team.id
35+
permission = "View"
36+
}
37+
38+
resource "grafana_service_account_permission_item" "on_user" {
39+
service_account_id = grafana_service_account.service_account.id
40+
user = grafana_user.user.id
41+
permission = "Admin"
42+
}
43+
```
44+
45+
<!-- schema generated by tfplugindocs -->
46+
## Schema
47+
48+
### Required
49+
50+
- `permission` (String) the permission to be assigned
51+
- `service_account_id` (String) The ID of the service account.
52+
53+
### Optional
54+
55+
- `org_id` (String) The Organization ID. If not set, the Org ID defined in the provider block will be used.
56+
- `team` (String) the team onto which the permission is to be assigned
57+
- `user` (String) the user or service account onto which the permission is to be assigned
58+
59+
### Read-Only
60+
61+
- `id` (String) The ID of this resource.
62+
63+
## Import
64+
65+
Import is supported using the following syntax:
66+
67+
```shell
68+
terraform import grafana_service_account_permission_item.name "{{ serviceAccountID }}:{{ type (role, team, or user) }}:{{ identifier }}"
69+
terraform import grafana_service_account_permission_item.name "{{ orgID }}:{{ serviceAccountID }}:{{ type (role, team, or user) }}:{{ identifier }}"
70+
```
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
terraform import grafana_service_account_permission_item.name "{{ serviceAccountID }}:{{ type (role, team, or user) }}:{{ identifier }}"
2+
terraform import grafana_service_account_permission_item.name "{{ orgID }}:{{ serviceAccountID }}:{{ type (role, team, or user) }}:{{ identifier }}"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
resource "grafana_team" "team" {
2+
name = "Team Name"
3+
}
4+
5+
resource "grafana_user" "user" {
6+
7+
login = "user.name"
8+
password = "my-password"
9+
}
10+
11+
resource "grafana_folder" "collection" {
12+
title = "Folder Title"
13+
}
14+
15+
resource "grafana_service_account_permission_item" "on_team" {
16+
service_account_id = grafana_service_account.service_account.id
17+
team = grafana_team.team.id
18+
permission = "View"
19+
}
20+
21+
resource "grafana_service_account_permission_item" "on_user" {
22+
service_account_id = grafana_service_account.service_account.id
23+
user = grafana_user.user.id
24+
permission = "Admin"
25+
}
26+

internal/resources/grafana/common_resource_permission.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ func (r *resourcePermissionBase) readItem(id string, checkExistsFunc func(client
161161
func (r *resourcePermissionBase) writeItem(itemID string, data *resourcePermissionItemBaseModel) diag.Diagnostics {
162162
client, orgID := r.clientFromNewOrgResource(data.OrgID.ValueString())
163163
data.OrgID = types.StringValue(strconv.FormatInt(orgID, 10))
164+
_, itemID = SplitOrgResourceID(itemID)
164165
data.ResourceID = types.StringValue(itemID)
165166

166167
var err error
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package grafana
2+
3+
import (
4+
"context"
5+
"strconv"
6+
7+
"github.com/grafana/grafana-openapi-client-go/client"
8+
"github.com/grafana/terraform-provider-grafana/v2/internal/common"
9+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
10+
"github.com/hashicorp/terraform-plugin-framework/path"
11+
"github.com/hashicorp/terraform-plugin-framework/resource"
12+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
13+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
14+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
15+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
16+
"github.com/hashicorp/terraform-plugin-framework/types"
17+
)
18+
19+
var (
20+
resourceServiceAccountPermissionItemName = "grafana_service_account_permission_item"
21+
resourceServiceAccountPermissionItemID = common.NewResourceID(common.OptionalIntIDField("orgID"), common.StringIDField("serviceAccountID"), common.StringIDField("type (role, team, or user)"), common.StringIDField("identifier"))
22+
23+
// Check interface
24+
_ resource.ResourceWithImportState = (*resourceServiceAccountPermissionItem)(nil)
25+
)
26+
27+
func makeResourceServiceAccountPermissionItem() *common.Resource {
28+
resourceStruct := &resourceServiceAccountPermissionItem{
29+
resourcePermissionBase: resourcePermissionBase{
30+
resourceType: serviceAccountsPermissionsType,
31+
},
32+
}
33+
return common.NewResource(resourceServiceAccountPermissionItemName, resourceServiceAccountPermissionItemID, resourceStruct)
34+
}
35+
36+
type resourceServiceAccountPermissionItemModel struct {
37+
ID types.String `tfsdk:"id"`
38+
OrgID types.String `tfsdk:"org_id"`
39+
Team types.String `tfsdk:"team"`
40+
User types.String `tfsdk:"user"`
41+
Permission types.String `tfsdk:"permission"`
42+
ServiceAccountID types.String `tfsdk:"service_account_id"`
43+
}
44+
45+
// Framework doesn't support embedding a base struct: https://github.com/hashicorp/terraform-plugin-framework/issues/242
46+
func (m *resourceServiceAccountPermissionItemModel) ToBase() *resourcePermissionItemBaseModel {
47+
return &resourcePermissionItemBaseModel{
48+
ID: m.ID,
49+
OrgID: m.OrgID,
50+
Team: m.Team,
51+
User: m.User,
52+
Permission: m.Permission,
53+
}
54+
}
55+
56+
func (m *resourceServiceAccountPermissionItemModel) SetFromBase(base *resourcePermissionItemBaseModel) {
57+
m.ServiceAccountID = base.ResourceID
58+
m.ID = base.ID
59+
m.OrgID = base.OrgID
60+
m.Team = base.Team
61+
m.User = base.User
62+
m.Permission = base.Permission
63+
}
64+
65+
type resourceServiceAccountPermissionItem struct{ resourcePermissionBase }
66+
67+
func (r *resourceServiceAccountPermissionItem) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
68+
resp.TypeName = resourceServiceAccountPermissionItemName
69+
}
70+
71+
func (r *resourceServiceAccountPermissionItem) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
72+
resp.Schema = schema.Schema{
73+
MarkdownDescription: `Manages a single permission item for a service account. Conflicts with the "grafana_service_account_permission" resource which manages the entire set of permissions for a service account.
74+
* [Official documentation](https://grafana.com/docs/grafana/latest/administration/service-accounts/#manage-users-and-teams-permissions-for-a-service-account-in-grafana)`,
75+
Attributes: r.addInSchemaAttributes(map[string]schema.Attribute{
76+
"service_account_id": schema.StringAttribute{
77+
Required: true,
78+
Description: "The ID of the service account.",
79+
PlanModifiers: []planmodifier.String{
80+
stringplanmodifier.RequiresReplace(),
81+
&orgScopedAttributePlanModifier{},
82+
},
83+
},
84+
}),
85+
}
86+
87+
// Role is not supported for service account permissions
88+
delete(resp.Schema.Attributes, permissionTargetRole)
89+
for key, attr := range resp.Schema.Attributes {
90+
if key != permissionTargetTeam && key != permissionTargetUser {
91+
continue
92+
}
93+
attrCast := attr.(schema.StringAttribute)
94+
attrCast.Validators = []validator.String{stringvalidator.ExactlyOneOf(
95+
path.MatchRoot(permissionTargetTeam),
96+
path.MatchRoot(permissionTargetUser),
97+
)}
98+
resp.Schema.Attributes[key] = attrCast
99+
}
100+
}
101+
102+
func (r *resourceServiceAccountPermissionItem) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
103+
readData, diags := r.readItem(req.ID, r.serviceAccountQuery)
104+
if diags != nil {
105+
resp.Diagnostics = diags
106+
return
107+
}
108+
if readData == nil {
109+
resp.Diagnostics.AddError("Resource not found", "Resource not found")
110+
return
111+
}
112+
var data resourceServiceAccountPermissionItemModel
113+
data.SetFromBase(readData)
114+
115+
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
116+
}
117+
118+
func (r *resourceServiceAccountPermissionItem) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
119+
// Read Terraform plan data into the model
120+
var data resourceServiceAccountPermissionItemModel
121+
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
122+
if resp.Diagnostics.HasError() {
123+
return
124+
}
125+
base := data.ToBase()
126+
if diags := r.writeItem(data.ServiceAccountID.ValueString(), base); diags != nil {
127+
resp.Diagnostics = diags
128+
return
129+
}
130+
base.ResourceID = data.ServiceAccountID
131+
data.SetFromBase(base)
132+
133+
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
134+
}
135+
136+
func (r *resourceServiceAccountPermissionItem) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
137+
// Read Terraform state data into the model
138+
var data resourceServiceAccountPermissionItemModel
139+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
140+
141+
// Read from API
142+
readData, diags := r.readItem(data.ID.ValueString(), r.serviceAccountQuery)
143+
if diags != nil {
144+
resp.Diagnostics = diags
145+
return
146+
}
147+
if readData == nil {
148+
resp.State.RemoveResource(ctx)
149+
return
150+
}
151+
readData.ResourceID = data.ServiceAccountID
152+
data.SetFromBase(readData)
153+
154+
// Save data into Terraform state
155+
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
156+
}
157+
158+
func (r *resourceServiceAccountPermissionItem) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
159+
// Read Terraform plan data into the model
160+
var data resourceServiceAccountPermissionItemModel
161+
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
162+
if resp.Diagnostics.HasError() {
163+
return
164+
}
165+
base := data.ToBase()
166+
if diags := r.writeItem(data.ServiceAccountID.ValueString(), base); diags != nil {
167+
resp.Diagnostics = diags
168+
return
169+
}
170+
base.ResourceID = data.ServiceAccountID
171+
data.SetFromBase(base)
172+
173+
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
174+
}
175+
176+
func (r *resourceServiceAccountPermissionItem) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
177+
// Read Terraform prior state data into the model
178+
var data resourceServiceAccountPermissionItemModel
179+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
180+
data.Permission = types.StringValue("")
181+
182+
if diags := r.writeItem(data.ServiceAccountID.ValueString(), data.ToBase()); diags != nil {
183+
resp.Diagnostics = diags
184+
}
185+
}
186+
187+
func (r *resourceServiceAccountPermissionItem) serviceAccountQuery(client *client.GrafanaHTTPAPI, serviceAccountID string) error {
188+
idNumerical, err := strconv.ParseInt(serviceAccountID, 10, 64)
189+
if err != nil {
190+
return err
191+
}
192+
_, err = client.ServiceAccounts.RetrieveServiceAccount(idNumerical)
193+
return err
194+
}

0 commit comments

Comments
 (0)