Skip to content

Commit 8843908

Browse files
committed
roles
1 parent aef8a8b commit 8843908

File tree

4 files changed

+326
-0
lines changed

4 files changed

+326
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/datastax/astra-client-go/v2/astra"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
)
10+
11+
func dataSourceRole() *schema.Resource {
12+
return &schema.Resource{
13+
Description: "`astra_role` provides a datasource that lists the custom roles for an org.",
14+
15+
ReadContext: dataSourceAccessListRead,
16+
17+
Schema: map[string]*schema.Schema{
18+
// Required
19+
"role_id": {
20+
Description: "Role ID, system generated",
21+
Type: schema.TypeString,
22+
Required: true,
23+
},
24+
25+
// Computed
26+
"results": {
27+
Type: schema.TypeList,
28+
Description: "The list of private links that match the search criteria.",
29+
Computed: true,
30+
Elem: &schema.Resource{
31+
Schema: map[string]*schema.Schema{
32+
"role_name": {
33+
Description: "Role name",
34+
Type: schema.TypeString,
35+
Required: true,
36+
ForceNew: true,
37+
},
38+
"description": {
39+
Description: "Role description",
40+
Type: schema.TypeString,
41+
Required: true,
42+
ForceNew: true,
43+
},
44+
"effect": {
45+
Description: "Role effect",
46+
Type: schema.TypeString,
47+
Required: true,
48+
ForceNew: true,
49+
},
50+
"resources": {
51+
Description: "Resources for which role is applicable",
52+
Type: schema.TypeList,
53+
Required: true,
54+
ForceNew: true,
55+
Elem: &schema.Schema{
56+
Type: schema.TypeString,
57+
},
58+
},
59+
60+
"policy": {
61+
Description: "List of policies for the role.",
62+
Type: schema.TypeList,
63+
Required: true,
64+
ForceNew: true,
65+
Elem: &schema.Schema{
66+
Type: schema.TypeString,
67+
},
68+
},
69+
},
70+
},
71+
},
72+
},
73+
}
74+
}
75+
76+
func dataSourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
77+
fmt.Printf("role data source")
78+
79+
client := meta.(*astra.ClientWithResponses)
80+
81+
roleID := d.Get("role_id").(string)
82+
83+
role, err := listRole(ctx, client, roleID)
84+
if err != nil {
85+
return diag.FromErr(err)
86+
}
87+
88+
id := role["id"].(string)
89+
d.SetId(id)
90+
if err := d.Set("results", role); err != nil {
91+
return diag.FromErr(err)
92+
}
93+
94+
95+
return nil
96+
}
97+
98+
func listRole(ctx context.Context, client *astra.ClientWithResponses, roleID string) (map[string]interface{}, error) {
99+
resp, err := client.GetOrganizationRoleWithResponse(ctx, astra.RoleIdParam(roleID))
100+
if err != nil {
101+
return nil, err
102+
}
103+
104+
roleRaw := (*resp.JSON200).(map[string]interface{})
105+
106+
return roleRaw, err
107+
}

