Skip to content

Commit

Permalink
New Resource gitlab_cluster_agent_token
Browse files Browse the repository at this point in the history
This change set adds support for the `gitlab_cluster_agent_token`
resource, representing the [Agents Token
API](https://docs.gitlab.com/ee/api/cluster_agents.html#create-an-agent-token).

Closes: #1141
  • Loading branch information
timofurrer committed Jun 25, 2022
1 parent 334b041 commit e937938
Show file tree
Hide file tree
Showing 6 changed files with 515 additions and 0 deletions.
99 changes: 99 additions & 0 deletions docs/resources/cluster_agent_token.md
@@ -0,0 +1,99 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "gitlab_cluster_agent_token Resource - terraform-provider-gitlab"
subcategory: ""
description: |-
The gitlab_cluster_agent_token resource allows to manage the lifecycle of a token for a GitLab Agent for Kubernetes.
-> Requires at least maintainer permissions on the project.
-> Requires at least GitLab 15.0
Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/cluster_agents.html#create-an-agent-token
---

# gitlab_cluster_agent_token (Resource)

The `gitlab_cluster_agent_token` resource allows to manage the lifecycle of a token for a GitLab Agent for Kubernetes.

-> Requires at least maintainer permissions on the project.

-> Requires at least GitLab 15.0

**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/cluster_agents.html#create-an-agent-token)

## Example Usage

```terraform
// Create token for an agent
resource "gitlab_cluster_agent_token" "example" {
project = "12345"
agent_id = 42
name = "some-token"
description = "some token"
}
// The following example creates a GitLab Agent for Kubernetes in a given project,
// creates a token and install the `gitlab-agent` Helm Chart.
// (see https://gitlab.com/gitlab-org/charts/gitlab-agent)
data "gitlab_project" "this" {
path_with_namespace = "my-org/example"
}
resource "gitlab_cluster_agent" "this" {
project = data.gitlab_project.this
name = "my-agent"
}
resource "gitlab_cluster_agent_token" "this" {
project = data.gitlab_project.this
agent_id = gitlab_cluster_agent.this.id
name = "my-agent-token"
description = "Token for the my-agent used with `gitlab-agent` Helm Chart"
}
resource "helm_release" "gitlab_agent" {
name = "gitlab-agent"
namespace = "gitlab-agent"
create_namespace = true
repository = "https://charts.gitlab.io"
chart = "gitlab-agent"
version = "1.2.0"
set {
name = "config.token"
value = gitlab_cluster_agent_token.this.token
}
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `agent_id` (Number) The ID of the agent.
- `name` (String) The Name of the agent.
- `project` (String) ID or full path of the project maintained by the authenticated user.

### Optional

- `description` (String) The Description for the agent.

### Read-Only

- `created_at` (String) The ISO8601 datetime when the agent was created.
- `created_by_user_id` (Number) The ID of the user who created the agent.
- `id` (String) The ID of this resource.
- `last_used_at` (String) The ISO8601 datetime when the token was last used.
- `status` (String) The status of the token. Valid values are `active`, `revoked`.
- `token` (String) The secret token for the agent. The `token` is not available in imported resources.
- `token_id` (Number) The ID of the token.

## Import

Import is supported using the following syntax:

```shell
# A token for a GitLab Agent for Kubernetes can be imported with the following command and the id pattern `<project>:<agent-id>:<token-id>`:
terraform import gitlab_cluster_agent_token.example '12345:42:1'

# ATTENTION: the `token` resource attribute is not available for imported resources as this information cannot be read from the GitLab API.
```
4 changes: 4 additions & 0 deletions examples/resources/gitlab_cluster_agent_token/import.sh
@@ -0,0 +1,4 @@
# A token for a GitLab Agent for Kubernetes can be imported with the following command and the id pattern `<project>:<agent-id>:<token-id>`:
terraform import gitlab_cluster_agent_token.example '12345:42:1'

# ATTENTION: the `token` resource attribute is not available for imported resources as this information cannot be read from the GitLab API.
40 changes: 40 additions & 0 deletions examples/resources/gitlab_cluster_agent_token/resource.tf
@@ -0,0 +1,40 @@
// Create token for an agent
resource "gitlab_cluster_agent_token" "example" {
project = "12345"
agent_id = 42
name = "some-token"
description = "some token"
}

// The following example creates a GitLab Agent for Kubernetes in a given project,
// creates a token and install the `gitlab-agent` Helm Chart.
// (see https://gitlab.com/gitlab-org/charts/gitlab-agent)
data "gitlab_project" "this" {
path_with_namespace = "my-org/example"
}

resource "gitlab_cluster_agent" "this" {
project = data.gitlab_project.this
name = "my-agent"
}

resource "gitlab_cluster_agent_token" "this" {
project = data.gitlab_project.this
agent_id = gitlab_cluster_agent.this.id
name = "my-agent-token"
description = "Token for the my-agent used with `gitlab-agent` Helm Chart"
}

resource "helm_release" "gitlab_agent" {
name = "gitlab-agent"
namespace = "gitlab-agent"
create_namespace = true
repository = "https://charts.gitlab.io"
chart = "gitlab-agent"
version = "1.2.0"

set {
name = "config.token"
value = gitlab_cluster_agent_token.this.token
}
}
121 changes: 121 additions & 0 deletions internal/provider/resource_gitlab_cluster_agent_token.go
@@ -0,0 +1,121 @@
package provider

import (
"context"
"fmt"
"log"
"strconv"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
gitlab "github.com/xanzy/go-gitlab"
)

var _ = registerResource("gitlab_cluster_agent_token", func() *schema.Resource {
return &schema.Resource{
Description: `The ` + "`" + `gitlab_cluster_agent_token` + "`" + ` resource allows to manage the lifecycle of a token for a GitLab Agent for Kubernetes.
-> Requires at least maintainer permissions on the project.
-> Requires at least GitLab 15.0
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/cluster_agents.html#create-an-agent-token)`,

CreateContext: resourceGitlabClusterAgentTokenCreate,
ReadContext: resourceGitlabClusterAgentTokenRead,
DeleteContext: resourceGitlabClusterAgentTokenDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: gitlabClusterAgentTokenSchema(),
}
})

func resourceGitlabClusterAgentTokenCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*gitlab.Client)

project := d.Get("project").(string)
agentID := d.Get("agent_id").(int)
options := gitlab.CreateAgentTokenOptions{
Name: gitlab.String(d.Get("name").(string)),
}

if v, ok := d.GetOk("description"); ok {
options.Description = gitlab.String(v.(string))
}

log.Printf("[DEBUG] create token for GitLab Agent for Kubernetes %d in project %s with name '%v'", agentID, project, options.Name)
clusterAgentToken, _, err := client.ClusterAgents.CreateAgentToken(project, agentID, &options, gitlab.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

d.SetId(resourceGitlabClusterAgentTokenBuildID(project, agentID, clusterAgentToken.ID))
// NOTE: the token is only returned with the direct response from the create API.
d.Set("token", clusterAgentToken.Token)
return resourceGitlabClusterAgentTokenRead(ctx, d, meta)
}

func resourceGitlabClusterAgentTokenRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*gitlab.Client)
project, agentID, tokenID, err := resourceGitlabClusterAgentTokenParseID(d.Id())
if err != nil {
return diag.FromErr(err)
}

log.Printf("[DEBUG] read token for GitLab Agent for Kubernetes %d in project %s with id %d", agentID, project, tokenID)
clusterAgentToken, _, err := client.ClusterAgents.GetAgentToken(project, agentID, tokenID, gitlab.WithContext(ctx))
if err != nil {
if is404(err) {
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)
d.SetId("")
return nil
}
return diag.FromErr(err)
}

stateMap := gitlabClusterAgentTokenToStateMap(project, clusterAgentToken)
if err = setStateMapInResourceData(stateMap, d); err != nil {
return diag.FromErr(err)
}
return nil
}

func resourceGitlabClusterAgentTokenDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*gitlab.Client)
project, agentID, tokenID, err := resourceGitlabClusterAgentTokenParseID(d.Id())
if err != nil {
return diag.FromErr(err)
}

log.Printf("[DEBUG] delete token for GitLab Agent for Kubernetes %d in project %s with id %d", agentID, project, tokenID)
if _, err := client.ClusterAgents.RevokeAgentToken(project, agentID, tokenID, gitlab.WithContext(ctx)); err != nil {
return diag.FromErr(err)
}

return nil
}

func resourceGitlabClusterAgentTokenBuildID(project string, agentID int, tokenID int) string {
return fmt.Sprintf("%s:%d:%d", project, agentID, tokenID)
}

func resourceGitlabClusterAgentTokenParseID(id string) (string, int, int, error) {
parts := strings.Split(id, ":")
if len(parts) != 3 {
return "", 0, 0, fmt.Errorf("invalid cluster agent token id %q, expected format '{project}:{agent_id}:{token_id}", id)
}
project, rawAgentID, rawTokenID := parts[0], parts[1], parts[2]
agentID, err := strconv.Atoi(rawAgentID)
if err != nil {
return "", 0, 0, fmt.Errorf("invalid cluster agent token id %q with 'agent_id' %q, expected integer", id, rawAgentID)
}
tokenID, err := strconv.Atoi(rawTokenID)
if err != nil {
return "", 0, 0, fmt.Errorf("invalid cluster agent token id %q with 'token_id' %q, expected integer", id, rawTokenID)
}

return project, agentID, tokenID, nil
}

0 comments on commit e937938

Please sign in to comment.