Skip to content

Commit 6270719

Browse files
authored
Merge pull request #1243 from gitlabhq/feature/saml-group-links
resource/gitlab_group_saml_link: Add new resource
2 parents e37d0f2 + c0d5f3a commit 6270719

File tree

5 files changed

+258
-0
lines changed

5 files changed

+258
-0
lines changed

docs/resources/group_saml_link.md

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "gitlab_group_saml_link Resource - terraform-provider-gitlab"
4+
subcategory: ""
5+
description: |-
6+
The gitlab_group_saml_link resource allows to manage the lifecycle of an SAML integration with a group.
7+
Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/groups.html#saml-group-links
8+
---
9+
10+
# gitlab_group_saml_link (Resource)
11+
12+
The `gitlab_group_saml_link` resource allows to manage the lifecycle of an SAML integration with a group.
13+
14+
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/groups.html#saml-group-links)
15+
16+
## Example Usage
17+
18+
```terraform
19+
resource "gitlab_group_saml_link" "test" {
20+
group_id = "12345"
21+
access_level = "developer"
22+
saml_group_name = "samlgroupname1"
23+
}
24+
```
25+
26+
<!-- schema generated by tfplugindocs -->
27+
## Schema
28+
29+
### Required
30+
31+
- `access_level` (String) Access level for members of the SAML group. Valid values are: `guest`, `reporter`, `developer`, `maintainer`, `owner`.
32+
- `group` (String) The ID or path of the group to add the SAML Group Link to.
33+
- `saml_group_name` (String) The name of the SAML group.
34+
35+
### Read-Only
36+
37+
- `id` (String) The ID of this resource.
38+
39+
## Import
40+
41+
Import is supported using the following syntax:
42+
43+
```shell
44+
# GitLab group saml links can be imported using an id made up of `group_id:saml_group_name`, e.g.
45+
terraform import gitlab_group_saml_link.test "12345:samlgroupname1"
46+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# GitLab group saml links can be imported using an id made up of `group_id:saml_group_name`, e.g.
2+
terraform import gitlab_group_saml_link.test "12345:samlgroupname1"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
resource "gitlab_group_saml_link" "test" {
2+
group_id = "12345"
3+
access_level = "developer"
4+
saml_group_name = "samlgroupname1"
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
11+
gitlab "github.com/xanzy/go-gitlab"
12+
)
13+
14+
var _ = registerResource("gitlab_group_saml_link", func() *schema.Resource {
15+
validGroupSamlLinkAccessLevelNames := []string{
16+
"guest",
17+
"reporter",
18+
"developer",
19+
"maintainer",
20+
"owner",
21+
}
22+
23+
return &schema.Resource{
24+
Description: `The ` + "`gitlab_group_saml_link`" + ` resource allows to manage the lifecycle of an SAML integration with a group.
25+
26+
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/groups.html#saml-group-links)`,
27+
28+
CreateContext: resourceGitlabGroupSamlLinkCreate,
29+
ReadContext: resourceGitlabGroupSamlLinkRead,
30+
DeleteContext: resourceGitlabGroupSamlLinkDelete,
31+
Importer: &schema.ResourceImporter{
32+
StateContext: schema.ImportStatePassthroughContext,
33+
},
34+
35+
Schema: map[string]*schema.Schema{
36+
"group": {
37+
Description: "The ID or path of the group to add the SAML Group Link to.",
38+
Type: schema.TypeString,
39+
Required: true,
40+
ForceNew: true,
41+
},
42+
"saml_group_name": {
43+
Description: "The name of the SAML group.",
44+
Type: schema.TypeString,
45+
Required: true,
46+
ForceNew: true,
47+
},
48+
"access_level": {
49+
Description: fmt.Sprintf("Access level for members of the SAML group. Valid values are: %s.", renderValueListForDocs(validGroupSamlLinkAccessLevelNames)),
50+
Type: schema.TypeString,
51+
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(validGroupSamlLinkAccessLevelNames, false)),
52+
Required: true,
53+
ForceNew: true,
54+
},
55+
},
56+
}
57+
})
58+
59+
func resourceGitlabGroupSamlLinkCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
60+
client := meta.(*gitlab.Client)
61+
62+
group := d.Get("group").(string)
63+
samlGroupName := d.Get("saml_group_name").(string)
64+
accessLevel := accessLevelNameToValue[d.Get("access_level").(string)]
65+
66+
options := &gitlab.AddGroupSAMLLinkOptions{
67+
SAMLGroupName: gitlab.String(samlGroupName),
68+
AccessLevel: gitlab.AccessLevel(accessLevel),
69+
}
70+
71+
log.Printf("[DEBUG] Create GitLab Group SAML Link for group %q with name %q", group, samlGroupName)
72+
SamlLink, _, err := client.Groups.AddGroupSAMLLink(group, options, gitlab.WithContext(ctx))
73+
if err != nil {
74+
return diag.FromErr(err)
75+
}
76+
77+
d.SetId(buildTwoPartID(&group, &SamlLink.Name))
78+
return resourceGitlabGroupSamlLinkRead(ctx, d, meta)
79+
}
80+
81+
func resourceGitlabGroupSamlLinkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
82+
client := meta.(*gitlab.Client)
83+
group, samlGroupName, parse_err := parseTwoPartID(d.Id())
84+
if parse_err != nil {
85+
return diag.FromErr(parse_err)
86+
}
87+
88+
// Try to fetch all group links from GitLab
89+
log.Printf("[DEBUG] Read GitLab Group SAML Link for group %q", group)
90+
samlLink, _, err := client.Groups.GetGroupSAMLLink(group, samlGroupName, nil, gitlab.WithContext(ctx))
91+
if err != nil {
92+
if is404(err) {
93+
log.Printf("[DEBUG] GitLab SAML Group Link %s for group ID %s not found, removing from state", samlGroupName, group)
94+
d.SetId("")
95+
return nil
96+
}
97+
return diag.FromErr(err)
98+
}
99+
100+
d.Set("group", group)
101+
d.Set("access_level", accessLevelValueToName[samlLink.AccessLevel])
102+
d.Set("saml_group_name", samlLink.Name)
103+
104+
return nil
105+
}
106+
107+
func resourceGitlabGroupSamlLinkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
108+
client := meta.(*gitlab.Client)
109+
group, samlGroupName, parse_err := parseTwoPartID(d.Id())
110+
if parse_err != nil {
111+
return diag.FromErr(parse_err)
112+
}
113+
114+
log.Printf("[DEBUG] Delete GitLab Group SAML Link for group %q with name %q", group, samlGroupName)
115+
_, err := client.Groups.DeleteGroupSAMLLink(group, samlGroupName, gitlab.WithContext(ctx))
116+
if err != nil {
117+
if is404(err) {
118+
log.Printf("[WARNING] %s", err)
119+
} else {
120+
return diag.FromErr(err)
121+
}
122+
}
123+
124+
return nil
125+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//go:build acceptance
2+
// +build acceptance
3+
4+
package provider
5+
6+
import (
7+
"fmt"
8+
"testing"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
12+
)
13+
14+
func TestAccGitlabGroupSamlLink_basic(t *testing.T) {
15+
testAccCheckEE(t)
16+
testAccRequiresAtLeast(t, "15.3")
17+
18+
testGroup := testAccCreateGroups(t, 1)[0]
19+
20+
resource.ParallelTest(t, resource.TestCase{
21+
ProviderFactories: providerFactories,
22+
CheckDestroy: testAccCheckGitlabGroupSamlLinkDestroy,
23+
Steps: []resource.TestStep{
24+
25+
// Create a group SAML link as a developer
26+
{
27+
Config: fmt.Sprintf(`
28+
resource "gitlab_group_saml_link" "this" {
29+
group = "%d"
30+
access_level = "developer"
31+
saml_group_name = "test_saml_group"
32+
33+
}
34+
`, testGroup.ID),
35+
},
36+
// Verify Import
37+
{
38+
ResourceName: "gitlab_group_saml_link.this",
39+
ImportState: true,
40+
ImportStateVerify: true,
41+
},
42+
// Update the group SAML link to change the access level
43+
{
44+
Config: fmt.Sprintf(`
45+
resource "gitlab_group_saml_link" "this" {
46+
group = "%d"
47+
access_level = "maintainer"
48+
saml_group_name = "test_saml_group"
49+
50+
}
51+
`, testGroup.ID),
52+
},
53+
},
54+
})
55+
}
56+
57+
func testAccCheckGitlabGroupSamlLinkDestroy(s *terraform.State) error {
58+
for _, resourceState := range s.RootModule().Resources {
59+
if resourceState.Type != "gitlab_group_saml_link" {
60+
continue
61+
}
62+
63+
group, samlGroupName, err := parseTwoPartID(resourceState.Primary.ID)
64+
if err != nil {
65+
return err
66+
}
67+
68+
samlGroupLink, _, err := testGitlabClient.Groups.GetGroupSAMLLink(group, samlGroupName)
69+
if err == nil {
70+
if samlGroupLink != nil {
71+
return fmt.Errorf("SAML Group Link still exists")
72+
}
73+
}
74+
if !is404(err) {
75+
return err
76+
}
77+
return nil
78+
}
79+
return nil
80+
}

0 commit comments

Comments
 (0)