internal/provider/provider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@ func New(version string) func() *schema.Provider {
4040
"astra_private_links": dataSourcePrivateLinks(),
4141
"astra_private_link_endpoints": dataSourcePrivateLinkEndpoints(),
4242
"astra_access_list": dataSourceAccessList(),
43+
"astra_role": dataSourceRole(),
4344
},
4445
ResourcesMap: map[string]*schema.Resource{
4546
"astra_database": resourceDatabase(),
4647
"astra_keyspace": resourceKeyspace(),
4748
"astra_private_link": resourcePrivateLink(),
4849
"astra_private_link_endpoint": resourcePrivateLinkEndpoint(),
4950
"astra_access_list": resourceAccessList(),
51+
"astra_role": resourceRole(),
5052
},
5153
Schema: map[string]*schema.Schema{
5254
"token": {

internal/provider/resource_role.go

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"strings"
8+
9+
"github.com/datastax/astra-client-go/v2/astra"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
12+
)
13+
14+
func resourceRole() *schema.Resource {
15+
return &schema.Resource{
16+
Description: "`astra_role` resource represents custom roles for a particular Astra Org. Custom roles can be assigned to an Astra user is to grant them granular permissions when the default roles in the UI are not specific enough. Roles are composed of policies which are granted to resources.",
17+
CreateContext: resourceRoleCreate,
18+
ReadContext: resourceRoleRead,
19+
DeleteContext: resourceRoleDelete,
20+
21+
Importer: &schema.ResourceImporter{
22+
StateContext: schema.ImportStatePassthroughContext,
23+
},
24+
25+
Schema: map[string]*schema.Schema{
26+
// Required
27+
"role_name": {
28+
Description: "Role name",
29+
Type: schema.TypeString,
30+
Required: true,
31+
ForceNew: true,
32+
},
33+
"description": {
34+
Description: "Role description",
35+
Type: schema.TypeString,
36+
Required: true,
37+
ForceNew: true,
38+
},
39+
"effect": {
40+
Description: "Role effect",
41+
Type: schema.TypeString,
42+
Required: true,
43+
ForceNew: true,
44+
},
45+
"resources": {
46+
Description: "Resources for which role is applicable",
47+
Type: schema.TypeList,
48+
Required: true,
49+
ForceNew: true,
50+
Elem: &schema.Schema{
51+
Type: schema.TypeString,
52+
},
53+
},
54+
55+
"policy": {
56+
Description: "List of policies for the role.",
57+
Type: schema.TypeList,
58+
Required: true,
59+
ForceNew: true,
60+
Elem: &schema.Schema{
61+
Type: schema.TypeString,
62+
},
63+
},
64+
"role_id": {
65+
Description: "Role ID, system generated",
66+
Type: schema.TypeString,
67+
Computed: true,
68+
ForceNew: true,
69+
},
70+
},
71+
}
72+
}
73+
74+
func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
75+
client := meta.(*astra.ClientWithResponses)
76+
77+
roleName := d.Get("role_name").(string)
78+
description := d.Get("description").(string)
79+
effect := d.Get("effect").(string)
80+
resourcesRaw := d.Get("resources").([]interface{})
81+
policyRaw := d.Get("policy")
82+
83+
actions := policyRaw.([]interface{})
84+
85+
86+
resourcesList := make([]string, len(actions))
87+
actionsList := make([]astra.PolicyActions, len(actions))
88+
89+
for k, v := range resourcesRaw {
90+
resourcesList[k] = v.(string)
91+
}
92+
for k, v := range policyRaw.([]interface{}) {
93+
actionsList[k] = astra.PolicyActions(v.(string))
94+
}
95+
policy := astra.Policy{
96+
Actions: actionsList,
97+
Description: description,
98+
Effect: astra.PolicyEffect(effect),
99+
Resources: resourcesList,
100+
}
101+
102+
103+
roleJSON := astra.AddOrganizationRoleJSONRequestBody{
104+
Name: roleName,
105+
Policy: policy,
106+
}
107+
resp, err := client.AddOrganizationRoleWithResponse(ctx,
108+
roleJSON,
109+
)
110+
111+
if err != nil {
112+
return diag.FromErr(err)
113+
} else if resp.StatusCode() >= 400 {
114+
return diag.Errorf("error adding role to org: %s", resp.Body)
115+
}
116+
117+
role := resp.JSON201
118+
if err := setRoleData(d, *role.Id); err != nil {
119+
return diag.FromErr(err)
120+
}
121+
122+
return nil
123+
}
124+
125+
func resourceRoleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
126+
client := meta.(*astra.ClientWithResponses)
127+
128+
id := d.Id()
129+
130+
roleID, err := parseRoleID(id)
131+
if err != nil {
132+
return diag.FromErr(err)
133+
}
134+
135+
roleParam := astra.RoleIdParam(roleID)
136+
client.DeleteOrganizationRoleWithResponse(ctx, roleParam)
137+
138+
return nil
139+
}
140+
141+
func resourceRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
142+
client := meta.(*astra.ClientWithResponses)
143+
144+
id := d.Id()
145+
146+
roleID, err := parseRoleID(id)
147+
if err != nil {
148+
return diag.FromErr(err)
149+
}
150+
151+
role, err := listRole(ctx, client, roleID)
152+
if err != nil {
153+
return diag.FromErr(err)
154+
}
155+
156+
157+
if role["id"].(string) == roleID {
158+
if err := setRoleData(d, roleID); err != nil {
159+
return diag.FromErr(err)
160+
}
161+
return nil
162+
}
163+
164+
// Not found. Remove from state.
165+
d.SetId("")
166+
167+
return nil
168+
}
169+
170+
func setRoleData(d *schema.ResourceData, roleID string) error {
171+
d.SetId(fmt.Sprintf("%s", roleID))
172+
173+
if err := d.Set("role_id", roleID); err != nil {
174+
return err
175+
}
176+
177+
return nil
178+
}
179+
180+
func parseRoleID(id string) (string, error) {
181+
idParts := strings.Split(strings.ToLower(id), "/")
182+
if len(idParts) != 1 {
183+
return "", errors.New("invalid role id format: expected roleID/")
184+
}
185+
return idParts[0], nil
186+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package provider
2+
3+
import (
4+
"fmt"
5+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
6+
"testing"
7+
)
8+
9+
func TestRole(t *testing.T){
10+
resource.Test(t, resource.TestCase{
11+
PreCheck: func() { testAccPreCheck(t) },
12+
Providers: testAccProviders,
13+
Steps: []resource.TestStep{
14+
{
15+
Config: testAccRoleConfiguration(),
16+
},
17+
},
18+
})
19+
}
20+
21+
func testAccRoleConfiguration() string {
22+
return fmt.Sprintf(`
23+
resource "astra_role" "example" {
24+
role_name = "puppies"
25+
description = "test role"
26+
effect = "allow"
27+
resources = ["drn:astra:org:f9f4b1e0-4c05-451e-9bba-d631295a7f73"]
28+
policy = ["db-all-keyspace-create"]
29+
}
30+
`)
31+
}

0 commit comments

Comments
 (0)