Skip to content

Commit

Permalink
Merge pull request #1243 from gitlabhq/feature/saml-group-links
Browse files Browse the repository at this point in the history
resource/gitlab_group_saml_link: Add new resource
  • Loading branch information
PatrickRice-KSC committed Sep 5, 2022
2 parents e37d0f2 + c0d5f3a commit 6270719
Show file tree
Hide file tree
Showing 5 changed files with 258 additions and 0 deletions.
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.
- `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{
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
}

0 comments on commit 6270719

Please sign in to comment.