Skip to content

Commit

Permalink
added argocd_repository_credentials resource (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
oboukili committed Jul 15, 2020
1 parent 0335263 commit 7386dec
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 13 deletions.
2 changes: 2 additions & 0 deletions argocd/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/argoproj/argo-cd/pkg/apiclient"
"github.com/argoproj/argo-cd/pkg/apiclient/application"
"github.com/argoproj/argo-cd/pkg/apiclient/project"
"github.com/argoproj/argo-cd/pkg/apiclient/repocreds"
"github.com/argoproj/argo-cd/pkg/apiclient/repository"
"github.com/argoproj/argo-cd/pkg/apiclient/version"
)
Expand All @@ -29,6 +30,7 @@ type ServerInterface struct {
ApplicationClient *application.ApplicationServiceClient
ProjectClient *project.ProjectServiceClient
RepositoryClient *repository.RepositoryServiceClient
RepoCredsClient *repocreds.RepoCredsServiceClient
ServerVersion *semver.Version
ServerVersionMessage *version.VersionMessage
}
Expand Down
19 changes: 15 additions & 4 deletions argocd/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/argoproj/argo-cd/pkg/apiclient"
"github.com/argoproj/argo-cd/pkg/apiclient/application"
"github.com/argoproj/argo-cd/pkg/apiclient/project"
"github.com/argoproj/argo-cd/pkg/apiclient/repocreds"
"github.com/argoproj/argo-cd/pkg/apiclient/repository"
"github.com/argoproj/argo-cd/pkg/apiclient/session"
util "github.com/argoproj/gitops-engine/pkg/utils/io"
Expand Down Expand Up @@ -101,10 +102,11 @@ func Provider(doneCh chan bool) terraform.ResourceProvider {
},

ResourcesMap: map[string]*schema.Resource{
"argocd_application": resourceArgoCDApplication(),
"argocd_project": resourceArgoCDProject(),
"argocd_project_token": resourceArgoCDProjectToken(),
"argocd_repository": resourceArgoCDRepository(),
"argocd_application": resourceArgoCDApplication(),
"argocd_project": resourceArgoCDProject(),
"argocd_project_token": resourceArgoCDProjectToken(),
"argocd_repository": resourceArgoCDRepository(),
"argocd_repository_credentials": resourceArgoCDRepositoryCredentials(),
},
ConfigureFunc: func(d *schema.ResourceData) (interface{}, error) {
apiClient, err := initApiClient(d)
Expand All @@ -126,18 +128,25 @@ func Provider(doneCh chan bool) terraform.ResourceProvider {
return nil, err
}

rcredsCloser, repoCredsClient, err := apiClient.NewRepoCredsClient()
if err != nil {
return nil, err
}

// Clients connection pooling, close when the provider execution ends
go func(done chan bool) {
<-done
util.Close(pcCloser)
util.Close(acCloser)
util.Close(rcCloser)
util.Close(rcredsCloser)
}(doneCh)
return initServerInterface(
apiClient,
projectClient,
applicationClient,
repositoryClient,
repoCredsClient,
)
},
}
Expand All @@ -148,6 +157,7 @@ func initServerInterface(
projectClient project.ProjectServiceClient,
applicationClient application.ApplicationServiceClient,
repositoryClient repository.RepositoryServiceClient,
repoCredsClient repocreds.RepoCredsServiceClient,
) (interface{}, error) {
acCloser, versionClient, err := apiClient.NewVersionClient()
if err != nil {
Expand All @@ -172,6 +182,7 @@ func initServerInterface(
&applicationClient,
&projectClient,
&repositoryClient,
&repoCredsClient,
serverVersion,
serverVersionMessage}, err
}
Expand Down
108 changes: 108 additions & 0 deletions argocd/resource_argocd_repository_credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package argocd

import (
"context"
"github.com/argoproj/argo-cd/pkg/apiclient/repocreds"
application "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"strings"
)

func resourceArgoCDRepositoryCredentials() *schema.Resource {
return &schema.Resource{
Create: resourceArgoCDRepositoryCredentialsCreate,
Read: resourceArgoCDRepositoryCredentialsRead,
Update: resourceArgoCDRepositoryCredentialsUpdate,
Delete: resourceArgoCDRepositoryCredentialsDelete,
// TODO: add importer acceptance tests
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: repositoryCredentialsSchema(),
}
}

func resourceArgoCDRepositoryCredentialsCreate(d *schema.ResourceData, meta interface{}) error {
server := meta.(ServerInterface)
c := *server.RepoCredsClient
repoCreds := expandRepositoryCredentials(d)
rc, err := c.CreateRepositoryCredentials(
context.Background(),
&repocreds.RepoCredsCreateRequest{
Creds: repoCreds,
Upsert: false,
},
)
if err != nil {
return err
}
d.SetId(rc.URL)
return resourceArgoCDRepositoryCredentialsRead(d, meta)
}

func resourceArgoCDRepositoryCredentialsRead(d *schema.ResourceData, meta interface{}) error {
server := meta.(ServerInterface)
c := *server.RepoCredsClient
rc := application.RepoCreds{}
rcl, err := c.ListRepositoryCredentials(context.Background(), &repocreds.RepoCredsQuery{
Url: d.Id(),
})
if err != nil {
// TODO: check for NotFound condition?
return err
}
if rcl == nil {
// Repository credentials have already been deleted in an out-of-band fashion
d.SetId("")
return nil
}
for i, _rc := range rcl.Items {
if _rc.URL == d.Id() {
rc = _rc
break
}
// Repository credentials have already been deleted in an out-of-band fashion
if i == len(rcl.Items)-1 {
d.SetId("")
return nil
}
}
return flattenRepositoryCredentials(rc, d)
}

func resourceArgoCDRepositoryCredentialsUpdate(d *schema.ResourceData, meta interface{}) error {
server := meta.(ServerInterface)
c := *server.RepoCredsClient
repoCreds := expandRepositoryCredentials(d)
r, err := c.UpdateRepositoryCredentials(
context.Background(),
&repocreds.RepoCredsUpdateRequest{
Creds: repoCreds},
)
if err != nil {
switch strings.Contains(err.Error(), "NotFound") {
// Repository credentials have already been deleted in an out-of-band fashion
case true:
d.SetId("")
return nil
default:
return err
}
}
d.SetId(r.URL)
return resourceArgoCDRepositoryCredentialsRead(d, meta)
}

func resourceArgoCDRepositoryCredentialsDelete(d *schema.ResourceData, meta interface{}) error {
server := meta.(ServerInterface)
c := *server.RepoCredsClient
_, err := c.DeleteRepositoryCredentials(
context.Background(),
&repocreds.RepoCredsDeleteRequest{Url: d.Id()},
)
if err != nil {
return err
}
d.SetId("")
return nil
}
67 changes: 67 additions & 0 deletions argocd/resource_argocd_repository_credentials_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package argocd

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"testing"
)

