Skip to content

Commit 1697d2e

Browse files
ichung08vandyliu
andauthored
Add API Token Resource (#110)
Co-authored-by: Vandy Liu <vandy.liu@astronomer.io>
1 parent 56e00be commit 1697d2e

File tree

15 files changed

+1729
-29
lines changed

15 files changed

+1729
-29
lines changed

.github/workflows/testacc.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ jobs:
9090
SKIP_CLUSTER_RESOURCE_TESTS: ${{ env.SKIP_CLUSTER_RESOURCE_TESTS }}
9191
HOSTED_TEAM_ID: clx44rvzr01nc01o06pze6qb7
9292
HOSTED_USER_ID: clhpichn8002m01mqa4ocs7g6
93-
HOSTED_DEPLOYMENT_ID: clyd4zf7g01uu01oxpve7tfvx
93+
HOSTED_DEPLOYMENT_ID: clyn6kxud003x01mtxmccegnh
9494
HOSTED_WORKSPACE_ID: clx42sxw501gl01o0gjenthnh
9595
HOSTED_API_TOKEN_ID: clxm4836f00ql01me3nigmcr6
9696
TESTARGS: "-failfast"
@@ -186,7 +186,7 @@ jobs:
186186
ASTRO_API_HOST: https://api.astronomer-dev.io
187187
HOSTED_TEAM_ID: clx44rvzr01nc01o06pze6qb7
188188
HOSTED_USER_ID: clhpichn8002m01mqa4ocs7g6
189-
HOSTED_DEPLOYMENT_ID: clyd4zf7g01uu01oxpve7tfvx
189+
HOSTED_DEPLOYMENT_ID: clyn6kxud003x01mtxmccegnh
190190
HOSTED_WORKSPACE_ID: clx42sxw501gl01o0gjenthnh
191191
HOSTED_API_TOKEN_ID: clxm4836f00ql01me3nigmcr6
192192
TESTARGS: "-failfast"

docs/data-sources/api_token.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Read-Only:
6161

6262
- `entity_id` (String) The ID of the entity to assign the role to
6363
- `entity_type` (String) The type of entity to assign the role to
64-
- `role` (String) The role to assign to the deployment
64+
- `role` (String) The role to assign to the entity
6565

6666

6767
<a id="nestedatt--updated_by"></a>

docs/data-sources/api_tokens.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Read-Only:
8484

8585
- `entity_id` (String) The ID of the entity to assign the role to
8686
- `entity_type` (String) The type of entity to assign the role to
87-
- `role` (String) The role to assign to the deployment
87+
- `role` (String) The role to assign to the entity
8888

8989

9090
<a id="nestedatt--api_tokens--updated_by"></a>

docs/resources/api_token.md

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "astro_api_token Resource - astro"
4+
subcategory: ""
5+
description: |-
6+
API Token resource
7+
---
8+
9+
# astro_api_token (Resource)
10+
11+
API Token resource
12+
13+
## Example Usage
14+
15+
```terraform
16+
resource "astro_api_token" "example_organization_token" {
17+
name = "organization api token"
18+
description = "organization api token description"
19+
type = "ORGANIZATION"
20+
roles = [{
21+
"role" : "ORGANIZATION_OWNER",
22+
"entity_id" : "clx42kkcm01fo01o06agtmshg",
23+
"entity_type" : "ORGANIZATION"
24+
}]
25+
expiry_period_in_days = 30
26+
}
27+
28+
resource "astro_api_token" "example_organization_token_with_multiple_roles" {
29+
name = "organization api token with multiple roles"
30+
description = "organization api token description"
31+
type = "ORGANIZATION"
32+
roles = [{
33+
"role" : "ORGANIZATION_OWNER",
34+
"entity_id" : "clx42kkcm01fo01o06agtmshg",
35+
"entity_type" : "ORGANIZATION"
36+
},
37+
{
38+
"role" : "WORKSPACE_OWNER",
39+
"entity_id" : "clx42sxw501gl01o0gjenthnh",
40+
"entity_type" : "WORKSPACE"
41+
},
42+
{
43+
"role" : "DEPLOYMENT_ADMIN",
44+
"entity_id" : "clyn6kxud003x01mtxmccegnh",
45+
"entity_type" : "DEPLOYMENT"
46+
}]
47+
}
48+
49+
resource "astro_api_token" "example_workspace_token" {
50+
name = "workspace api token"
51+
description = "workspace api token description"
52+
type = "WORKSPACE"
53+
roles = [{
54+
"role" : "WORKSPACE_OWNER",
55+
"entity_id" : "clx42sxw501gl01o0gjenthnh",
56+
"entity_type" : "WORKSPACE"
57+
}]
58+
}
59+
60+
resource "astro_api_token" "example_workspace_token_with_deployment_role" {
61+
name = "workspace api token"
62+
description = "workspace api token description"
63+
type = "WORKSPACE"
64+
roles = [{
65+
"role" : "WORKSPACE_OWNER",
66+
"entity_id" : "clx42sxw501gl01o0gjenthnh",
67+
"entity_type" : "WORKSPACE"
68+
},
69+
{
70+
"role" : "DEPLOYMENT_ADMIN",
71+
"entity_id" : "clyn6kxud003x01mtxmccegnh",
72+
"entity_type" : "DEPLOYMENT"
73+
}]
74+
}
75+
76+
resource "astro_api_token" "example_deployment_token" {
77+
name = "deployment api token"
78+
description = "deployment api token description"
79+
type = "DEPLOYMENT"
80+
roles = [{
81+
"role" : "DEPLOYMENT_ADMIN",
82+
"entity_id" : "clyn6kxud003x01mtxmccegnh",
83+
"entity_type" : "DEPLOYMENT"
84+
}]
85+
}
86+
87+
resource "astro_api_token" "example_deployment_token_with_custom_role" {
88+
name = "deployment api token with custom role"
89+
description = "deployment api token description"
90+
type = "DEPLOYMENT"
91+
roles = [{
92+
"role" : "CUSTOM_ROLE",
93+
"entity_id" : "clyn6kxud003x01mtxmccegnh",
94+
"entity_type" : "DEPLOYMENT"
95+
}]
96+
}
97+
```
98+
99+
<!-- schema generated by tfplugindocs -->
100+
## Schema
101+
102+
### Required
103+
104+
- `name` (String) API Token name
105+
- `roles` (Attributes Set) The roles assigned to the API Token (see [below for nested schema](#nestedatt--roles))
106+
- `type` (String) API Token type - if changing this value, the API Token will be recreated with the new type
107+
108+
### Optional
109+
110+
- `description` (String) API Token description
111+
- `expiry_period_in_days` (Number) API Token expiry period in days
112+
113+
### Read-Only
114+
115+
- `created_at` (String) API Token creation timestamp
116+
- `created_by` (Attributes) API Token creator (see [below for nested schema](#nestedatt--created_by))
117+
- `end_at` (String) time when the API token will expire in UTC
118+
- `id` (String) API Token identifier
119+
- `last_used_at` (String) API Token last used timestamp
120+
- `short_token` (String) API Token short token
121+
- `start_at` (String) time when the API token will become valid in UTC
122+
- `token` (String, Sensitive) API Token value. Warning: This value will be saved in plaintext in the terraform state file.
123+
- `updated_at` (String) API Token last updated timestamp
124+
- `updated_by` (Attributes) API Token updater (see [below for nested schema](#nestedatt--updated_by))
125+
126+
<a id="nestedatt--roles"></a>
127+
### Nested Schema for `roles`
128+
129+
Required:
130+
131+
- `entity_id` (String) The ID of the entity to assign the role to
132+
- `entity_type` (String) The type of entity to assign the role to
133+
- `role` (String) The role to assign to the entity
134+
135+
136+
<a id="nestedatt--created_by"></a>
137+
### Nested Schema for `created_by`
138+
139+
Read-Only:
140+
141+
- `api_token_name` (String)
142+
- `avatar_url` (String)
143+
- `full_name` (String)
144+
- `id` (String)
145+
- `subject_type` (String)
146+
- `username` (String)
147+
148+
149+
<a id="nestedatt--updated_by"></a>
150+
### Nested Schema for `updated_by`
151+
152+
Read-Only:
153+
154+
- `api_token_name` (String)
155+
- `avatar_url` (String)
156+
- `full_name` (String)
157+
- `id` (String)
158+
- `subject_type` (String)
159+
- `username` (String)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
resource "astro_api_token" "example_organization_token" {
2+
name = "organization api token"
3+
description = "organization api token description"
4+
type = "ORGANIZATION"
5+
roles = [{
6+
"role" : "ORGANIZATION_OWNER",
7+
"entity_id" : "clx42kkcm01fo01o06agtmshg",
8+
"entity_type" : "ORGANIZATION"
9+
}]
10+
expiry_period_in_days = 30
11+
}
12+
13+
resource "astro_api_token" "example_organization_token_with_multiple_roles" {
14+
name = "organization api token with multiple roles"
15+
description = "organization api token description"
16+
type = "ORGANIZATION"
17+
roles = [{
18+
"role" : "ORGANIZATION_OWNER",
19+
"entity_id" : "clx42kkcm01fo01o06agtmshg",
20+
"entity_type" : "ORGANIZATION"
21+
},
22+
{
23+
"role" : "WORKSPACE_OWNER",
24+
"entity_id" : "clx42sxw501gl01o0gjenthnh",
25+
"entity_type" : "WORKSPACE"
26+
},
27+
{
28+
"role" : "DEPLOYMENT_ADMIN",
29+
"entity_id" : "clyn6kxud003x01mtxmccegnh",
30+
"entity_type" : "DEPLOYMENT"
31+
}]
32+
}
33+
34+
resource "astro_api_token" "example_workspace_token" {
35+
name = "workspace api token"
36+
description = "workspace api token description"
37+
type = "WORKSPACE"
38+
roles = [{
39+
"role" : "WORKSPACE_OWNER",
40+
"entity_id" : "clx42sxw501gl01o0gjenthnh",
41+
"entity_type" : "WORKSPACE"
42+
}]
43+
}
44+
45+
resource "astro_api_token" "example_workspace_token_with_deployment_role" {
46+
name = "workspace api token"
47+
description = "workspace api token description"
48+
type = "WORKSPACE"
49+
roles = [{
50+
"role" : "WORKSPACE_OWNER",
51+
"entity_id" : "clx42sxw501gl01o0gjenthnh",
52+
"entity_type" : "WORKSPACE"
53+
},
54+
{
55+
"role" : "DEPLOYMENT_ADMIN",
56+
"entity_id" : "clyn6kxud003x01mtxmccegnh",
57+
"entity_type" : "DEPLOYMENT"
58+
}]
59+
}
60+
61+
resource "astro_api_token" "example_deployment_token" {
62+
name = "deployment api token"
63+
description = "deployment api token description"
64+
type = "DEPLOYMENT"
65+
roles = [{
66+
"role" : "DEPLOYMENT_ADMIN",
67+
"entity_id" : "clyn6kxud003x01mtxmccegnh",
68+
"entity_type" : "DEPLOYMENT"
69+
}]
70+
}
71+
72+
resource "astro_api_token" "example_deployment_token_with_custom_role" {
73+
name = "deployment api token with custom role"
74+
description = "deployment api token description"
75+
type = "DEPLOYMENT"
76+
roles = [{
77+
"role" : "CUSTOM_ROLE",
78+
"entity_id" : "clyn6kxud003x01mtxmccegnh",
79+
"entity_type" : "DEPLOYMENT"
80+
}]
81+
}

internal/provider/datasources/data_source_api_tokens_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func checkApiTokens(tfVarName string, input checkApiTokensInput) resource.TestCh
162162
if entityId != input.workspaceId {
163163
return fmt.Errorf("expected 'entity_id' to be set to workspace_id")
164164
}
165-
if utils.CheckRole(role, "workspace") {
165+
if utils.ValidateRoleMatchesEntityType(role, "workspace") {
166166
return fmt.Errorf("expected 'role' to be set as a workspace role")
167167
}
168168
}
@@ -183,7 +183,7 @@ func checkApiTokens(tfVarName string, input checkApiTokensInput) resource.TestCh
183183
if entityId != input.organizationId {
184184
return fmt.Errorf("expected 'entity_id' to be set to organization_id")
185185
}
186-
if utils.CheckRole(role, "organization") {
186+
if utils.ValidateRoleMatchesEntityType(role, "organization") {
187187
return fmt.Errorf("expected 'role' to be set as an organization role")
188188
}
189189
}

internal/provider/models/api_token.go

+68
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@ type ApiTokenDataSource struct {
2828
Roles types.Set `tfsdk:"roles"`
2929
}
3030

31+
// ApiTokenResource defines the resource implementation.
32+
type ApiTokenResource struct {
33+
Id types.String `tfsdk:"id"`
34+
Name types.String `tfsdk:"name"`
35+
Description types.String `tfsdk:"description"`
36+
ShortToken types.String `tfsdk:"short_token"`
37+
Type types.String `tfsdk:"type"`
38+
StartAt types.String `tfsdk:"start_at"`
39+
EndAt types.String `tfsdk:"end_at"`
40+
CreatedAt types.String `tfsdk:"created_at"`
41+
UpdatedAt types.String `tfsdk:"updated_at"`
42+
CreatedBy types.Object `tfsdk:"created_by"`
43+
UpdatedBy types.Object `tfsdk:"updated_by"`
44+
ExpiryPeriodInDays types.Int64 `tfsdk:"expiry_period_in_days"`
45+
LastUsedAt types.String `tfsdk:"last_used_at"`
46+
Roles types.Set `tfsdk:"roles"`
47+
Token types.String `tfsdk:"token"`
48+
}
49+
3150
func (data *ApiTokenDataSource) ReadFromResponse(ctx context.Context, apiToken *iam.ApiToken) diag.Diagnostics {
3251
var diags diag.Diagnostics
3352
data.Id = types.StringValue(apiToken.Id)
@@ -67,3 +86,52 @@ func (data *ApiTokenDataSource) ReadFromResponse(ctx context.Context, apiToken *
6786
}
6887
return diags
6988
}
89+
90+
func (data *ApiTokenResource) ReadFromResponse(ctx context.Context, apiToken *iam.ApiToken, token string) diag.Diagnostics {
91+
var diags diag.Diagnostics
92+
data.Id = types.StringValue(apiToken.Id)
93+
data.Name = types.StringValue(apiToken.Name)
94+
if apiToken.Description == "" {
95+
data.Description = types.StringValue("")
96+
} else {
97+
data.Description = types.StringValue(apiToken.Description)
98+
}
99+
data.ShortToken = types.StringValue(apiToken.ShortToken)
100+
data.Type = types.StringValue(string(apiToken.Type))
101+
data.StartAt = types.StringValue(apiToken.StartAt.String())
102+
if apiToken.EndAt == nil {
103+
data.EndAt = types.StringValue("")
104+
} else {
105+
data.EndAt = types.StringValue(apiToken.EndAt.String())
106+
}
107+
data.CreatedAt = types.StringValue(apiToken.CreatedAt.String())
108+
data.UpdatedAt = types.StringValue(apiToken.UpdatedAt.String())
109+
data.CreatedBy, diags = SubjectProfileTypesObject(ctx, apiToken.CreatedBy)
110+
if diags.HasError() {
111+
return diags
112+
}
113+
data.UpdatedBy, diags = SubjectProfileTypesObject(ctx, apiToken.UpdatedBy)
114+
if diags.HasError() {
115+
return diags
116+
}
117+
if apiToken.ExpiryPeriodInDays != nil {
118+
data.ExpiryPeriodInDays = types.Int64Value(int64(*apiToken.ExpiryPeriodInDays))
119+
}
120+
if apiToken.LastUsedAt == nil {
121+
data.LastUsedAt = types.StringValue("")
122+
} else {
123+
data.LastUsedAt = types.StringValue(apiToken.LastUsedAt.String())
124+
}
125+
data.Roles, diags = utils.ObjectSet(ctx, apiToken.Roles, schemas.ApiTokenRoleAttributeTypes(), ApiTokenRoleTypesObject)
126+
if diags.HasError() {
127+
return diags
128+
}
129+
if apiToken.Token != nil && len(*apiToken.Token) > 0 {
130+
data.Token = types.StringValue(*apiToken.Token)
131+
} else if token != "" {
132+
data.Token = types.StringValue(token)
133+
} else {
134+
data.Token = types.StringNull()
135+
}
136+
return diags
137+
}

internal/provider/models/subject_profile.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ import (
44
"context"
55

66
"github.com/astronomer/terraform-provider-astro/internal/clients/iam"
7-
"github.com/astronomer/terraform-provider-astro/internal/provider/schemas"
8-
"github.com/hashicorp/terraform-plugin-log/tflog"
9-
107
"github.com/astronomer/terraform-provider-astro/internal/clients/platform"
8+
"github.com/astronomer/terraform-provider-astro/internal/provider/schemas"
119
"github.com/hashicorp/terraform-plugin-framework/diag"
1210
"github.com/hashicorp/terraform-plugin-framework/types"
11+
"github.com/hashicorp/terraform-plugin-log/tflog"
1312
)
1413

1514
type SubjectProfile struct {

internal/provider/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ func (p *AstroProvider) Resources(ctx context.Context) []func() resource.Resourc
125125
resources.NewClusterResource,
126126
resources.NewTeamRolesResource,
127127
resources.NewHybridClusterWorkspaceAuthorizationResource,
128+
resources.NewApiTokenResource,
128129
}
129130
}
130131

0 commit comments

Comments
 (0)