Skip to content

Commit 8c50c85

Browse files
committed
astra token generation, resource & data source
1 parent e464713 commit 8c50c85

File tree

9 files changed

+332
-1
lines changed

9 files changed

+332
-1
lines changed

docs/resources/token.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "astra_token Resource - terraform-provider-astra"
4+
subcategory: ""
5+
description: |-
6+
astra_token resource represents a token with a specific role assigned.
7+
---
8+
9+
# astra_token (Resource)
10+
11+
`astra_token` resource represents a token with a specific role assigned.
12+
13+
## Example Usage
14+
15+
```terraform
16+
resource "astra_token" "example" {
17+
roles = ["puppies"]
18+
}
19+
```
20+
21+
<!-- schema generated by tfplugindocs -->
22+
## Schema
23+
24+
### Required
25+
26+
- **roles** (List of String) Roles for generated token
27+
28+
### Optional
29+
30+
- **id** (String) The ID of this resource.
31+
32+
### Read-Only
33+
34+
- **client_id** (String) Client id, use as username in cql to connect
35+
- **secret** (String) Secret, use as password in cql to connect
36+
- **token** (String) Token, use as auth bearer for API calls or as password in combination with the word `token` in cql
37+
38+
## Import
39+
40+
Import is supported using the following syntax:
41+
42+
```shell
43+
terraform import astra_token.example client-secret
44+
```
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
data "astra_token" "dev" {
2+
client_id = "client-id-here"
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
terraform import astra_token.example client-secret
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
resource "astra_token" "example" {
2+
roles = ["puppies"]
3+
}

internal/provider/data_source_role.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ func dataSourceRole() *schema.Resource {
1212
return &schema.Resource{
1313
Description: "`astra_role` provides a datasource that lists the custom roles for an org.",
1414

15-
ReadContext: dataSourceAccessListRead,
15+
ReadContext: dataSourceRoleRead,
1616

1717
Schema: map[string]*schema.Schema{
1818
// Required
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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+
"strings"
10+
)
11+
12+
func dataSourceToken() *schema.Resource {
13+
return &schema.Resource{
14+
Description: "`astra_token` provides a datasource that lists client tokens.",
15+
16+
ReadContext: dataSourceTokenRead,
17+
18+
Schema: map[string]*schema.Schema{
19+
// Required
20+
"client_id": {
21+
Description: "Client ID, system generated",
22+
Type: schema.TypeString,
23+
Required: true,
24+
},
25+
26+
// Computed
27+
"results": {
28+
Type: schema.TypeList,
29+
Description: "The list of private links that match the search criteria.",
30+
Computed: true,
31+
Elem: &schema.Resource{
32+
Schema: map[string]*schema.Schema{
33+
"client_id": {
34+
Description: "Role name",
35+
Type: schema.TypeString,
36+
Required: true,
37+
ForceNew: true,
38+
},
39+
"roles": {
40+
Description: "Roles for this client",
41+
Type: schema.TypeList,
42+
Required: true,
43+
ForceNew: true,
44+
Elem: &schema.Schema{
45+
Type: schema.TypeString,
46+
},
47+
},
48+
49+
},
50+
},
51+
},
52+
},
53+
}
54+
}
55+
56+
func dataSourceTokenRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
57+
fmt.Printf("token data source")
58+
59+
client := meta.(*astra.ClientWithResponses)
60+
61+
clientID := d.Get("client_id").(string)
62+
63+
token, err := listRole(ctx, client, clientID)
64+
if err != nil {
65+
return diag.FromErr(err)
66+
}
67+
68+
id := token["client_id"].(string)
69+
d.SetId(id)
70+
if err := d.Set("results", token); err != nil {
71+
return diag.FromErr(err)
72+
}
73+
74+
75+
return nil
76+
}
77+
78+
func listToken(ctx context.Context, client *astra.ClientWithResponses, clientID string) (map[string]interface{}, error) {
79+
resp, err := client.GetClientsForOrgWithResponse(ctx)
80+
if err != nil {
81+
return nil, err
82+
}
83+
84+
tokens := (*resp.JSON200).(map[string]interface{})["clients"].([]interface{})
85+
86+
for _, v := range tokens {
87+
token := v.(map[string]interface{})
88+
if strings.EqualFold(token["clientId"].(string), clientID) {
89+
token["client_id"] = token["clientId"]
90+
delete(token, "clientId")
91+
return token, nil
92+
}
93+
}
94+
95+
return nil, err
96+
}

internal/provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func New(version string) func() *schema.Provider {
4949
"astra_private_link_endpoint": resourcePrivateLinkEndpoint(),
5050
"astra_access_list": resourceAccessList(),
5151
"astra_role": resourceRole(),
52+
"astra_token": resourceToken(),
5253
},
5354
Schema: map[string]*schema.Schema{
5455
"token": {
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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 resourceToken() *schema.Resource {
15+
return &schema.Resource{
16+
Description: "`astra_token` resource represents a token with a specific role assigned.",
17+
CreateContext: resourceTokenCreate,
18+
ReadContext: resourceTokenRead,
19+
DeleteContext: resourceTokenDelete,
20+
21+
Importer: &schema.ResourceImporter{
22+
StateContext: schema.ImportStatePassthroughContext,
23+
},
24+
25+
Schema: map[string]*schema.Schema{
26+
// Required
27+
"roles": {
28+
Description: "Roles for generated token",
29+
Type: schema.TypeList,
30+
Required: true,
31+
ForceNew: true,
32+
Elem: &schema.Schema{
33+
Type: schema.TypeString,
34+
},
35+
},
36+
"client_id": {
37+
Description: "Client id, use as username in cql to connect",
38+
Type: schema.TypeString,
39+
Computed: true,
40+
},
41+
"secret": {
42+
Description: "Secret, use as password in cql to connect",
43+
Type: schema.TypeString,
44+
Computed: true,
45+
},
46+
"token": {
47+
Description: "Token, use as auth bearer for API calls or as password in combination with the word `token` in cql",
48+
Type: schema.TypeString,
49+
Computed: true,
50+
},
51+
52+
53+
},
54+
}
55+
}
56+
57+
func resourceTokenCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
58+
client := meta.(*astra.ClientWithResponses)
59+
60+
roles := d.Get("roles").([]interface{})
61+
62+
rolesList := make([]string, len(roles))
63+
64+
for k, v := range roles {
65+
rolesList[k] = v.(string)
66+
}
67+
68+
tokenJSON := astra.GenerateTokenForClientJSONRequestBody{
69+
Roles: rolesList,
70+
}
71+
resp, err := client.GenerateTokenForClientWithResponse(ctx,
72+
tokenJSON,
73+
)
74+
75+
if err != nil {
76+
return diag.FromErr(err)
77+
} else if resp.StatusCode() >= 400 {
78+
return diag.Errorf("error adding role to org: %s", resp.Body)
79+
}
80+
81+
token := (*resp.JSON200).(map[string]interface{})
82+
if err := setTokenData(d, token); err != nil {
83+
return diag.FromErr(err)
84+
}
85+
86+
87+
return nil
88+
}
89+
90+
func resourceTokenDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
91+
client := meta.(*astra.ClientWithResponses)
92+
93+
id := d.Id()
94+
95+
clientID, err := parseTokenID(id)
96+
if err != nil {
97+
return diag.FromErr(err)
98+
}
99+
100+
client.DeleteTokenForClient(ctx, astra.ClientIdParam(clientID))
101+
102+
return nil
103+
}
104+
105+
func resourceTokenRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
106+
107+
client := meta.(*astra.ClientWithResponses)
108+
109+
id := d.Id()
110+
111+
clientID, err := parseTokenID(id)
112+
if err != nil {
113+
return diag.FromErr(err)
114+
}
115+
116+
token, err := listToken(ctx, client, clientID)
117+
if err != nil {
118+
return diag.FromErr(err)
119+
}
120+
121+
d.SetId(fmt.Sprintf("%s", clientID))
122+
if err := d.Set("client_id", token["client_id"]); err != nil {
123+
return diag.FromErr(err)
124+
}
125+
126+
return nil
127+
128+
}
129+
130+
func setTokenData(d *schema.ResourceData, tokenMap map[string]interface{}) error {
131+
clientID := tokenMap["clientId"].(string)
132+
secret:= tokenMap["secret"].(string)
133+
token := tokenMap["token"].(string)
134+
135+
d.SetId(fmt.Sprintf("%s", clientID))
136+
137+
if err := d.Set("client_id", clientID); err != nil {
138+
return err
139+
}
140+
if err := d.Set("secret", secret); err != nil {
141+
return err
142+
}
143+
if err := d.Set("token", token); err != nil {
144+
return err
145+
}
146+
147+
return nil
148+
}
149+
150+
func parseTokenID(id string) (string, error) {
151+
idParts := strings.Split(strings.ToLower(id), "/")
152+
if len(idParts) != 1 {
153+
return "", errors.New("invalid token id format: expected clientID/")
154+
}
155+
return idParts[0], nil
156+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package provider
2+
3+
import (
4+
"fmt"
5+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
6+
"testing"
7+
)
8+
9+
func TestToken(t *testing.T){
10+
resource.Test(t, resource.TestCase{
11+
PreCheck: func() { testAccPreCheck(t) },
12+
Providers: testAccProviders,
13+
Steps: []resource.TestStep{
14+
{
15+
Config: testAccTokenConfiguration(),
16+
},
17+
},
18+
})
19+
}
20+
21+
func testAccTokenConfiguration() string {
22+
return fmt.Sprintf(`
23+
resource "astra_token" "example" {
24+
roles = ["puppies"]
25+
}
26+
`)
27+
}

0 commit comments

Comments
 (0)