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

Deploy token #284

Merged
merged 1 commit into from
May 31, 2020
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gitlab/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func Provider() terraform.ResourceProvider {
"gitlab_project_push_rules": resourceGitlabProjectPushRules(),
"gitlab_deploy_key": resourceGitlabDeployKey(),
"gitlab_deploy_key_enable": resourceGitlabDeployEnableKey(),
"gitlab_deploy_token": resourceGitlabDeployToken(),
"gitlab_user": resourceGitlabUser(),
"gitlab_project_membership": resourceGitlabProjectMembership(),
"gitlab_group_membership": resourceGitlabGroupMembership(),
Expand Down
201 changes: 201 additions & 0 deletions gitlab/resource_gitlab_deploy_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
package gitlab

import (
"fmt"
"log"
"net/http"
"strconv"
"time"

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

func resourceGitlabDeployToken() *schema.Resource {
return &schema.Resource{
Create: resourceGitlabDeployTokenCreate,
Read: resourceGitlabDeployTokenRead,
Delete: resourceGitlabDeployTokenDelete,

Schema: map[string]*schema.Schema{
"project": {
Type: schema.TypeString,
Optional: true,
ExactlyOneOf: []string{"project", "group"},
ForceNew: true,
},
"group": {
Type: schema.TypeString,
Optional: true,
ExactlyOneOf: []string{"project", "group"},
ForceNew: true,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"username": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"expires_at": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.ValidateRFC3339TimeString,
ForceNew: true,
},
"scopes": {
Type: schema.TypeSet,
Required: true,
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{"read_registry", "read_repository"}, false),
},
},

"token": {
Type: schema.TypeString,
Computed: true,
Sensitive: true,
},
},
}
}

func resourceGitlabDeployTokenCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
project, isProject := d.GetOk("project")
group, isGroup := d.GetOk("group")

var expiresAt time.Time
var err error

if exp, ok := d.GetOk("expires_at"); ok {
expiresAt, err = time.Parse(time.RFC3339, exp.(string))
if err != nil {
return fmt.Errorf("Invalid expires_at date: %v", err)
}
}

scopes := stringSetToStringSlice(d.Get("scopes").(*schema.Set))

var deployToken *gitlab.DeployToken

if isProject {
options := &gitlab.CreateProjectDeployTokenOptions{
Name: gitlab.String(d.Get("name").(string)),
Username: gitlab.String(d.Get("username").(string)),
ExpiresAt: gitlab.Time(expiresAt),
Scopes: *scopes,
}

log.Printf("[DEBUG] Create GitLab deploy token %s in project %s", *options.Name, project.(string))

deployToken, _, err = client.DeployTokens.CreateProjectDeployToken(project, options)

} else if isGroup {
options := &gitlab.CreateGroupDeployTokenOptions{
Name: gitlab.String(d.Get("name").(string)),
Username: gitlab.String(d.Get("username").(string)),
ExpiresAt: gitlab.Time(expiresAt),
Scopes: *scopes,
}

log.Printf("[DEBUG] Create GitLab deploy token %s in group %s", *options.Name, group.(string))

deployToken, _, err = client.DeployTokens.CreateGroupDeployToken(group, options)
}

if err != nil {
return err
}

d.SetId(fmt.Sprintf("%d", deployToken.ID))

// Token is only available on creation
d.Set("token", deployToken.Token)
d.Set("username", deployToken.Username)

return nil
}

func resourceGitlabDeployTokenRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
project, isProject := d.GetOk("project")
group, isGroup := d.GetOk("group")
deployTokenID, err := strconv.Atoi(d.Id())
if err != nil {
return err
}

var deployTokens []*gitlab.DeployToken

if isProject {
log.Printf("[DEBUG] Read GitLab deploy token %d in project %s", deployTokenID, project.(string))
deployTokens, _, err = client.DeployTokens.ListProjectDeployTokens(project, nil)

} else if isGroup {
log.Printf("[DEBUG] Read GitLab deploy token %d in group %s", deployTokenID, group.(string))
deployTokens, _, err = client.DeployTokens.ListGroupDeployTokens(group, nil)
}
if err != nil {
return err
}

for _, token := range deployTokens {
if token.ID == deployTokenID {
d.Set("name", token.Name)
d.Set("username", token.Username)
d.Set("expires_at", token.ExpiresAt.Format(time.RFC3339))

for _, scope := range token.Scopes {
if scope == "read_repository" {
d.Set("scopes.read_repository", true)
}

if scope == "read_registry" {
d.Set("scopes.read_registry", true)
}
}
}
}

return nil
}

func resourceGitlabDeployTokenDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*gitlab.Client)
project, isProject := d.GetOk("project")
group, isGroup := d.GetOk("group")
deployTokenID, err := strconv.Atoi(d.Id())
if err != nil {
return err
}

