Skip to content

Commit d88d528

Browse files
authored
Merge pull request #1147 from timofurrer/feature/cluster_agent_token
New Resource `gitlab_cluster_agent_token`
2 parents b5a42dd + e937938 commit d88d528

File tree

6 files changed

+515
-0
lines changed

6 files changed

+515
-0
lines changed

docs/resources/cluster_agent_token.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "gitlab_cluster_agent_token Resource - terraform-provider-gitlab"
4+
subcategory: ""
5+
description: |-
6+
The gitlab_cluster_agent_token resource allows to manage the lifecycle of a token for a GitLab Agent for Kubernetes.
7+
-> Requires at least maintainer permissions on the project.
8+
-> Requires at least GitLab 15.0
9+
Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/cluster_agents.html#create-an-agent-token
10+
---
11+
12+
# gitlab_cluster_agent_token (Resource)
13+
14+
The `gitlab_cluster_agent_token` resource allows to manage the lifecycle of a token for a GitLab Agent for Kubernetes.
15+
16+
-> Requires at least maintainer permissions on the project.
17+
18+
-> Requires at least GitLab 15.0
19+
20+
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/cluster_agents.html#create-an-agent-token)
21+
22+
## Example Usage
23+
24+
```terraform
25+
// Create token for an agent
26+
resource "gitlab_cluster_agent_token" "example" {
27+
project = "12345"
28+
agent_id = 42
29+
name = "some-token"
30+
description = "some token"
31+
}
32+
33+
// The following example creates a GitLab Agent for Kubernetes in a given project,
34+
// creates a token and install the `gitlab-agent` Helm Chart.
35+
// (see https://gitlab.com/gitlab-org/charts/gitlab-agent)
36+
data "gitlab_project" "this" {
37+
path_with_namespace = "my-org/example"
38+
}
39+
40+
resource "gitlab_cluster_agent" "this" {
41+
project = data.gitlab_project.this
42+
name = "my-agent"
43+
}
44+
45+
resource "gitlab_cluster_agent_token" "this" {
46+
project = data.gitlab_project.this
47+
agent_id = gitlab_cluster_agent.this.id
48+
name = "my-agent-token"
49+
description = "Token for the my-agent used with `gitlab-agent` Helm Chart"
50+
}
51+
52+
resource "helm_release" "gitlab_agent" {
53+
name = "gitlab-agent"
54+
namespace = "gitlab-agent"
55+
create_namespace = true
56+
repository = "https://charts.gitlab.io"
57+
chart = "gitlab-agent"
58+
version = "1.2.0"
59+
60+
set {
61+
name = "config.token"
62+
value = gitlab_cluster_agent_token.this.token
63+
}
64+
}
65+
```
66+
67+
<!-- schema generated by tfplugindocs -->
68+
## Schema
69+
70+
### Required
71+
72+
- `agent_id` (Number) The ID of the agent.
73+
- `name` (String) The Name of the agent.
74+
- `project` (String) ID or full path of the project maintained by the authenticated user.
75+
76+
### Optional
77+
78+
- `description` (String) The Description for the agent.
79+
80+
### Read-Only
81+
82+
- `created_at` (String) The ISO8601 datetime when the agent was created.
83+
- `created_by_user_id` (Number) The ID of the user who created the agent.
84+
- `id` (String) The ID of this resource.
85+
- `last_used_at` (String) The ISO8601 datetime when the token was last used.
86+
- `status` (String) The status of the token. Valid values are `active`, `revoked`.
87+
- `token` (String) The secret token for the agent. The `token` is not available in imported resources.
88+
- `token_id` (Number) The ID of the token.
89+
90+
## Import
91+
92+
Import is supported using the following syntax:
93+
94+
```shell
95+
# A token for a GitLab Agent for Kubernetes can be imported with the following command and the id pattern `<project>:<agent-id>:<token-id>`:
96+
terraform import gitlab_cluster_agent_token.example '12345:42:1'
97+
98+
# ATTENTION: the `token` resource attribute is not available for imported resources as this information cannot be read from the GitLab API.
99+
```
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# A token for a GitLab Agent for Kubernetes can be imported with the following command and the id pattern `<project>:<agent-id>:<token-id>`:
2+
terraform import gitlab_cluster_agent_token.example '12345:42:1'
3+
4+
# ATTENTION: the `token` resource attribute is not available for imported resources as this information cannot be read from the GitLab API.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Create token for an agent
2+
resource "gitlab_cluster_agent_token" "example" {
3+
project = "12345"
4+
agent_id = 42
5+
name = "some-token"
6+
description = "some token"
7+
}
8+
9+
// The following example creates a GitLab Agent for Kubernetes in a given project,
10+
// creates a token and install the `gitlab-agent` Helm Chart.
11+
// (see https://gitlab.com/gitlab-org/charts/gitlab-agent)
12+
data "gitlab_project" "this" {
13+
path_with_namespace = "my-org/example"
14+
}
15+
16+
resource "gitlab_cluster_agent" "this" {
17+
project = data.gitlab_project.this
18+
name = "my-agent"
19+
}
20+
21+
resource "gitlab_cluster_agent_token" "this" {
22+
project = data.gitlab_project.this
23+
agent_id = gitlab_cluster_agent.this.id
24+
name = "my-agent-token"
25+
description = "Token for the my-agent used with `gitlab-agent` Helm Chart"
26+
}
27+
28+
resource "helm_release" "gitlab_agent" {
29+
name = "gitlab-agent"
30+
namespace = "gitlab-agent"
31+
create_namespace = true
32+
repository = "https://charts.gitlab.io"
33+
chart = "gitlab-agent"
34+
version = "1.2.0"
35+
36+
set {
37+
name = "config.token"
38+
value = gitlab_cluster_agent_token.this.token
39+
}
40+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"strconv"
8+
"strings"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
12+
gitlab "github.com/xanzy/go-gitlab"
13+
)
14+
15+
var _ = registerResource("gitlab_cluster_agent_token", func() *schema.Resource {
16+
return &schema.Resource{
17+
Description: `The ` + "`" + `gitlab_cluster_agent_token` + "`" + ` resource allows to manage the lifecycle of a token for a GitLab Agent for Kubernetes.
18+
19+
-> Requires at least maintainer permissions on the project.
20+
21+
-> Requires at least GitLab 15.0
22+
23+
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/cluster_agents.html#create-an-agent-token)`,
24+
25+
CreateContext: resourceGitlabClusterAgentTokenCreate,
26+
ReadContext: resourceGitlabClusterAgentTokenRead,
27+
DeleteContext: resourceGitlabClusterAgentTokenDelete,
28+
Importer: &schema.ResourceImporter{
29+
StateContext: schema.ImportStatePassthroughContext,
30+
},
31+
32+
Schema: gitlabClusterAgentTokenSchema(),
33+
}
34+
})
35+
36+
func resourceGitlabClusterAgentTokenCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
37+
client := meta.(*gitlab.Client)
38+
39+
project := d.Get("project").(string)
40+
agentID := d.Get("agent_id").(int)
41+
options := gitlab.CreateAgentTokenOptions{
42+
Name: gitlab.String(d.Get("name").(string)),
43+
}
44+
45+
if v, ok := d.GetOk("description"); ok {
46+
options.Description = gitlab.String(v.(string))
47+
}
48+
49+
log.Printf("[DEBUG] create token for GitLab Agent for Kubernetes %d in project %s with name '%v'", agentID, project, options.Name)
50+
clusterAgentToken, _, err := client.ClusterAgents.CreateAgentToken(project, agentID, &options, gitlab.WithContext(ctx))
51+
if err != nil {
52+
return diag.FromErr(err)
53+
}
54+
55+
d.SetId(resourceGitlabClusterAgentTokenBuildID(project, agentID, clusterAgentToken.ID))
56+
// NOTE: the token is only returned with the direct response from the create API.
57+
d.Set("token", clusterAgentToken.Token)
58+
return resourceGitlabClusterAgentTokenRead(ctx, d, meta)
59+
}
60+
61+
func resourceGitlabClusterAgentTokenRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
62+
client := meta.(*gitlab.Client)
63+
project, agentID, tokenID, err := resourceGitlabClusterAgentTokenParseID(d.Id())
64+
if err != nil {
65+
return diag.FromErr(err)
66+
}
67+
68+
log.Printf("[DEBUG] read token for GitLab Agent for Kubernetes %d in project %s with id %d", agentID, project, tokenID)
69+
clusterAgentToken, _, err := client.ClusterAgents.GetAgentToken(project, agentID, tokenID, gitlab.WithContext(ctx))
70+
if err != nil {
71+
if is404(err) {
72+
log.Printf("[DEBUG] read token for GitLab Agent for Kubernetes %d in project %s with id %d not found, removing from state", agentID, project, tokenID)
73+
d.SetId("")
74+
return nil
75+
}
76+
return diag.FromErr(err)
77+
}
78+
79+
stateMap := gitlabClusterAgentTokenToStateMap(project, clusterAgentToken)
80+
if err = setStateMapInResourceData(stateMap, d); err != nil {
81+
return diag.FromErr(err)
82+
}
83+
return nil
84+
}
85+
86+
func resourceGitlabClusterAgentTokenDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
87+
client := meta.(*gitlab.Client)
88+
project, agentID, tokenID, err := resourceGitlabClusterAgentTokenParseID(d.Id())
89+
if err != nil {
90+
return diag.FromErr(err)
91+
}
92+
93+
log.Printf("[DEBUG] delete token for GitLab Agent for Kubernetes %d in project %s with id %d", agentID, project, tokenID)
94+
if _, err := client.ClusterAgents.RevokeAgentToken(project, agentID, tokenID, gitlab.WithContext(ctx)); err != nil {
95+
return diag.FromErr(err)
96+
}
97+
98+
return nil
99+
}
100+
101+
func resourceGitlabClusterAgentTokenBuildID(project string, agentID int, tokenID int) string {
102+
return fmt.Sprintf("%s:%d:%d", project, agentID, tokenID)
103+
}
104+
105+
func resourceGitlabClusterAgentTokenParseID(id string) (string, int, int, error) {
106+
parts := strings.Split(id, ":")
107+
if len(parts) != 3 {
108+
return "", 0, 0, fmt.Errorf("invalid cluster agent token id %q, expected format '{project}:{agent_id}:{token_id}", id)
109+
}
110+
project, rawAgentID, rawTokenID := parts[0], parts[1], parts[2]
111+
agentID, err := strconv.Atoi(rawAgentID)
112+
if err != nil {
113+
return "", 0, 0, fmt.Errorf("invalid cluster agent token id %q with 'agent_id' %q, expected integer", id, rawAgentID)
114+
}
115+
tokenID, err := strconv.Atoi(rawTokenID)
116+
if err != nil {
117+
return "", 0, 0, fmt.Errorf("invalid cluster agent token id %q with 'token_id' %q, expected integer", id, rawTokenID)
118+
}
119+
120+
return project, agentID, tokenID, nil
121+
}

0 commit comments

Comments
 (0)