Skip to content

Commit

Permalink
Create ArgoCD clients on demand (#75)
Browse files Browse the repository at this point in the history
* Use new GNUMakefile to build local binaries for multiple OSes
* Create clients on resource demand
* Cache clients
* fix: add missing scripts/gofmtcheck.sh
* fix(provider): avoid inter-locking during client initialization

Signed-off-by: Raphaël Pinson <[email protected]>
Co-authored-by: Olivier Boukili <[email protected]>
  • Loading branch information
raphink and oboukili authored Sep 27, 2021
1 parent 304dbc4 commit ec966d2
Show file tree
Hide file tree
Showing 11 changed files with 496 additions and 112 deletions.
69 changes: 59 additions & 10 deletions GNUmakefile
Original file line number Diff line number Diff line change
@@ -1,18 +1,40 @@
TEST?=$$(go list ./... |grep -v 'vendor')
TEST?=./...
GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor)
PKG_NAME=pass

default: build
BINARY=terraform-provider-argocd
VERSION = $(shell git describe --always)

fmt:
gofmt -w $(GOFMT_FILES)
default: build-all

build-all: linux windows darwin

build: fmt
install: fmtcheck
go install

test: fmt
go test -i $(TEST) || exit 1
echo $(TEST) | \
xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4
linux: fmtcheck
@mkdir -p bin/
GOOS=linux GOARCH=amd64 go build -v -o bin/$(BINARY)_$(VERSION)_linux_amd64
GOOS=linux GOARCH=386 go build -v -o bin/$(BINARY)_$(VERSION)_linux_x86

windows: fmtcheck
@mkdir -p bin/
GOOS=windows GOARCH=amd64 go build -v -o bin/$(BINARY)_$(VERSION)_windows_amd64
GOOS=windows GOARCH=386 go build -v -o bin/$(BINARY)_$(VERSION)_windows_x86

darwin: fmtcheck
@mkdir -p bin/
GOOS=darwin GOARCH=amd64 go build -v -o bin/$(BINARY)_$(VERSION)_darwin_amd64
GOOS=darwin GOARCH=386 go build -v -o bin/$(BINARY)_$(VERSION)_darwin_x86

release: clean linux windows darwin
for f in $(shell ls bin/); do zip bin/$${f}.zip bin/$${f}; done

clean:
git clean -fXd -e \!vendor -e \!vendor/**/*

test: fmtcheck
go test $(TEST) -timeout=30s -parallel=4

testacc_prepare_env:
sh scripts/testacc_prepare_env.sh
Expand All @@ -23,4 +45,31 @@ testacc:
testacc_clean_env:
kind delete cluster --name argocd

.PHONY: build test testacc_prepare_env testacc testacc_clean_env fmt
fmt:
@echo "==> Fixing source code with gofmt..."
gofmt -s -w ./$(PKG_NAME)

# Currently required by tf-deploy compile
fmtcheck:
@sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'"

lint:
@echo "==> Checking source code against linters..."
@GOGC=30 golangci-lint run ./$(PKG_NAME)

test-compile:
@if [ "$(TEST)" = "./..." ]; then \
echo "ERROR: Set TEST to a specific package. For example,"; \
echo " make test-compile TEST=./$(PKG_NAME)"; \
exit 1; \
fi
go test -c $(TEST) $(TESTARGS)

vendor:
go mod tidy
go mod vendor

vet:
go vet $<

.PHONY: build test testacc_prepare_env testacc testacc_clean_env fmt fmtcheck lint test-compile vendor
92 changes: 92 additions & 0 deletions argocd/features.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package argocd

import (
"context"
"fmt"
"sync"

"github.com/Masterminds/semver"
"github.com/argoproj/argo-cd/v2/pkg/apiclient"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
Expand All @@ -10,6 +13,9 @@ import (
"github.com/argoproj/argo-cd/v2/pkg/apiclient/repocreds"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/repository"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/version"
"github.com/argoproj/argo-cd/v2/util/io"
"github.com/golang/protobuf/ptypes/empty"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

const (
Expand All @@ -35,6 +41,92 @@ type ServerInterface struct {
RepoCredsClient *repocreds.RepoCredsServiceClient
ServerVersion *semver.Version
ServerVersionMessage *version.VersionMessage
ProviderData *schema.ResourceData

sync.Mutex
initialized bool
}

func (p *ServerInterface) initClients() error {
if p.initialized {
return nil
}

d := p.ProviderData

p.Lock()
defer p.Unlock()

if p.ApiClient == nil {
apiClient, err := initApiClient(d)
if err != nil {
return err
}
p.ApiClient = &apiClient
}

if p.ClusterClient == nil {
_, clusterClient, err := (*p.ApiClient).NewClusterClient()
if err != nil {
return err
}
p.ClusterClient = &clusterClient
}

if p.ApplicationClient == nil {
_, applicationClient, err := (*p.ApiClient).NewApplicationClient()
if err != nil {
return err
}
p.ApplicationClient = &applicationClient
}

if p.ProjectClient == nil {
_, projectClient, err := (*p.ApiClient).NewProjectClient()
if err != nil {
return err
}
p.ProjectClient = &projectClient
}

if p.RepositoryClient == nil {
_, repositoryClient, err := (*p.ApiClient).NewRepoClient()
if err != nil {
return err
}
p.RepositoryClient = &repositoryClient
}

if p.RepoCredsClient == nil {
_, repoCredsClient, err := (*p.ApiClient).NewRepoCredsClient()
if err != nil {
return err
}
p.RepoCredsClient = &repoCredsClient
}

acCloser, versionClient, err := (*p.ApiClient).NewVersionClient()
if err != nil {
return err
}
defer io.Close(acCloser)

serverVersionMessage, err := versionClient.Version(context.Background(), &empty.Empty{})
if err != nil {
return err
}
if serverVersionMessage == nil {
return fmt.Errorf("could not get server version information")
}
p.ServerVersionMessage = serverVersionMessage
serverVersion, err := semver.NewVersion(serverVersionMessage.Version)
if err != nil {
return fmt.Errorf("could not parse server semantic version: %s", serverVersionMessage.Version)
}
p.ServerVersion = serverVersion

p.initialized = true
return nil
}

// Checks that a specific feature is available for the current ArgoCD server version.
Expand Down
81 changes: 3 additions & 78 deletions argocd/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,11 @@ package argocd

import (
"context"
"fmt"
"sync"

"github.com/Masterminds/semver"
"github.com/argoproj/argo-cd/v2/pkg/apiclient"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/project"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/repocreds"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/repository"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/session"
"github.com/argoproj/argo-cd/v2/util/io"
"github.com/golang/protobuf/ptypes/empty"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

Expand Down Expand Up @@ -122,80 +114,12 @@ func Provider() *schema.Provider {
"argocd_repository_credentials": resourceArgoCDRepositoryCredentials(),
},
ConfigureFunc: func(d *schema.ResourceData) (interface{}, error) {
apiClient, err := initApiClient(d)
if err != nil {
return nil, err
}
_, clusterClient, err := apiClient.NewClusterClient()
if err != nil {
return nil, err
}
_, applicationClient, err := apiClient.NewApplicationClient()
if err != nil {
return nil, err
}
_, projectClient, err := apiClient.NewProjectClient()
if err != nil {
return nil, err
}
_, repositoryClient, err := apiClient.NewRepoClient()
if err != nil {
return nil, err
}

_, repoCredsClient, err := apiClient.NewRepoCredsClient()
if err != nil {
return nil, err
}
return initServerInterface(
apiClient,
applicationClient,
clusterClient,
projectClient,
repositoryClient,
repoCredsClient,
)
server := ServerInterface{ProviderData: d}
return &server, nil
},
}
}

func initServerInterface(
apiClient apiclient.Client,
applicationClient application.ApplicationServiceClient,
clusterClient cluster.ClusterServiceClient,
projectClient project.ProjectServiceClient,
repositoryClient repository.RepositoryServiceClient,
repoCredsClient repocreds.RepoCredsServiceClient,
) (interface{}, error) {
acCloser, versionClient, err := apiClient.NewVersionClient()
if err != nil {
return nil, err
}
defer io.Close(acCloser)

serverVersionMessage, err := versionClient.Version(context.Background(), &empty.Empty{})
if err != nil {
return nil, err
}
if serverVersionMessage == nil {
return nil, fmt.Errorf("could not get server version information")
}
serverVersion, err := semver.NewVersion(serverVersionMessage.Version)
if err != nil {
return nil, fmt.Errorf("could not parse server semantic version: %s", serverVersionMessage.Version)
}

return ServerInterface{
&apiClient,
&applicationClient,
&clusterClient,
&projectClient,
&repositoryClient,
&repoCredsClient,
serverVersion,
serverVersionMessage}, err
}

func initApiClient(d *schema.ResourceData) (
apiClient apiclient.Client,
err error) {
Expand All @@ -205,6 +129,7 @@ func initApiClient(d *schema.ResourceData) (
if v, ok := d.GetOk("server_addr"); ok {
opts.ServerAddr = v.(string)
}

if v, ok := d.GetOk("plain_text"); ok {
opts.PlainText = v.(bool)
}
Expand Down
44 changes: 40 additions & 4 deletions argocd/resource_argocd_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,16 @@ func resourceArgoCDApplicationCreate(ctx context.Context, d *schema.ResourceData
if diags != nil {
return diags
}
server := meta.(ServerInterface)
server := meta.(*ServerInterface)
if err := server.initClients(); err != nil {
return []diag.Diagnostic{
{
Severity: diag.Error,
Summary: fmt.Sprintf("Failed to init clients"),
Detail: err.Error(),
},
}
}
c := *server.ApplicationClient
app, err := c.Get(ctx, &applicationClient.ApplicationQuery{
Name: &objectMeta.Name,
Expand Down Expand Up @@ -154,7 +163,16 @@ func resourceArgoCDApplicationCreate(ctx context.Context, d *schema.ResourceData
}

func resourceArgoCDApplicationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
server := meta.(ServerInterface)
server := meta.(*ServerInterface)
if err := server.initClients(); err != nil {
return []diag.Diagnostic{
{
Severity: diag.Error,
Summary: fmt.Sprintf("Failed to init clients"),
Detail: err.Error(),
},
}
}
c := *server.ApplicationClient
appName := d.Id()
app, err := c.Get(ctx, &applicationClient.ApplicationQuery{
Expand Down Expand Up @@ -193,7 +211,16 @@ func resourceArgoCDApplicationUpdate(ctx context.Context, d *schema.ResourceData
if diags != nil {
return diags
}
server := meta.(ServerInterface)
server := meta.(*ServerInterface)
if err := server.initClients(); err != nil {
return []diag.Diagnostic{
{
Severity: diag.Error,
Summary: fmt.Sprintf("Failed to init clients"),
Detail: err.Error(),
},
}
}
c := *server.ApplicationClient
appRequest := &applicationClient.ApplicationUpdateRequest{
Application: &application.Application{
Expand Down Expand Up @@ -278,7 +305,16 @@ func resourceArgoCDApplicationUpdate(ctx context.Context, d *schema.ResourceData
}

func resourceArgoCDApplicationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
server := meta.(ServerInterface)
server := meta.(*ServerInterface)
if err := server.initClients(); err != nil {
return []diag.Diagnostic{
{
Severity: diag.Error,
Summary: fmt.Sprintf("Failed to init clients"),
Detail: err.Error(),
},
}
}
c := *server.ApplicationClient
appName := d.Id()
_, err := c.Delete(ctx, &applicationClient.ApplicationDeleteRequest{
Expand Down
Loading

0 comments on commit ec966d2

Please sign in to comment.