func TestAccArgoCDRepositoryCredentials(t *testing.T) {
repoUrl := fmt.Sprintf("https://git.local/%s/%s",
acctest.RandString(10),
acctest.RandString(10))
username := fmt.Sprintf(acctest.RandString(10))
sshPrivateKey, err := generateSSHPrivateKey()
if err != nil {
panic(err)
}
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccArgoCDRepositoryCredentialsSimple(repoUrl, username, sshPrivateKey),
Check: resource.TestCheckResourceAttr(
"argocd_repository_credentials.simple",
"username",
username,
),
},
},
})
}

func testAccArgoCDRepositoryCredentialsSimple(repoUrl, username, sshPrivateKey string) string {
return fmt.Sprintf(`
resource "argocd_repository_credentials" "simple" {
url = "%s"
username = "%s"
ssh_private_key = <<EOT
%s
EOT
}
`, repoUrl, username, sshPrivateKey)
}

func generateSSHPrivateKey() (privateKey string, err error) {
pk, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return
}
err = pk.Validate()
if err != nil {
return
}
privDER := x509.MarshalPKCS1PrivateKey(pk)
privBlock := pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: privDER,
}
return string(pem.EncodeToMemory(&privBlock)), nil
}
52 changes: 52 additions & 0 deletions argocd/schema_repository_credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package argocd

import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func repositoryCredentialsSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"url": {
Type: schema.TypeString,
Description: "URL is the URL that this credentials matches to",
Required: true,
},
"username": {
Type: schema.TypeString,
Description: "Username for authenticating at the repo server",
Optional: true,
},
"password": {
Type: schema.TypeString,
Sensitive: true,
Description: "Password for authenticating at the repo server, cannot be managed once created!",
Optional: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return true
},
},
"ssh_private_key": {
Type: schema.TypeString,
Sensitive: true,
Description: "SSH private key data for authenticating at the repo server only for Git repos, cannot be managed once created!",
// TODO: add a validator
Optional: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return true
},
},
"tls_client_cert_data": {
Type: schema.TypeString,
Description: "TLS client cert data for authenticating at the repo server",
// TODO: add a validator
Optional: true,
},
"tls_client_cert_key": {
Type: schema.TypeString,
Sensitive: true,
Description: "TLS client cert key for authenticating at the repo server ",
// TODO: add a validator
Optional: true,
},
}
}
9 changes: 0 additions & 9 deletions argocd/structure_repository.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package argocd

import (
"fmt"
application "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
Expand Down Expand Up @@ -64,18 +63,10 @@ func flattenRepository(repository *application.Repository, d *schema.ResourceDat
"tls_client_cert_key": repository.TLSClientCertKey,
"type": repository.Type,
}

for k, v := range r {
if err := persistToState(k, v, d); err != nil {
return err
}
}
return nil
}

func persistToState(key string, data interface{}, d *schema.ResourceData) error {
if err := d.Set(key, data); err != nil {
return fmt.Errorf("error persisting %s: %s", key, err)
}
return nil
}
51 changes: 51 additions & 0 deletions argocd/structure_repository_credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package argocd

import (
application "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"

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

// Expand

func expandRepositoryCredentials(d *schema.ResourceData) *application.RepoCreds {
repoCreds := &application.RepoCreds{}
if v, ok := d.GetOk("url"); ok {
repoCreds.URL = v.(string)
}
if v, ok := d.GetOk("username"); ok {
repoCreds.Username = v.(string)
}
if v, ok := d.GetOk("password"); ok {
repoCreds.Password = v.(string)
}
if v, ok := d.GetOk("ssh_private_key"); ok {
repoCreds.SSHPrivateKey = v.(string)
}
if v, ok := d.GetOk("tls_client_cert_data"); ok {
repoCreds.TLSClientCertData = v.(string)
}
if v, ok := d.GetOk("tls_client_cert_key"); ok {
repoCreds.TLSClientCertKey = v.(string)
}
return repoCreds
}

// Flatten

func flattenRepositoryCredentials(repository application.RepoCreds, d *schema.ResourceData) error {
r := map[string]interface{}{
"url": repository.URL,
"username": repository.Username,
"password": repository.Password,
"ssh_private_key": repository.SSHPrivateKey,
"tls_client_cert_data": repository.TLSClientCertData,
"tls_client_cert_key": repository.TLSClientCertKey,
}
for k, v := range r {
if err := persistToState(k, v, d); err != nil {
return err
}
}
return nil
}
Loading

0 comments on commit 7386dec

Please sign in to comment.