mirror of
https://github.com/ysoftdevs/terraform-provider-bitbucketserver.git
synced 2026-03-30 14:12:01 +02:00
feat(#4) Add resource_repository_deploy_key
Allows to add an ssh key to a given repository. This should allow to make build servers with more restricted access controls.
This commit is contained in:
@@ -62,6 +62,7 @@ func Provider() terraform.ResourceProvider {
|
||||
"bitbucketserver_project_permissions_group": resourceProjectPermissionsGroup(),
|
||||
"bitbucketserver_project_permissions_user": resourceProjectPermissionsUser(),
|
||||
"bitbucketserver_repository": resourceRepository(),
|
||||
"bitbucketserver_repository_deploy_key": resourceRepositoryDeployKey(),
|
||||
"bitbucketserver_repository_hook": resourceRepositoryHook(),
|
||||
"bitbucketserver_repository_permissions_group": resourceRepositoryPermissionsGroup(),
|
||||
"bitbucketserver_repository_permissions_user": resourceRepositoryPermissionsUser(),
|
||||
|
||||
233
bitbucket/resource_repository_deploy_key.go
Normal file
233
bitbucket/resource_repository_deploy_key.go
Normal file
@@ -0,0 +1,233 @@
|
||||
package bitbucket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type SSHKey struct {
|
||||
ID int `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
CreatedDate jsonTime `json:"createdDate,omitempty"`
|
||||
UpdatedDate jsonTime `json:"updatedDate,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Active bool `json:"active"`
|
||||
Events []interface{} `json:"events"`
|
||||
Configuration WebhookConfiguration `json:"configuration"`
|
||||
}
|
||||
|
||||
func resourceRepositoryDeployKey() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceRepositoryDeployKeyCreate,
|
||||
Read: resourceRepositoryDeployKeyRead,
|
||||
Delete: resourceRepositoryDeployKeyDelete,
|
||||
Schema: map[string]*schema.Schema{
|
||||
"project": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"repository": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"key": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"label": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"permission": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validation.StringInSlice([]string{"REPO_READ", "REPO_WRITE", "REPO_ADMIN"}, false),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type KeyRequestKey struct {
|
||||
Label string `json:"label"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type KeyRequest struct {
|
||||
Key KeyRequestKey `json:"key"`
|
||||
Permission string `json:"permission"`
|
||||
}
|
||||
|
||||
type KeyResponse struct {
|
||||
Key struct {
|
||||
Id int `json:"id"`
|
||||
ExpiryDays int `json:"expiryDays"`
|
||||
BitLength int `json:"bitLength"`
|
||||
AlgorithmType string `json:"algorithmType"`
|
||||
CreatedDate string `json:"createdDate"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
LastAuthenticated string `json:"lastAuthenticated"`
|
||||
Label string `json:"label"`
|
||||
Text string `json:"text"`
|
||||
} `json:"key"`
|
||||
Permission string `json:"permission"`
|
||||
Project struct {
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
Id int `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Public bool `json:"public"`
|
||||
Avatar string `json:"avatar"`
|
||||
Description string `json:"description"`
|
||||
Namespace string `json:"namespace"`
|
||||
Scope string `json:"scope"`
|
||||
} `json:"project"`
|
||||
Repository struct {
|
||||
Name string `json:"name"`
|
||||
Id int `json:"id"`
|
||||
State string `json:"state"`
|
||||
Public bool `json:"public"`
|
||||
DefaultBranch string `json:"defaultBranch"`
|
||||
HierarchyId string `json:"hierarchyId"`
|
||||
StatusMessage string `json:"statusMessage"`
|
||||
Archived bool `json:"archived"`
|
||||
Forkable bool `json:"forkable"`
|
||||
RelatedLinks struct {
|
||||
} `json:"relatedLinks"`
|
||||
Partition int `json:"partition"`
|
||||
Origin struct {
|
||||
Name string `json:"name"`
|
||||
Id int `json:"id"`
|
||||
State string `json:"state"`
|
||||
Public bool `json:"public"`
|
||||
DefaultBranch string `json:"defaultBranch"`
|
||||
HierarchyId string `json:"hierarchyId"`
|
||||
StatusMessage string `json:"statusMessage"`
|
||||
Archived bool `json:"archived"`
|
||||
Forkable bool `json:"forkable"`
|
||||
RelatedLinks struct {
|
||||
} `json:"relatedLinks"`
|
||||
Partition int `json:"partition"`
|
||||
Description string `json:"description"`
|
||||
Project struct {
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
Id int `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Public bool `json:"public"`
|
||||
Avatar string `json:"avatar"`
|
||||
Description string `json:"description"`
|
||||
Namespace string `json:"namespace"`
|
||||
Scope string `json:"scope"`
|
||||
} `json:"project"`
|
||||
Scope string `json:"scope"`
|
||||
ScmId string `json:"scmId"`
|
||||
Slug string `json:"slug"`
|
||||
} `json:"origin"`
|
||||
Description string `json:"description"`
|
||||
Project struct {
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
Id int `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Public bool `json:"public"`
|
||||
Avatar string `json:"avatar"`
|
||||
Description string `json:"description"`
|
||||
Namespace string `json:"namespace"`
|
||||
Scope string `json:"scope"`
|
||||
} `json:"project"`
|
||||
Scope string `json:"scope"`
|
||||
ScmId string `json:"scmId"`
|
||||
Slug string `json:"slug"`
|
||||
} `json:"repository"`
|
||||
}
|
||||
|
||||
func resourceRepositoryDeployKeyCreate(d *schema.ResourceData, m interface{}) error {
|
||||
keyRequest := &KeyRequest{
|
||||
Key: KeyRequestKey{
|
||||
Label: d.Get("label").(string),
|
||||
Text: d.Get("key").(string),
|
||||
},
|
||||
Permission: d.Get("permission").(string),
|
||||
}
|
||||
|
||||
request, err := json.Marshal(keyRequest)
|
||||
|
||||
client := m.(*BitbucketServerProvider).BitbucketClient
|
||||
resp, err := client.Post(fmt.Sprintf("/rest/keys/latest/projects/%s/repos/%s/ssh",
|
||||
url.QueryEscape(d.Get("project").(string)),
|
||||
url.QueryEscape(d.Get("repository").(string)),
|
||||
), bytes.NewBuffer(request))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return storeResponse(d, resp)
|
||||
}
|
||||
|
||||
func resourceRepositoryDeployKeyRead(d *schema.ResourceData, m interface{}) error {
|
||||
client := m.(*BitbucketServerProvider).BitbucketClient
|
||||
|
||||
resp, err := client.Get(fmt.Sprintf("/rest/keys/latest/projects/%s/repos/%s/ssh/%s",
|
||||
url.QueryEscape(d.Get("project").(string)),
|
||||
url.QueryEscape(d.Get("repository").(string)),
|
||||
url.QueryEscape(d.Id()),
|
||||
))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return storeResponse(d, resp)
|
||||
}
|
||||
|
||||
func resourceRepositoryDeployKeyDelete(d *schema.ResourceData, m interface{}) error {
|
||||
client := m.(*BitbucketServerProvider).BitbucketClient
|
||||
_, err := client.Delete(fmt.Sprintf("/rest/keys/latest/projects/%s/repos/%s/ssh/%s",
|
||||
url.QueryEscape(d.Get("project").(string)),
|
||||
url.QueryEscape(d.Get("repository").(string)),
|
||||
url.QueryEscape(d.Id()),
|
||||
))
|
||||
return err
|
||||
}
|
||||
|
||||
func storeResponse(d *schema.ResourceData, resp *http.Response) error {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var keyResponse KeyResponse
|
||||
err = json.Unmarshal(body, &keyResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(strconv.Itoa(keyResponse.Key.Id))
|
||||
labelError := store(d, keyResponse, keyResponse.Key.Label, "label")
|
||||
permissionError := store(d, keyResponse, keyResponse.Permission, "permission")
|
||||
keyError := store(d, keyResponse, keyResponse.Key.Text, "key")
|
||||
projectError := store(d, keyResponse, keyResponse.Repository.Project.Key, "project")
|
||||
repositoryError := store(d, keyResponse, keyResponse.Repository.Slug, "repository")
|
||||
|
||||
return errors.Join(labelError, permissionError, keyError, projectError, repositoryError)
|
||||
}
|
||||
|
||||
func store(d *schema.ResourceData, keyResponse KeyResponse, value string, name string) error {
|
||||
if value == "" {
|
||||
respAsJson, _ := json.Marshal(keyResponse)
|
||||
return errors.New(fmt.Sprintf("%s is nil in %s", name, string(respAsJson)))
|
||||
} else {
|
||||
return d.Set(name, value)
|
||||
}
|
||||
}
|
||||
50
bitbucket/resource_repository_deploy_key_test.go
Normal file
50
bitbucket/resource_repository_deploy_key_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package bitbucket
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccBitbucketResourceRepositoryDeployKey(t *testing.T) {
|
||||
projectKey := fmt.Sprintf("TEST%v", rand.New(rand.NewSource(time.Now().UnixNano())).Int())
|
||||
|
||||
config := fmt.Sprintf(`
|
||||
resource "bitbucketserver_project" "test" {
|
||||
key = "%v"
|
||||
name = "test-project-%v"
|
||||
}
|
||||
|
||||
resource "bitbucketserver_repository" "test" {
|
||||
project = bitbucketserver_project.test.key
|
||||
name = "repo"
|
||||
}
|
||||
|
||||
resource "bitbucketserver_repository_deploy_key" "test" {
|
||||
project = bitbucketserver_project.test.key
|
||||
repository = bitbucketserver_repository.test.slug
|
||||
label = "newLabelForTest"
|
||||
key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQD1F2KTOi8ptpqkXdcARgYy27uWRCav1isJUB3Hz59MDM6CSAXa+HCgUNDV+6gXQ1eR24nr1Efb7AkEM8LmvMkNlQqpAsPEPxVlndA0KSRLXb3mWruJzkZtrJo1HhVDffuKnevPLFkB75wyBX3jn1FNtc2qfc2i80mu8TfviZnOPYnrRa8B2S9Q8IlUtXAyihQ1G3fn5r5nxrw3QQGrD3cckB9nCZpzAPn6hlDHVk6n5efoWAUxM5AhKln0OLsA1HwjGJN7/dbDPu1nSLuiJSAISSSg4E4SNdfnr3FOhTA79AKNzsor2/EXdbG+f+S4op3s3wtt05zwkHLXRSqKYoT31RFiV9d1XIav+dGTvXCgc6DNG6rbogE6ZbugDZXdcHOAoNs7IUDFbtI/HGKS7CStxAUEchoxM8HDYXmhYt1kUEpmP3g2ckILHGoGPEkOCYGPqx5HbDvAXAJVk3DdSOibCckR2FK2qEoCbMgnPUX84CqNJPHBZ24AaE8htE6TKr0= user@somewhere"
|
||||
permission = "REPO_READ"
|
||||
}
|
||||
`, projectKey, projectKey)
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttrSet("bitbucketserver_repository_deploy_key.test", "id"),
|
||||
resource.TestCheckResourceAttr("bitbucketserver_repository_deploy_key.test", "project", projectKey),
|
||||
resource.TestCheckResourceAttr("bitbucketserver_repository_deploy_key.test", "repository", "repo"),
|
||||
resource.TestCheckResourceAttr("bitbucketserver_repository_deploy_key.test", "key", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQD1F2KTOi8ptpqkXdcARgYy27uWRCav1isJUB3Hz59MDM6CSAXa+HCgUNDV+6gXQ1eR24nr1Efb7AkEM8LmvMkNlQqpAsPEPxVlndA0KSRLXb3mWruJzkZtrJo1HhVDffuKnevPLFkB75wyBX3jn1FNtc2qfc2i80mu8TfviZnOPYnrRa8B2S9Q8IlUtXAyihQ1G3fn5r5nxrw3QQGrD3cckB9nCZpzAPn6hlDHVk6n5efoWAUxM5AhKln0OLsA1HwjGJN7/dbDPu1nSLuiJSAISSSg4E4SNdfnr3FOhTA79AKNzsor2/EXdbG+f+S4op3s3wtt05zwkHLXRSqKYoT31RFiV9d1XIav+dGTvXCgc6DNG6rbogE6ZbugDZXdcHOAoNs7IUDFbtI/HGKS7CStxAUEchoxM8HDYXmhYt1kUEpmP3g2ckILHGoGPEkOCYGPqx5HbDvAXAJVk3DdSOibCckR2FK2qEoCbMgnPUX84CqNJPHBZ24AaE8htE6TKr0= user@somewhere"),
|
||||
resource.TestCheckResourceAttr("bitbucketserver_repository_deploy_key.test", "label", "newLabelForTest"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user