Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add resource gitlab_user_gpgkey #1181

Merged
merged 1 commit into from Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
65 changes: 65 additions & 0 deletions docs/resources/user_gpgkey.md
@@ -0,0 +1,65 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "gitlab_user_gpgkey Resource - terraform-provider-gitlab"
subcategory: ""
description: |-
The gitlab_user_gpgkey resource allows to manage the lifecycle of a GPG key assigned to the current user or a specific user.
-> Managing GPG keys for arbitrary users requires admin privileges.
Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/users.html#get-a-specific-gpg-key
---

# gitlab_user_gpgkey (Resource)

The `gitlab_user_gpgkey` resource allows to manage the lifecycle of a GPG key assigned to the current user or a specific user.

-> Managing GPG keys for arbitrary users requires admin privileges.

**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/users.html#get-a-specific-gpg-key)

## Example Usage

```terraform
data "gitlab_user" "example" {
username = "example-user"
}

# Manages a GPG key for the specified user. An admin token is required if `user_id` is specified.
resource "gitlab_user_gpgkey" "example" {
user_id = data.gitlab_user.example.id
key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"
}

# Manages a GPG key for the current user
resource "gitlab_user_gpgkey" "example_user" {
key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"
}
```

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

### Required

- `key` (String) The armored GPG public key.

### Optional

- `user_id` (Number) The ID of the user to add the GPG key to. If this field is omitted, this resource manages a GPG key for the current user. Otherwise, this resource manages a GPG key for the speicifed user, and an admin token is required.

### Read-Only

- `created_at` (String) The time when this key was created in GitLab.
- `id` (String) The ID of this resource.
- `key_id` (Number) The ID of the GPG key.

## Import

Import is supported using the following syntax:

```shell
# You can import a GPG key for a specific user using an id made up of `{user-id}:{key}`, e.g.
terraform import gitlab_user_gpgkey.example 42:1

# Alternatively, you can import a GPG key for the current user using an id made up of `{key}`, e.g.
terraform import gitlab_user_gpgkey.example_user 1
```
5 changes: 5 additions & 0 deletions examples/resources/gitlab_user_gpgkey/import.sh
@@ -0,0 +1,5 @@
# You can import a GPG key for a specific user using an id made up of `{user-id}:{key}`, e.g.
terraform import gitlab_user_gpgkey.example 42:1

# Alternatively, you can import a GPG key for the current user using an id made up of `{key}`, e.g.
terraform import gitlab_user_gpgkey.example_user 1
14 changes: 14 additions & 0 deletions examples/resources/gitlab_user_gpgkey/resource.tf
@@ -0,0 +1,14 @@
data "gitlab_user" "example" {
username = "example-user"
}

# Manages a GPG key for the specified user. An admin token is required if `user_id` is specified.
resource "gitlab_user_gpgkey" "example" {
user_id = data.gitlab_user.example.id
key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"
}

# Manages a GPG key for the current user
resource "gitlab_user_gpgkey" "example_user" {
key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"
}
180 changes: 180 additions & 0 deletions internal/provider/resource_gitlab_user_gpgkey.go
@@ -0,0 +1,180 @@
package provider

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

"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_user_gpgkey", func() *schema.Resource {
return &schema.Resource{
Description: `The ` + "`" + `gitlab_user_gpgkey` + "`" + ` resource allows to manage the lifecycle of a GPG key assigned to the current user or a specific user.
yan12125 marked this conversation as resolved.
Show resolved Hide resolved

-> Managing GPG keys for arbitrary users requires admin privileges.

**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/users.html#get-a-specific-gpg-key)`,

CreateContext: resourceGitlabUserGPGKeyCreate,
ReadContext: resourceGitlabUserGPGKeyRead,
DeleteContext: resourceGitlabUserGPGKeyDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"user_id": {
Description: "The ID of the user to add the GPG key to. If this field is omitted, this resource manages a GPG key for the current user. Otherwise, this resource manages a GPG key for the speicifed user, and an admin token is required.",
Type: schema.TypeInt,
ForceNew: true,
Optional: true,
},
"key": {
Description: "The armored GPG public key.",
Type: schema.TypeString,
ForceNew: true,
Required: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
strippedOld := strings.TrimSpace(old)
strippedNew := strings.TrimSpace(new)
return strippedOld == strippedNew
},
},
"key_id": {
Description: "The ID of the GPG key.",
Type: schema.TypeInt,
Computed: true,
},
"created_at": {
Description: "The time when this key was created in GitLab.",
Type: schema.TypeString,
Computed: true,
},
},
}
})

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

