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

Create ArgoCD clients on demand #75

Merged
merged 8 commits into from
Sep 27, 2021

Conversation

raphink
Copy link
Contributor

@raphink raphink commented May 10, 2021

This PR aims to create ArgoCD clients on demand, in order to allow setting the
provider dynamically, based on other resource attributes.

The idea is to store the provider's ResourceData in the meta and use it to
initialize the clients when resources need them.

This PR is based on top of #62.

TODO:

  • pass the provider's ResourceData as pointer to resources
  • call initClients() in all resource types
  • cache clients to avoid duplication

@raphink raphink force-pushed the provider_data branch 2 times, most recently from 10d5d3a to 1285ec2 Compare May 10, 2021 14:22
@lgtm-com
Copy link

lgtm-com bot commented May 10, 2021

This pull request introduces 1 alert when merging 1285ec2 into 4bd78ea - view on LGTM.com

new alerts:

  • 1 for Useless assignment to local variable

@raphink raphink marked this pull request as ready for review May 10, 2021 15:56
@lgtm-com
Copy link

lgtm-com bot commented May 10, 2021

This pull request introduces 1 alert when merging 4c28eb9 into 4bd78ea - view on LGTM.com

new alerts:

  • 1 for Useless assignment to local variable

@lgtm-com
Copy link

lgtm-com bot commented May 11, 2021

This pull request introduces 1 alert when merging 9596107 into 4bd78ea - view on LGTM.com

new alerts:

  • 1 for Useless assignment to local variable

@github-actions
Copy link

This pr is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 10 days.

@github-actions github-actions bot added the Stale label May 25, 2021
@raphink
Copy link
Contributor Author

raphink commented May 25, 2021

@oboukili what is the status for #62?

@oboukili oboukili removed the Stale label May 26, 2021
@oboukili
Copy link
Collaborator

Unfortunately, there is no answer from the PR author of #62

@ClaireBellivier
Copy link
Contributor

If you can wait for next Tuesday, I can have a look at the remaining tasks. Otherwise, feel free to complete the pull request yourself.

@raphink
Copy link
Contributor Author

raphink commented May 26, 2021

Great. I'm also happy to help if necessary 😁

@github-actions
Copy link

This pr is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 10 days.

@github-actions github-actions bot added the Stale label Jun 10, 2021
@raphink
Copy link
Contributor Author

raphink commented Jun 11, 2021

Stale status: waiting on #62

@github-actions github-actions bot removed the Stale label Jun 12, 2021
@github-actions
Copy link

This pr is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 10 days.

@github-actions github-actions bot added the Stale label Jun 27, 2021
@oboukili oboukili removed the Stale label Jul 8, 2021
@github-actions
Copy link

This pr is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 10 days.

@github-actions github-actions bot added the Stale label Jul 23, 2021
@oboukili oboukili removed the Stale label Aug 11, 2021
@oboukili oboukili mentioned this pull request Aug 13, 2021
@github-actions
Copy link

This pr is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 10 days.

@github-actions github-actions bot added the Stale label Aug 26, 2021
@oboukili
Copy link
Collaborator

oboukili commented Sep 8, 2021

Hi @raphink , #62 has just been merged, therefore if you could update your branch from the master branch, we can resume the work on this PR.
I will hold off releasing any new version until we merge your PR as this one in addition to #62 warrants a major version bump of the provider.

This was linked to issues Sep 13, 2021
@raphink
Copy link
Contributor Author

raphink commented Sep 13, 2021

@oboukili is it ok like this?

@oboukili
Copy link
Collaborator

Yes, we just need to wait for the CI tests to pass, I think I noticed a test case error earlier. Let's see.

@oboukili
Copy link
Collaborator

oboukili commented Sep 13, 2021

Apparently there's a race condition

 fatal error: concurrent map read and map write

goroutine 17906 [running]:
runtime.throw(0x392a315, 0x21)
	/opt/hostedtoolcache/go/1.16.8/x64/src/runtime/panic.go:1117 +0x72 fp=0xc00395ae10 sp=0xc00395ade0 pc=0x1127ef2
