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 SAML Group link resource #1215

Closed
wants to merge 9 commits into from
Closed
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
46 changes: 46 additions & 0 deletions docs/resources/group_saml_link.md
@@ -0,0 +1,46 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "gitlab_group_saml_link Resource - terraform-provider-gitlab"
subcategory: ""
description: |-
The gitlab_group_saml_link resource allows to manage the lifecycle of an SAML integration with a group.
Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/groups.html#saml-group-links
---

# gitlab_group_saml_link (Resource)

The `gitlab_group_saml_link` resource allows to manage the lifecycle of an SAML integration with a group.

**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/groups.html#saml-group-links)

## Example Usage

```terraform
resource "gitlab_group_saml_link" "test" {
group_id = "12345"
access_level = "Developer"
saml_group_name = "samlgroupname1"
}
```

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

### Required

- `access_level` (String) Access level for members of the SAML group. Valid values are: `guest`, `reporter`, `developer`, `maintainer`, `owner`.
- `group` (String) The ID or path of the group to add the SAML Group Link to.
mhodgson marked this conversation as resolved.
Show resolved Hide resolved
- `saml_group_name` (String) The name of the SAML group.

### Read-Only

- `id` (String) The ID of this resource.

## Import

Import is supported using the following syntax:

```shell
# GitLab group saml links can be imported using an id made up of `group_id:saml_group_name`, e.g.
terraform import gitlab_group_saml_link.test "12345:samlgroupname1"
```
2 changes: 2 additions & 0 deletions examples/resources/gitlab_group_saml_link/import.sh
@@ -0,0 +1,2 @@
# GitLab group saml links can be imported using an id made up of `group_id:saml_group_name`, e.g.
terraform import gitlab_group_saml_link.test "12345:samlgroupname1"
5 changes: 5 additions & 0 deletions examples/resources/gitlab_group_saml_link/resource.tf
@@ -0,0 +1,5 @@
resource "gitlab_group_saml_link" "test" {
group_id = "12345"
access_level = "Developer"
saml_group_name = "samlgroupname1"
}
125 changes: 125 additions & 0 deletions internal/provider/resource_gitlab_group_saml_link.go
@@ -0,0 +1,125 @@
package provider

import (
"context"
"fmt"
"log"

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

var _ = registerResource("gitlab_group_saml_link", func() *schema.Resource {
validGroupSamlLinkAccessLevelNames := []string{
"guest",
"reporter",
"developer",
"maintainer",
"owner",
}

return &schema.Resource{
Description: `The ` + "`gitlab_group_saml_link`" + ` resource allows to manage the lifecycle of an SAML integration with a group.

**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/groups.html#saml-group-links)`,

CreateContext: resourceGitlabGroupSamlLinkCreate,
ReadContext: resourceGitlabGroupSamlLinkRead,
DeleteContext: resourceGitlabGroupSamlLinkDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"group": {
Description: "The ID or path of the group to add the SAML Group Link to.",
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"saml_group_name": {
Description: "The name of the SAML group.",
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"access_level": {
Description: fmt.Sprintf("Access level for members of the SAML group. Valid values are: %s.", renderValueListForDocs(validGroupSamlLinkAccessLevelNames)),
Type: schema.TypeString,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice(validGroupSamlLinkAccessLevelNames, false)),
Required: true,
ForceNew: true,
},
},
}
})

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

group := d.Get("group").(string)
samlGroupName := d.Get("saml_group_name").(string)
accessLevel := accessLevelNameToValue[d.Get("access_level").(string)]

options := &gitlab.AddGroupSAMLLinkOptions{
SAMLGroupName: gitlab.String(samlGroupName),
AccessLevel: gitlab.AccessLevel(accessLevel),
}

log.Printf("[DEBUG] Create GitLab Group SAML Link for group %q with name %q", group, samlGroupName)
SamlLink, _, err := client.Groups.AddGroupSAMLLink(group, options, gitlab.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

d.SetId(buildTwoPartID(&group, &SamlLink.Name))
return resourceGitlabGroupSamlLinkRead(ctx, d, meta)
}

func resourceGitlabGroupSamlLinkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*gitlab.Client)
group, samlGroupName, parse_err := parseTwoPartID(d.Id())
if parse_err != nil {
return diag.FromErr(parse_err)
}

// Try to fetch all group links from GitLab
log.Printf("[DEBUG] Read GitLab Group SAML Link for group %q", group)
samlLink, _, err := client.Groups.GetGroupSAMLLink(group, samlGroupName, nil, gitlab.WithContext(ctx))
if err != nil {
if is404(err) {
log.Printf("[DEBUG] GitLab SAML Group Link %s for group ID %s not found, removing from state", samlGroupName, group)
d.SetId("")
return nil
}
return diag.FromErr(err)
}

d.Set("group", group)
d.Set("access_level", accessLevelValueToName[samlLink.AccessLevel])
d.Set("saml_group_name", samlLink.Name)

return nil
}

func resourceGitlabGroupSamlLinkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*gitlab.Client)
group, samlGroupName, parse_err := parseTwoPartID(d.Id())
if parse_err != nil {
return diag.FromErr(parse_err)
}

log.Printf("[DEBUG] Delete GitLab Group SAML Link for group %q with name %q", group, samlGroupName)
_, err := client.Groups.DeleteGroupSAMLLink(group, samlGroupName, gitlab.WithContext(ctx))
if err != nil {
if is404(err) {
log.Printf("[WARNING] %s", err)
} else {
return diag.FromErr(err)
}
}

return nil
}
80 changes: 80 additions & 0 deletions internal/provider/resource_gitlab_group_saml_link_test.go
@@ -0,0 +1,80 @@
//go:build acceptance
// +build acceptance

package provider

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccGitlabGroupSamlLink_basic(t *testing.T) {
testAccCheckEE(t)
testAccRequiresAtLeast(t, "15.3")

testGroup := testAccCreateGroups(t, 1)[0]

resource.ParallelTest(t, resource.TestCase{
mhodgson marked this conversation as resolved.
Show resolved Hide resolved
ProviderFactories: providerFactories,
CheckDestroy: testAccCheckGitlabGroupSamlLinkDestroy,
Steps: []resource.TestStep{

// Create a group SAML link as a developer
{
Config: fmt.Sprintf(`
resource "gitlab_group_saml_link" "this" {
group = "%d"
access_level = "developer"
saml_group_name = "test_saml_group"

}
`, testGroup.ID),
},
// Verify Import
{
ResourceName: "gitlab_group_saml_link.this",
ImportState: true,
ImportStateVerify: true,
},
// Update the group SAML link to change the access level
{
Config: fmt.Sprintf(`
resource "gitlab_group_saml_link" "this" {
group = "%d"
access_level = "maintainer"
saml_group_name = "test_saml_group"

}
`, testGroup.ID),
},
},
})
}

func testAccCheckGitlabGroupSamlLinkDestroy(s *terraform.State) error {
for _, resourceState := range s.RootModule().Resources {
if resourceState.Type != "gitlab_group_saml_link" {
continue
}

group, samlGroupName, err := parseTwoPartID(resourceState.Primary.ID)
if err != nil {
return err
}

samlGroupLink, _, err := testGitlabClient.Groups.GetGroupSAMLLink(group, samlGroupName)
if err == nil {
if samlGroupLink != nil {
return fmt.Errorf("SAML Group Link still exists")
}
}
if !is404(err) {
return err
}
return nil
}
return nil
}