options := &gitlab.AddGPGKeyOptions{
Key: gitlab.String(strings.TrimSpace(d.Get("key").(string))),
}

var isAdmin bool
var key *gitlab.GPGKey
var err error
userID, userIDOk := d.GetOk("user_id")
if userIDOk {
isAdmin, err = isCurrentUserAdmin(ctx, client)
if err != nil {
return diag.Errorf("failed to check if user is admin for configuring GPG keys for a user")
}
if !isAdmin {
return diag.Errorf("current user needs to be admin for configuring GPG keys for a user")
}
key, _, err = client.Users.AddGPGKeyForUser(userID.(int), options, gitlab.WithContext(ctx))
} else {
key, _, err = client.Users.AddGPGKey(options, gitlab.WithContext(ctx))
}
if err != nil {
return diag.FromErr(err)
}

keyIDForID := fmt.Sprintf("%d", key.ID)
if userIDOk {
userIDForID := fmt.Sprintf("%d", userID)
d.SetId(buildTwoPartID(&userIDForID, &keyIDForID))
} else {
d.SetId(keyIDForID)
}
return resourceGitlabUserGPGKeyRead(ctx, d, meta)
}

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

userID, keyID, err := resourceGitlabUserGPGKeyParseID(d.Id())
if err != nil {
return diag.Errorf("unable to parse user GPG key resource id: %s: %v", d.Id(), err)
}

var key *gitlab.GPGKey
if userID != 0 {
key, _, err = client.Users.GetGPGKeyForUser(userID, keyID, gitlab.WithContext(ctx))
} else {
key, _, err = client.Users.GetGPGKey(keyID, gitlab.WithContext(ctx))
}
if err != nil {
if is404(err) {
log.Printf("Could not find GPG key %d for user %d, removing from state", keyID, userID)
d.SetId("")
return nil
}
return diag.FromErr(err)
}

if userID != 0 {
d.Set("user_id", userID)
}
d.Set("key_id", keyID)
d.Set("key", strings.TrimSpace(key.Key))
d.Set("created_at", key.CreatedAt.Format(time.RFC3339))
return nil
}

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

var isAdmin bool
_, keyID, err := resourceGitlabUserGPGKeyParseID(d.Id())
if err != nil {
return diag.Errorf("unable to parse user GPG key resource id: %s: %v", d.Id(), err)
}

if userID, ok := d.GetOk("user_id"); ok {
isAdmin, err = isCurrentUserAdmin(ctx, client)
if err != nil {
return diag.Errorf("failed to check if user is admin for configuring GPG keys for a user")
}
if !isAdmin {
return diag.Errorf("current user needs to be admin for configuring GPG keys for a user")
}
_, err = client.Users.DeleteGPGKeyForUser(userID.(int), keyID, gitlab.WithContext(ctx))
} else {
_, err = client.Users.DeleteGPGKey(keyID, gitlab.WithContext(ctx))
}
if err != nil {
return diag.FromErr(err)
}

return nil
}

func resourceGitlabUserGPGKeyParseID(id string) (int, int, error) {
userIDFromID, keyIDFromID, err := parseTwoPartID(id)
if err != nil {
keyID, errKeyID := strconv.Atoi(id)
if errKeyID != nil {
return 0, 0, err
} else {
return 0, keyID, nil
}
}
userID, err := strconv.Atoi(userIDFromID)
if err != nil {
return 0, 0, err
}
keyID, err := strconv.Atoi(keyIDFromID)
if err != nil {
return 0, 0, err
}

return userID, keyID, nil
}