runtime.mapaccess2_faststr(0x3509ae0, 0xc003682b70, 0x38efa87, 0x8, 0x1, 0x38efa87)
	/opt/hostedtoolcache/go/1.16.8/x64/src/runtime/map_faststr.go:116 +0x4a5 fp=0xc00395ae80 sp=0xc00395ae10 pc=0x1103ee5
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*DiffFieldReader).ReadField(0xc003682b10, 0xc003032ed0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, ...)
	/home/runner/go/pkg/mod/github.com/hashicorp/terraform-plugin-sdk/v2@v2.7.1/helper/schema/field_reader_diff.go:52 +0x10f fp=0xc00395afe8 sp=0xc00395ae80 pc=0x2d9326f
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*MultiLevelFieldReader).ReadFieldMerge(0xc001204ae0, 0xc003032ed0, 0x1, 0x1, 0x38e9071, 0x3, 0x0, 0x0, 0x0, 0x0, ...)
	/home/runner/go/pkg/mod/github.com/hashicorp/terraform-plugin-sdk/v2@v2.7.1/helper/schema/field_reader_multi.go:45 +0x1ff fp=0xc00395b120 sp=0xc00395afe8 pc=0x2d96bbf
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*ResourceData).get(0xc000cecf80, 0xc003032ed0, 0x1, 0x1, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
	/home/runner/go/pkg/mod/github.com/hashicorp/terraform-plugin-sdk/v2@v2.7.1/helper/schema/resource_data.go:550 +0x34a fp=0xc00395b230 sp=0xc00395b120 pc=0x2db05aa
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*ResourceData).getRaw(0xc000cecf80, 0x38efa87, 0x8, 0x3cd8308, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
	/home/runner/go/pkg/mod/github.com/hashicorp/terraform-plugin-sdk/v2@v2.7.1/helper/schema/resource_data.go:118 +0x8d fp=0xc00395b2c8 sp=0xc00395b230 pc=0x2dad82d
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*ResourceData).GetOk(0xc000cecf80, 0x38efa87, 0x8, 0x33ff800, 0x3cd8330, 0xc00395b400)
	/home/runner/go/pkg/mod/github.com/hashicorp/terraform-plugin-sdk/v2@v2.7.1/helper/schema/resource_data.go:84 +0x5f fp=0xc00395b378 sp=0xc00395b2c8 pc=0x2dad55f
github.com/oboukili/terraform-provider-argocd/argocd.initApiClient(0xc000cecf80, 0x0, 0x0, 0x0, 0x0)
	/home/runner/work/terraform-provider-argocd/terraform-provider-argocd/argocd/provider.go:148 +0x2c6 fp=0xc00395b520 sp=0xc00395b378 pc=0x32081c6
github.com/oboukili/terraform-provider-argocd/argocd.(*ServerInterface).initClients(0xc000b599f0, 0x0, 0x0)
	/home/runner/work/terraform-provider-argocd/terraform-provider-argocd/argocd/features.go:50 +0x8a5 fp=0xc00395b608 sp=0xc00395b520 pc=0x3206de5
github.com/oboukili/terraform-provider-argocd/argocd.resourceArgoCDProjectTokenDelete(0x3d6f130, 0xc001c6e240, 0xc000ceda00, 0x3549560, 0xc000b599f0, 0xc003032e50, 0xc00395b7b0, 0x10fdd78)
	/home/runner/work/terraform-provider-argocd/terraform-provider-argocd/argocd/resource_argocd_project_token.go:420 +0x5b fp=0xc00395b750 sp=0xc00395b608 pc=0x321567b
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*Resource).delete(0xc001bc3180, 0x3d6f0c0, 0xc0025fdf80, 0xc000ceda00, 0x3549560, 0xc000b599f0, 0x0, 0x0, 0x0)
	/home/runner/go/pkg/mod/github.com/hashicorp/terraform-plugin-sdk/v2@v2.7.1/helper/schema/resource.go:381 +0x17f fp=0xc00395b7c0 sp=0xc00395b750 pc=0x2da983f
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*Resource).Apply(0xc001bc3180, 0x3d6f0c0, 0xc0025fdf80, 0xc003c49650, 0xc0026529a0, 0x3549560, 0xc000b599f0, 0x0, 0x0, 0x0, ...)
	/home/runner/go/pkg/mod/github.com/hashicorp/terraform-plugin-sdk/v2@v2.7.1/helper/schema/resource.go:428 +0x8f7 fp=0xc00395b8a0 sp=0xc00395b7c0 pc=0x2daa297
github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema.(*GRPCProviderServer).ApplyResourceChange(0xc00101cc18, 0x3d6f0c0, 0xc0025fdf80, 0xc001f70c80, 0xc0025fdf80, 0x37bb7c0, 0xc0035ae700)
	/home/runner/go/pkg/mod/github.com/hashicorp/terraform-plugin-sdk/v2@v2.7.1/helper/schema/grpc_provider.go:955 +0x8ef fp=0xc00395baf0 sp=0xc00395b8a0 pc=0x2da0faf

I never had the opportunity to debug this so I can't really offer serious guidance, but I remember go test -race might come in handy.