var response *gitlab.Response

if isProject {
log.Printf("[DEBUG] Delete GitLab deploy token %d in project %s", deployTokenID, project.(string))
response, err = client.DeployTokens.DeleteProjectDeployToken(project, deployTokenID)

} else if isGroup {
log.Printf("[DEBUG] Delete GitLab deploy token %d in group %s", deployTokenID, group.(string))
response, err = client.DeployTokens.DeleteGroupDeployToken(group, deployTokenID)
}
if err != nil {
return err
}

// StatusNoContent = 204
// Success with no body
if response.StatusCode != http.StatusNoContent {
return fmt.Errorf("Invalid status code returned: %s", response.Status)
}

return nil
}
167 changes: 167 additions & 0 deletions gitlab/resource_gitlab_deploy_token_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package gitlab

import (
"fmt"
"net/http"
"strconv"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/xanzy/go-gitlab"
)

func TestAccGitlabDeployToken_basic(t *testing.T) {
var deployToken gitlab.DeployToken
rInt := acctest.RandInt()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckGitlabDeployTokenDestroy,
Steps: []resource.TestStep{
{
Config: testAccGitlabDeployTokenConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckGitlabDeployTokenExists("gitlab_deploy_token.foo", &deployToken),
testAccCheckGitlabDeployTokenAttributes(&deployToken, &testAccCheckGitlabDeployTokenExpectedAttributes{
Name: fmt.Sprintf("deployToken-%d", rInt),
Username: "my-username",
}),
),
},
},
})
}

func testAccCheckGitlabDeployTokenExists(n string, deployToken *gitlab.DeployToken) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not Found: %s", n)
}

deployTokenID, err := strconv.Atoi(rs.Primary.ID)
if err != nil {
return err
}

conn := testAccProvider.Meta().(*gitlab.Client)

projectName := rs.Primary.Attributes["project"]
groupName := rs.Primary.Attributes["group"]

var gotDeployTokens []*gitlab.DeployToken

if projectName != "" {
gotDeployTokens, _, err = conn.DeployTokens.ListProjectDeployTokens(projectName, nil)
} else if groupName != "" {
gotDeployTokens, _, err = conn.DeployTokens.ListGroupDeployTokens(groupName, nil)
} else {
return fmt.Errorf("No project or group ID is set")
}

if err != nil {
return err
}

for _, token := range gotDeployTokens {
if token.ID == deployTokenID {
*deployToken = *token
return nil
}
}

return fmt.Errorf("Deploy Token doesn't exist")
}
}

type testAccCheckGitlabDeployTokenExpectedAttributes struct {
Name string
Username string
}

func testAccCheckGitlabDeployTokenAttributes(deployToken *gitlab.DeployToken, want *testAccCheckGitlabDeployTokenExpectedAttributes) resource.TestCheckFunc {
return func(s *terraform.State) error {

if deployToken.Name != want.Name {
return fmt.Errorf("got name %q; want %q", deployToken.Name, want.Name)
}

if deployToken.Username != want.Username {
return fmt.Errorf("got username %q; want %q", deployToken.Username, want.Username)
}

return nil
}
}

func testAccCheckGitlabDeployTokenDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*gitlab.Client)

for _, rs := range s.RootModule().Resources {
if rs.Type != "gitlab_deploy_token" {
continue
}

deployTokenID, err := strconv.Atoi(rs.Primary.ID)
if err != nil {
return err
}

project := rs.Primary.Attributes["project"]
group := rs.Primary.Attributes["group"]

var gotDeployTokens []*gitlab.DeployToken
var resp *gitlab.Response

if project != "" {
gotDeployTokens, resp, err = conn.DeployTokens.ListProjectDeployTokens(project, nil)
} else if group != "" {
gotDeployTokens, resp, err = conn.DeployTokens.ListGroupDeployTokens(group, nil)
} else {
return fmt.Errorf("somehow neither project nor group were set")
}

if err == nil {
for _, token := range gotDeployTokens {
if token.ID == deployTokenID {
return fmt.Errorf("Deploy token still exists")
}
}
}

if resp.StatusCode != http.StatusNotFound {
return err
}
}

return nil
}

func testAccGitlabDeployTokenConfig(rInt int) string {
return fmt.Sprintf(`
resource "gitlab_project" "foo" {
name = "foo-%d"
description = "Terraform acceptance test"

# So that acceptance tests can be run in a gitlab organization
# with no billing
visibility_level = "public"
}

resource "gitlab_deploy_token" "foo" {
project = "${gitlab_project.foo.id}"
name = "deployToken-%d"
username = "my-username"

expires_at = "2021-03-14T07:20:50Z"

scopes = [
"read_registry",
"read_repository",
]
}
`, rInt, rInt)
}
Loading