From 395f1d5bbf19c3141d35f1a0bec291efc5739d6c Mon Sep 17 00:00:00 2001 From: Richard Clamp Date: Wed, 24 May 2017 11:41:40 +0100 Subject: [PATCH] provider/gitlab: add `gitlab_deploy_key` (#14734) * provider/gitlab: add `gitlab_deploy_key` Here we extend the gitlab provider further by adding a `gitlab_deploy_key` resource. This resource allows management of a projects deploy keys. * provider/gitlab: Do not test `gitlab_deploy_key` `can_push` Here we remove the testing of the `can_push` attribute. This makes the tests less comprehensive, but will allow them to work with the current release of gitlab-ce. This change is staged as a distinct commit so it can be easily dropped/reverted once gitlab MR !11607 has reached a released state. https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11607 * provider/gitlab: Update docs for gitlab_deploy_key/can_push Note that the can_push attribute of gitlab_deploy_key doesn't currently work. This note can be removed once https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11607 is merged and in general circulation. --- builtin/providers/gitlab/provider.go | 1 + .../gitlab/resource_gitlab_deploy_key.go | 107 +++++++++++ .../gitlab/resource_gitlab_deploy_key_test.go | 170 ++++++++++++++++++ .../gitlab/r/deploy_key.html.markdown | 34 ++++ 4 files changed, 312 insertions(+) create mode 100644 builtin/providers/gitlab/resource_gitlab_deploy_key.go create mode 100644 builtin/providers/gitlab/resource_gitlab_deploy_key_test.go create mode 100644 website/source/docs/providers/gitlab/r/deploy_key.html.markdown diff --git a/builtin/providers/gitlab/provider.go b/builtin/providers/gitlab/provider.go index 097dc39e1..9e8b5be4f 100644 --- a/builtin/providers/gitlab/provider.go +++ b/builtin/providers/gitlab/provider.go @@ -27,6 +27,7 @@ func Provider() terraform.ResourceProvider { ResourcesMap: map[string]*schema.Resource{ "gitlab_project": resourceGitlabProject(), "gitlab_project_hook": resourceGitlabProjectHook(), + "gitlab_deploy_key": resourceGitlabDeployKey(), }, ConfigureFunc: providerConfigure, diff --git a/builtin/providers/gitlab/resource_gitlab_deploy_key.go b/builtin/providers/gitlab/resource_gitlab_deploy_key.go new file mode 100644 index 000000000..8da54fb8e --- /dev/null +++ b/builtin/providers/gitlab/resource_gitlab_deploy_key.go @@ -0,0 +1,107 @@ +package gitlab + +import ( + "fmt" + "log" + "strconv" + + "github.com/hashicorp/terraform/helper/schema" + gitlab "github.com/xanzy/go-gitlab" +) + +func resourceGitlabDeployKey() *schema.Resource { + return &schema.Resource{ + Create: resourceGitlabDeployKeyCreate, + Read: resourceGitlabDeployKeyRead, + Delete: resourceGitlabDeployKeyDelete, + + Schema: map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "title": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "key": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "can_push": { + Type: schema.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + }, + }, + } +} + +func resourceGitlabDeployKeyCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*gitlab.Client) + project := d.Get("project").(string) + options := &gitlab.AddDeployKeyOptions{ + Title: gitlab.String(d.Get("title").(string)), + Key: gitlab.String(d.Get("key").(string)), + CanPush: gitlab.Bool(d.Get("can_push").(bool)), + } + + log.Printf("[DEBUG] create gitlab deployment key %s", *options.Title) + + deployKey, _, err := client.DeployKeys.AddDeployKey(project, options) + if err != nil { + return err + } + + d.SetId(fmt.Sprintf("%d", deployKey.ID)) + + return resourceGitlabDeployKeyRead(d, meta) +} + +func resourceGitlabDeployKeyRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*gitlab.Client) + project := d.Get("project").(string) + deployKeyID, err := strconv.Atoi(d.Id()) + if err != nil { + return err + } + log.Printf("[DEBUG] read gitlab deploy key %s/%d", project, deployKeyID) + + deployKey, response, err := client.DeployKeys.GetDeployKey(project, deployKeyID) + if err != nil { + if response.StatusCode == 404 { + log.Printf("[WARN] removing deploy key %d from state because it no longer exists in gitlab", deployKeyID) + d.SetId("") + return nil + } + + return err + } + + d.Set("title", deployKey.Title) + d.Set("key", deployKey.Key) + d.Set("can_push", deployKey.CanPush) + return nil +} + +func resourceGitlabDeployKeyDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*gitlab.Client) + project := d.Get("project").(string) + deployKeyID, err := strconv.Atoi(d.Id()) + if err != nil { + return err + } + log.Printf("[DEBUG] Delete gitlab deploy key %s", d.Id()) + + response, err := client.DeployKeys.DeleteDeployKey(project, deployKeyID) + + // HTTP 204 is success with no body + if response.StatusCode == 204 { + return nil + } + return err +} diff --git a/builtin/providers/gitlab/resource_gitlab_deploy_key_test.go b/builtin/providers/gitlab/resource_gitlab_deploy_key_test.go new file mode 100644 index 000000000..44a1841c0 --- /dev/null +++ b/builtin/providers/gitlab/resource_gitlab_deploy_key_test.go @@ -0,0 +1,170 @@ +package gitlab + +import ( + "fmt" + "strconv" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/xanzy/go-gitlab" +) + +func TestAccGitlabDeployKey_basic(t *testing.T) { + var deployKey gitlab.DeployKey + rInt := acctest.RandInt() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckGitlabDeployKeyDestroy, + Steps: []resource.TestStep{ + // Create a project and deployKey with default options + { + Config: testAccGitlabDeployKeyConfig(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckGitlabDeployKeyExists("gitlab_deploy_key.foo", &deployKey), + testAccCheckGitlabDeployKeyAttributes(&deployKey, &testAccGitlabDeployKeyExpectedAttributes{ + Title: fmt.Sprintf("deployKey-%d", rInt), + Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCj13ozEBZ0s4el4k6mYqoyIKKKMh9hHY0sAYqSPXs2zGuVFZss1P8TPuwmdXVjHR7TiRXwC49zDrkyWJgiufggYJ1VilOohcMOODwZEJz+E5q4GCfHuh90UEh0nl8B2R0Uoy0LPeg93uZzy0hlHApsxRf/XZJz/1ytkZvCtxdllxfImCVxJReMeRVEqFCTCvy3YuJn0bce7ulcTFRvtgWOpQsr6GDK8YkcCCv2eZthVlrEwy6DEpAKTRiRLGgUj4dPO0MmO4cE2qD4ualY01PhNORJ8Q++I+EtkGt/VALkecwFuBkl18/gy+yxNJHpKc/8WVVinDeFrd/HhiY9yU0d richardc@tamborine.example.1", + }), + ), + }, + // Update the project deployKey to toggle all the values to their inverse + { + Config: testAccGitlabDeployKeyUpdateConfig(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckGitlabDeployKeyExists("gitlab_deploy_key.foo", &deployKey), + testAccCheckGitlabDeployKeyAttributes(&deployKey, &testAccGitlabDeployKeyExpectedAttributes{ + Title: fmt.Sprintf("modifiedDeployKey-%d", rInt), + Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6pSke2kb7YBjo65xDKegbOQsAtnMupRcFxXji7L1iXivGwORq0qpC2xzbhez5jk1WgPckEaNv2/Bz0uEW6oSIXw1KT1VN2WzEUfQCbpNyZPtn4iV3nyl6VQW/Nd1SrxiFJtH1H4vu+eCo4McMXTjuBBD06fiJNrHaSw734LjQgqtXWJuVym9qS5MqraZB7wDwTQwSM6kslL7KTgmo3ONsTLdb2zZhv6CS+dcFKinQo7/ttTmeMuXGbPOVuNfT/bePVIN1MF1TislHa2L2dZdGeoynNJT4fVPjA2Xl6eHWh4ySbvnfPznASsjBhP0n/QKprYJ/5fQShdBYBcuQiIMd richardc@tamborine.example.2", + }), + ), + }, + // Update the project deployKey to toggle the options back + { + Config: testAccGitlabDeployKeyConfig(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckGitlabDeployKeyExists("gitlab_deploy_key.foo", &deployKey), + testAccCheckGitlabDeployKeyAttributes(&deployKey, &testAccGitlabDeployKeyExpectedAttributes{ + Title: fmt.Sprintf("deployKey-%d", rInt), + Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCj13ozEBZ0s4el4k6mYqoyIKKKMh9hHY0sAYqSPXs2zGuVFZss1P8TPuwmdXVjHR7TiRXwC49zDrkyWJgiufggYJ1VilOohcMOODwZEJz+E5q4GCfHuh90UEh0nl8B2R0Uoy0LPeg93uZzy0hlHApsxRf/XZJz/1ytkZvCtxdllxfImCVxJReMeRVEqFCTCvy3YuJn0bce7ulcTFRvtgWOpQsr6GDK8YkcCCv2eZthVlrEwy6DEpAKTRiRLGgUj4dPO0MmO4cE2qD4ualY01PhNORJ8Q++I+EtkGt/VALkecwFuBkl18/gy+yxNJHpKc/8WVVinDeFrd/HhiY9yU0d richardc@tamborine.example.1", + }), + ), + }, + }, + }) +} + +func testAccCheckGitlabDeployKeyExists(n string, deployKey *gitlab.DeployKey) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not Found: %s", n) + } + + deployKeyID, err := strconv.Atoi(rs.Primary.ID) + if err != nil { + return err + } + repoName := rs.Primary.Attributes["project"] + if repoName == "" { + return fmt.Errorf("No project ID is set") + } + conn := testAccProvider.Meta().(*gitlab.Client) + + gotDeployKey, _, err := conn.DeployKeys.GetDeployKey(repoName, deployKeyID) + if err != nil { + return err + } + *deployKey = *gotDeployKey + return nil + } +} + +type testAccGitlabDeployKeyExpectedAttributes struct { + Title string + Key string + CanPush bool +} + +func testAccCheckGitlabDeployKeyAttributes(deployKey *gitlab.DeployKey, want *testAccGitlabDeployKeyExpectedAttributes) resource.TestCheckFunc { + return func(s *terraform.State) error { + if deployKey.Title != want.Title { + return fmt.Errorf("got title %q; want %q", deployKey.Title, want.Title) + } + + if deployKey.Key != want.Key { + return fmt.Errorf("got key %q; want %q", deployKey.Key, want.Key) + } + + if deployKey.CanPush != nil && *deployKey.CanPush != want.CanPush { + return fmt.Errorf("got can_push %t; want %t", *deployKey.CanPush, want.CanPush) + } + + return nil + } +} + +func testAccCheckGitlabDeployKeyDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*gitlab.Client) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "gitlab_project" { + continue + } + deployKeyID, err := strconv.Atoi(rs.Primary.ID) + project := rs.Primary.Attributes["project"] + + gotDeployKey, resp, err := conn.DeployKeys.GetDeployKey(project, deployKeyID) + if err == nil { + if gotDeployKey != nil && fmt.Sprintf("%d", gotDeployKey.ID) == rs.Primary.ID { + return fmt.Errorf("Deploy key still exists") + } + } + if resp.StatusCode != 404 { + return err + } + return nil + } + return nil +} + +func testAccGitlabDeployKeyConfig(rInt int) string { + return fmt.Sprintf(` +resource "gitlab_project" "foo" { + name = "foo-%d" + description = "Terraform acceptance tests" + + # So that acceptance tests can be run in a gitlab organization + # with no billing + visibility_level = "public" +} + +resource "gitlab_deploy_key" "foo" { + project = "${gitlab_project.foo.id}" + title = "deployKey-%d" + key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCj13ozEBZ0s4el4k6mYqoyIKKKMh9hHY0sAYqSPXs2zGuVFZss1P8TPuwmdXVjHR7TiRXwC49zDrkyWJgiufggYJ1VilOohcMOODwZEJz+E5q4GCfHuh90UEh0nl8B2R0Uoy0LPeg93uZzy0hlHApsxRf/XZJz/1ytkZvCtxdllxfImCVxJReMeRVEqFCTCvy3YuJn0bce7ulcTFRvtgWOpQsr6GDK8YkcCCv2eZthVlrEwy6DEpAKTRiRLGgUj4dPO0MmO4cE2qD4ualY01PhNORJ8Q++I+EtkGt/VALkecwFuBkl18/gy+yxNJHpKc/8WVVinDeFrd/HhiY9yU0d richardc@tamborine.example.1" +} + `, rInt, rInt) +} + +func testAccGitlabDeployKeyUpdateConfig(rInt int) string { + return fmt.Sprintf(` +resource "gitlab_project" "foo" { + name = "foo-%d" + description = "Terraform acceptance tests" + + # So that acceptance tests can be run in a gitlab organization + # with no billing + visibility_level = "public" +} + +resource "gitlab_deploy_key" "foo" { + project = "${gitlab_project.foo.id}" + title = "modifiedDeployKey-%d" + key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6pSke2kb7YBjo65xDKegbOQsAtnMupRcFxXji7L1iXivGwORq0qpC2xzbhez5jk1WgPckEaNv2/Bz0uEW6oSIXw1KT1VN2WzEUfQCbpNyZPtn4iV3nyl6VQW/Nd1SrxiFJtH1H4vu+eCo4McMXTjuBBD06fiJNrHaSw734LjQgqtXWJuVym9qS5MqraZB7wDwTQwSM6kslL7KTgmo3ONsTLdb2zZhv6CS+dcFKinQo7/ttTmeMuXGbPOVuNfT/bePVIN1MF1TislHa2L2dZdGeoynNJT4fVPjA2Xl6eHWh4ySbvnfPznASsjBhP0n/QKprYJ/5fQShdBYBcuQiIMd richardc@tamborine.example.2" +} + `, rInt, rInt) +} diff --git a/website/source/docs/providers/gitlab/r/deploy_key.html.markdown b/website/source/docs/providers/gitlab/r/deploy_key.html.markdown new file mode 100644 index 000000000..6e95d806a --- /dev/null +++ b/website/source/docs/providers/gitlab/r/deploy_key.html.markdown @@ -0,0 +1,34 @@ +--- +layout: "gitlab" +page_title: "GitLab: gitlab_deploy_key" +sidebar_current: "docs-gitlab-resource-deploy_key" +description: |- +Creates and manages deploy keys for GitLab projects +--- + +# gitlab\_deploy\_key + +This resource allows you to create and manage deploy keys for your GitLab projects. + + +## Example Usage + +```hcl +resource "gitlab_deploy_key" "example" { + project = "example/deploying" + title = "Example deploy key" + key = "ssh-rsa AAAA..." +} +``` + +## Argument Reference + +The following arguments are supported: + +* `project` - (Required, string) The name or id of the project to add the deploy key to. + +* `title` - (Required, string) A title to describe the deploy key with. + +* `key` - (Required, string) The public ssh key body. + +* `can_push` - (Optional, boolean) Allow this deploy key to be used to push changes to the project. Defaults to `false`. **NOTE::** this cannot currently be managed.