@raphink
Copy link
Contributor Author

raphink commented Sep 13, 2021

I'm guessing this might have to do with multiple resources trying to init the clients at the same time. I could probably add a flag on the clients to mark them as initialized and avoid this behavior.

@oboukili
Copy link
Collaborator

We should use some kind of locking mechanism such as a sync.RWMutex or try to use a sync.syncMap.
The former will be a bit tedious to add, the latter can be dangerous (never used it) as apparently some guarantees that Go provides get thrown out the window like type safety.

If you use the RWMutex, I think it should be located out of the clients' objects.

@raphink
Copy link
Contributor Author

raphink commented Sep 16, 2021

NOTE: @oboukili I used a sync.Mutex instead of a sync.RWMutex because we don't want to take the risk that a read-only client would exit the initClients() function before the first (write) client has initialized everything.

@oboukili
Copy link
Collaborator

oboukili commented Sep 16, 2021

@raphink the tests timeout quickly now, I believe it's because your lock is an exclusive one, not a RWMutex one, therefore even for a read a lock is positioned. Please try and use a RWMutex lock, thanks.

EDIT: just read your answer after my post. I don't think using an exclusive lock will be a good thing performance-wise in any case, I think the initClients() function should decide whether to set a RLock or a Lock depending on the state of the API client. (same think for unlocking -> RUnlock if a RLock has been set earlier, etc)

@@ -43,7 +43,7 @@ type ServerInterface struct {
ServerVersionMessage *version.VersionMessage
ProviderData *schema.ResourceData

InitLock sync.Mutex
InitLock sync.RWMutex
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not enough, the locking mechanism has to be updated as well in the function with RLock/Lock and RUnlock/Unlock

@raphink
Copy link
Contributor Author

raphink commented Sep 16, 2021

@oboukili I'm probably misunderstanding something I guess. If I use an RLock, then some resources will be able to read the ServerInterface before it is done initializing. I don't see a way to ensure all resources have fully initialized clients without an exclusive lock. How would I do that?

@oboukili
Copy link
Collaborator

Extremely naively (sorry I don't have so much time to spare at the moment) I would say:

Modify the initClients() function to:

func (p *ServerInterface) initClients() error {
	if p.Initialized {
		return nil
	}
	p.InitLock.Lock()

	d := p.ProviderData
...

and position a RLock very early on on every resource CRUD function:

func resourceArgoCDApplicationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
	objectMeta, spec, diags := expandApplication(d)
	if diags != nil {
		return diags
	}
	server := meta.(*ServerInterface)
	server.InitLock.RLock()
	defer server.InitLock.RUnlock()
       ...

Good luck and thanks!

@oboukili
Copy link
Collaborator

A syncMap would be most interesting though! If applicable.

@raphink
Copy link
Contributor Author

raphink commented Sep 17, 2021

The problem is not really with a map though (or is it?) but with the various fields of the ServerInterface struct. Are these managed as a map internally?

raphink and others added 7 commits September 21, 2021 17:26
Signed-off-by: Raphaël Pinson <raphael.pinson@camptocamp.com>
Signed-off-by: Raphaël Pinson <raphael.pinson@camptocamp.com>
Signed-off-by: Raphaël Pinson <raphael.pinson@camptocamp.com>
Signed-off-by: Raphaël Pinson <raphael.pinson@camptocamp.com>
Signed-off-by: Raphaël Pinson <raphael.pinson@camptocamp.com>
Signed-off-by: Raphaël Pinson <raphael.pinson@camptocamp.com>
@raphink
Copy link
Contributor Author

raphink commented Sep 21, 2021

@oboukili I managed to get it to pass (at least locally) with a simple mutex by just using defer, which I hadn't done in the first try. Could you just launch the pipeline to see if it's green like this please?

@raphink
Copy link
Contributor Author

raphink commented Sep 27, 2021

I see the acceptance tests are now passing. @oboukili is that good for you?

@oboukili
Copy link
Collaborator

Oh great! Awesome work @raphink ! Let me merge that and make a major release ;)

@oboukili oboukili merged commit ec966d2 into argoproj-labs:master Sep 27, 2021
onematchfox added a commit to onematchfox/terraform-provider-argocd that referenced this pull request Apr 25, 2023
All other resources managed by this provider have `Upsert: false` when creating.  This is because we want an error to occur if a duplicate cluster is created otherwise we can end up with two different Terraform resources managed the same resource in ArgoCD. Existing clusters must be imported into Terraform state.

Change to set Upsert = true was introduced in argoproj-labs#75. PR is in general unrelated to this functionality.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Checking host when apply Configure provider dynamically
4 participants