Skip to content

Commit 394f4ff

Browse files
authored
Merge pull request #1181 from yan12125/add-resource-gitlab_user_gpgkey
Add resource gitlab_user_gpgkey
2 parents 8cf59f2 + d3a0127 commit 394f4ff

File tree

5 files changed

+528
-0
lines changed

5 files changed

+528
-0
lines changed

docs/resources/user_gpgkey.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "gitlab_user_gpgkey Resource - terraform-provider-gitlab"
4+
subcategory: ""
5+
description: |-
6+
The gitlab_user_gpgkey resource allows to manage the lifecycle of a GPG key assigned to the current user or a specific user.
7+
-> Managing GPG keys for arbitrary users requires admin privileges.
8+
Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/users.html#get-a-specific-gpg-key
9+
---
10+
11+
# gitlab_user_gpgkey (Resource)
12+
13+
The `gitlab_user_gpgkey` resource allows to manage the lifecycle of a GPG key assigned to the current user or a specific user.
14+
15+
-> Managing GPG keys for arbitrary users requires admin privileges.
16+
17+
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/users.html#get-a-specific-gpg-key)
18+
19+
## Example Usage
20+
21+
```terraform
22+
data "gitlab_user" "example" {
23+
username = "example-user"
24+
}
25+
26+
# Manages a GPG key for the specified user. An admin token is required if `user_id` is specified.
27+
resource "gitlab_user_gpgkey" "example" {
28+
user_id = data.gitlab_user.example.id
29+
key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"
30+
}
31+
32+
# Manages a GPG key for the current user
33+
resource "gitlab_user_gpgkey" "example_user" {
34+
key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"
35+
}
36+
```
37+
38+
<!-- schema generated by tfplugindocs -->
39+
## Schema
40+
41+
### Required
42+
43+
- `key` (String) The armored GPG public key.
44+
45+
### Optional
46+
47+
- `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.
48+
49+
### Read-Only
50+
51+
- `created_at` (String) The time when this key was created in GitLab.
52+
- `id` (String) The ID of this resource.
53+
- `key_id` (Number) The ID of the GPG key.
54+
55+
## Import
56+
57+
Import is supported using the following syntax:
58+
59+
```shell
60+
# You can import a GPG key for a specific user using an id made up of `{user-id}:{key}`, e.g.
61+
terraform import gitlab_user_gpgkey.example 42:1
62+
63+
# Alternatively, you can import a GPG key for the current user using an id made up of `{key}`, e.g.
64+
terraform import gitlab_user_gpgkey.example_user 1
65+
```
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# You can import a GPG key for a specific user using an id made up of `{user-id}:{key}`, e.g.
2+
terraform import gitlab_user_gpgkey.example 42:1
3+
4+
# Alternatively, you can import a GPG key for the current user using an id made up of `{key}`, e.g.
5+
terraform import gitlab_user_gpgkey.example_user 1
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
data "gitlab_user" "example" {
2+
username = "example-user"
3+
}
4+
5+
# Manages a GPG key for the specified user. An admin token is required if `user_id` is specified.
6+
resource "gitlab_user_gpgkey" "example" {
7+
user_id = data.gitlab_user.example.id
8+
key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"
9+
}
10+
11+
# Manages a GPG key for the current user
12+
resource "gitlab_user_gpgkey" "example_user" {
13+
key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"
14+
}
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"strconv"
8+
"strings"
9+
"time"
10+
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
13+
gitlab "github.com/xanzy/go-gitlab"
14+
)
15+
16+
var _ = registerResource("gitlab_user_gpgkey", func() *schema.Resource {
17+
return &schema.Resource{
18+
Description: `The ` + "`" + `gitlab_user_gpgkey` + "`" + ` resource allows to manage the lifecycle of a GPG key assigned to the current user or a specific user.
19+
20+
-> Managing GPG keys for arbitrary users requires admin privileges.
21+
22+
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/users.html#get-a-specific-gpg-key)`,
23+
24+
CreateContext: resourceGitlabUserGPGKeyCreate,
25+
ReadContext: resourceGitlabUserGPGKeyRead,
26+
DeleteContext: resourceGitlabUserGPGKeyDelete,
27+
Importer: &schema.ResourceImporter{
28+
StateContext: schema.ImportStatePassthroughContext,
29+
},
30+
31+
Schema: map[string]*schema.Schema{
32+
"user_id": {
33+
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.",
34+
Type: schema.TypeInt,
35+
ForceNew: true,
36+
Optional: true,
37+
},
38+
"key": {
39+
Description: "The armored GPG public key.",
40+
Type: schema.TypeString,
41+
ForceNew: true,
42+
Required: true,
43+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
44+
strippedOld := strings.TrimSpace(old)
45+
strippedNew := strings.TrimSpace(new)
46+
return strippedOld == strippedNew
47+
},
48+
},
49+
"key_id": {
50+
Description: "The ID of the GPG key.",
51+
Type: schema.TypeInt,
52+
Computed: true,
53+
},
54+
"created_at": {
55+
Description: "The time when this key was created in GitLab.",
56+
Type: schema.TypeString,
57+
Computed: true,
58+
},
59+
},
60+
}
61+
})
62+
63+
func resourceGitlabUserGPGKeyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
64+
client := meta.(*gitlab.Client)
65+
66+
options := &gitlab.AddGPGKeyOptions{
67+
Key: gitlab.String(strings.TrimSpace(d.Get("key").(string))),
68+
}
69+
70+
var isAdmin bool
71+
var key *gitlab.GPGKey
72+
var err error
73+
userID, userIDOk := d.GetOk("user_id")
74+
if userIDOk {
75+
isAdmin, err = isCurrentUserAdmin(ctx, client)
76+
if err != nil {
77+
return diag.Errorf("failed to check if user is admin for configuring GPG keys for a user")
78+
}
79+
if !isAdmin {
80+
return diag.Errorf("current user needs to be admin for configuring GPG keys for a user")
81+
}
82+
key, _, err = client.Users.AddGPGKeyForUser(userID.(int), options, gitlab.WithContext(ctx))
83+
} else {
84+
key, _, err = client.Users.AddGPGKey(options, gitlab.WithContext(ctx))
85+
}
86+
if err != nil {
87+
return diag.FromErr(err)
88+
}
89+
90+
keyIDForID := fmt.Sprintf("%d", key.ID)
91+
if userIDOk {
92+
userIDForID := fmt.Sprintf("%d", userID)
93+
d.SetId(buildTwoPartID(&userIDForID, &keyIDForID))
94+
} else {
95+
d.SetId(keyIDForID)
96+
}
97+
return resourceGitlabUserGPGKeyRead(ctx, d, meta)
98+
}
99+
100+
func resourceGitlabUserGPGKeyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
101+
client := meta.(*gitlab.Client)
102+
103+
userID, keyID, err := resourceGitlabUserGPGKeyParseID(d.Id())
104+
if err != nil {
105+
return diag.Errorf("unable to parse user GPG key resource id: %s: %v", d.Id(), err)
106+
}
107+
108+
var key *gitlab.GPGKey
109+
if userID != 0 {
110+
key, _, err = client.Users.GetGPGKeyForUser(userID, keyID, gitlab.WithContext(ctx))
111+
} else {
112+
key, _, err = client.Users.GetGPGKey(keyID, gitlab.WithContext(ctx))
113+
}
114+
if err != nil {
115+
if is404(err) {
116+
log.Printf("Could not find GPG key %d for user %d, removing from state", keyID, userID)
117+
d.SetId("")
118+
return nil
119+
}
120+
return diag.FromErr(err)
121+
}
122+
123+
if userID != 0 {
124+
d.Set("user_id", userID)
125+
}
126+
d.Set("key_id", keyID)
127+
d.Set("key", strings.TrimSpace(key.Key))
128+
d.Set("created_at", key.CreatedAt.Format(time.RFC3339))
129+
return nil
130+
}
131+
132+
func resourceGitlabUserGPGKeyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
133+
client := meta.(*gitlab.Client)
134+
135+
var isAdmin bool
136+
_, keyID, err := resourceGitlabUserGPGKeyParseID(d.Id())
137+
if err != nil {
138+
return diag.Errorf("unable to parse user GPG key resource id: %s: %v", d.Id(), err)
139+
}
140+
141+
if userID, ok := d.GetOk("user_id"); ok {
142+
isAdmin, err = isCurrentUserAdmin(ctx, client)
143+
if err != nil {
144+
return diag.Errorf("failed to check if user is admin for configuring GPG keys for a user")
145+
}
146+
if !isAdmin {
147+
return diag.Errorf("current user needs to be admin for configuring GPG keys for a user")
148+
}
149+
_, err = client.Users.DeleteGPGKeyForUser(userID.(int), keyID, gitlab.WithContext(ctx))
150+
} else {
151+
_, err = client.Users.DeleteGPGKey(keyID, gitlab.WithContext(ctx))
152+
}
153+
if err != nil {
154+
return diag.FromErr(err)
155+
}
156+
157+
return nil
158+
}
159+
160+
func resourceGitlabUserGPGKeyParseID(id string) (int, int, error) {
161+
userIDFromID, keyIDFromID, err := parseTwoPartID(id)
162+
if err != nil {
163+
keyID, errKeyID := strconv.Atoi(id)
164+
if errKeyID != nil {
165+
return 0, 0, err
166+
} else {
167+
return 0, keyID, nil
168+
}
169+
}
170+
userID, err := strconv.Atoi(userIDFromID)
171+
if err != nil {
172+
return 0, 0, err
173+
}
174+
keyID, err := strconv.Atoi(keyIDFromID)
175+
if err != nil {
176+
return 0, 0, err
177+
}
178+
179+
return userID, keyID, nil
180+
}

0 commit comments

Comments
 (0)