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

core: fix the provisioner graphing #4877

Merged
merged 2 commits into from
Feb 5, 2016
Merged

core: fix the provisioner graphing #4877

merged 2 commits into from
Feb 5, 2016

Conversation

svanharmelen
Copy link
Contributor

Without this change, all provisioners are added to the graph by default and they are never pruned from the graph if their not needed.

I must admit I'm not a 100% sure if this is the correct solution, but there are a few (weird) things that we should discuss and/or have a look at in order to determine the correct solution.

  1. I wonder if it makes any sense at all to have a MissingProvisionerTransformer? It makes sense to have a MissingProviderTransformer because you could have used a resource without specifying the needed provider for that resource. But that isn't possible for a provisioner as that is a single entity which you either specify in your config, or you don't. So how can you ever have a missing provisioner in your config?
  2. I think we could ask ourselves the exact same question for the PruneProvisionerTransformer. What could this transformer ever prune (if we don't add all available provisioners or selves that is, see point 3 😉).
  3. If we still do want the MissingProvisionerTransformer, then I suppose we only want to add the provisioners that we actually need. Currently we just add all known provisioners and try to prune them in a later stage (which currently doesn't work, see point 4). The code in the PR changes the logic by only adding the provisioners that are needed by the supplied config in the same way as this is done for providers.
  4. We should have a closer look at PruneProviderTransformer and PruneProvisionerTransformer. They currently both check if there are any UpEdges, and only if there none the provider or provisioner is removed from the graph. But when the RootTransformer is executed before one of the prune transformers, they will have at least 1 UpEdge, being the graphNodeRoot added by the RootTransformer. And since the current graph builder ordering places the RootTransformer before the prune transformers, it means the prune transformers are effectively broken at this moment.

The code in this PR fixes the problem described in point 4 by reordering the transformers, but that doesn't feel like a robust solution. Another (possibly better) fix would be to change this code to something like:

s := g.UpEdges(v)
if s.Len() == 0 {
  g.Remove(v)
}
if s.Len() == 1 {
  if _, ok := s.List()[0].(graphNodeRoot); ok {
    g.Remove(v)
  }
}

This would make the ordering of the graph transformations less critical, but I'm not sure if this is a 100% fix and if this also works when your using modules and/or already have a root, not being a graphNodeRoot (not sure that is even possible?). So I need some input to be sure this would indeed be a solid fix for the current prune transformers problem in all use cases...

I labeled this as a bug, because the current code allocates resources (mainly a goroutine with a yamux stream) for each provisioner for every action (e.g. refresh, plan, apply) which is never released. If your running Terraform as a long running daemon (API) you can see this will kill your service at a certain point in time 😁

Without this change, all provisioners are added to the graph by default
and they are never pruned from the graph if their not needed.
@phinze
Copy link
Contributor

phinze commented Jan 28, 2016

Hi @svanharmelen, this seems reasonable at first glance!

I'm curious, though, does this have any functional effect?

Also same question for the RootTransformer move - is that required to make this change or was that just a cleanup you saw while in there?

@svanharmelen
Copy link
Contributor Author

@phinze I was still typing the complete description for this PR, so please have another look as I suspect it will now answer your questions 😉

/CC @mitchellh as this is mainly code he wrote at the time...

@svanharmelen
Copy link
Contributor Author

@phinze @mitchellh any feedback or thoughts about this one?

@svanharmelen
Copy link
Contributor Author

Any chance we can discuss this one?

If it's up to me I would just remove MissingProvisionerTransformer and PruneProvisionerTransformer all together and then the only question left is how to properly fix PruneProviderTransformer.

The reordering I did in this PR still feel hacky. So would the suggested code change do the trick and be robust enough? Or should we extend that peace of code to check additional use cases/types?

@mitchellh
Copy link
Contributor

Looking now, expect a follow up comment shortly.

@mitchellh
Copy link
Contributor

My thoughts are: not having the missing and prune transformers make sense. If we can remove those without breaking any tests (other than those that might just test for their existence), then it probably will work fine.

In terms of this PR, lets go with the route that makes the code simpler vs more complex, if we can do that while having all tests still pass.

@svanharmelen
Copy link
Contributor Author

Thanks for the feedback! I'll update the PR (somewhere tomorrow) accordingly 👍

@svanharmelen
Copy link
Contributor Author

@phinze @mitchellh just tried to remove the MissingProvisionersTransformer, only to learn that this transformer is responsible for adding any provisioner to the graph. So without this, no provisioners are added to the graph at all 😞

I first added a few lines of code to the ProvisionersTransformer to add any needed provisioners in there. But then I though it would be cleaner to have that logic separated, so I ended up reverting some parts of that 😁

To make things a little more descriptive I renamed a few types that had missing in their names, as they are not a specific type for missing provisioners, they just represent the (any) provisioners and/or providers in the graph.

So I think the PR should be good to go now, however I do have one feedback question left... I noticed I had to change 1 test in order to make all tests pass: https://github.com/hashicorp/terraform/pull/4877/files#diff-1848efa7a9473a60ae890ae47d35cbf0

I looked at this one, but I fail to fully understand if the previous version is the correct and desired outcome or if this current version is in fact the expected outcome. I was unable to reason about it correctly, so I hope one of you can enlighten me on this one.

Thanks!

// Add our own missing provider node to the graph
m[p] = g.Add(&graphNodeMissingProvider{ProviderNameValue: p})
// Add the missing provider node to the graph
m[p] = g.Add(&graphNodeProvider{ProviderNameValue: p})
Copy link
Contributor

Choose a reason for hiding this comment

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

Why rename this?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm actually +1 on this rename or something similar (since this node really does represent the provider itself in the graph) but I'd prefer we do it as a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, that was exactly the argument for renaming this... Since this node represents the provider itself in the graph, this name seemed a little more suitable and more descriptive.

I added the rename in this PR as the provisioner and provider transformers are very much inline with each other and I changed it for the provisioner as well.

But I'll take this code out if you prefer that and make a new PR for the provider renaming... 👍

@mitchellh
Copy link
Contributor

One question about why renaming the missing provider when I believe this PR is about provisioners.

@svanharmelen
Copy link
Contributor Author

Check... Replied inline, but will take out the provider rename and put in it a separate PR.

And renamed some types so they better reflect what they are for.
@svanharmelen
Copy link
Contributor Author

Updated the PR so it only contains provisioner related changes... Still would like to get a conformation (double check) that the updated test case is now giving the expected results so we're sure to not introduce any kind of regression. Thx!

@josephholsten
Copy link
Contributor

@svanharmelen I thought you were pulling out the renames from this branch? do you still need to push those changes?

@josephholsten
Copy link
Contributor

ah, all the functional changes are in the first commit. LGTM, though I'm not qualified to vouch for test completeness.

@phinze
Copy link
Contributor

phinze commented Feb 5, 2016

Hello again! This is looking good - I believe it solves the Provisioner already initialized portion of #3114 - cooking up a test to verify that it does that I'd like to drop in. Will keep you posted.

@svanharmelen
Copy link
Contributor Author

Sounds good... Thx!

phinze added a commit that referenced this pull request Feb 5, 2016
Currently failing, but going to move this commit around to vet fixes.

Confirmed that #4877 fixes the provisioner half of this!
@phinze
Copy link
Contributor

phinze commented Feb 5, 2016

Okay just confirmed on the linked branch/commit that this does indeed address the provisioner side of that problem. So I'll merge this now and then land that test once the Provider side of the issue is handled (looking into that now).

Thanks for all your work on this, Sander! 👍

phinze added a commit that referenced this pull request Feb 5, 2016
@phinze phinze merged commit 0846e32 into hashicorp:master Feb 5, 2016
phinze added a commit that referenced this pull request Feb 5, 2016
Context:

As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.

Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.

Bug:

In #3114 a problem was exposed where, given a module tree that looked
like this:

```
root
 |
 +-- parent (empty, except for sub-modules)
       |
       +-- child1 (1 resource)
       |
       +-- child2 (1 resource)
```

If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.

Fix:

This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.

Here, we add an additional check to prevent a double add, which
addresses this scenario properly.

Fixes #3114 (the Provisioner side of it was fixed in #4877)
@svanharmelen
Copy link
Contributor Author

Thanks!

@svanharmelen svanharmelen deleted the b-provisioner-graphing branch February 8, 2016 08:13
phinze added a commit that referenced this pull request Feb 9, 2016
Context:

As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.

Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.

Bug:

In #3114 a problem was exposed where, given a module tree that looked
like this:

```
root
 |
 +-- parent (empty, except for sub-modules)
       |
       +-- child1 (1 resource)
       |
       +-- child2 (1 resource)
```

If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.

Fix:

This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.

Here, we add an additional check to prevent a double add, which
addresses this scenario properly.

Fixes #3114 (the Provisioner side of it was fixed in #4877)
joshmyers pushed a commit to joshmyers/terraform that referenced this pull request Feb 18, 2016
Context:

As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.

Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.

Bug:

In hashicorp#3114 a problem was exposed where, given a module tree that looked
like this:

```
root
 |
 +-- parent (empty, except for sub-modules)
       |
       +-- child1 (1 resource)
       |
       +-- child2 (1 resource)
```

If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.

Fix:

This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.

Here, we add an additional check to prevent a double add, which
addresses this scenario properly.

Fixes hashicorp#3114 (the Provisioner side of it was fixed in hashicorp#4877)
bigkraig pushed a commit to bigkraig/terraform that referenced this pull request Mar 1, 2016
Context:

As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.

Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.

Bug:

In hashicorp#3114 a problem was exposed where, given a module tree that looked
like this:

```
root
 |
 +-- parent (empty, except for sub-modules)
       |
       +-- child1 (1 resource)
       |
       +-- child2 (1 resource)
```

If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.

Fix:

This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.

Here, we add an additional check to prevent a double add, which
addresses this scenario properly.

Fixes hashicorp#3114 (the Provisioner side of it was fixed in hashicorp#4877)
@ghost
Copy link

ghost commented Apr 28, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked and limited conversation to collaborators Apr 28, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants