Recursive loop when passing an undefined prompted variable to a deploy a release step

I have a variable set that includes a prompted variable that is scoped to my production environment. The project deployer must supply a value for this variable anytime they deploy to production. Both the child and parent projects inherit the variable set so the prompted variable is passed along through the deploy a release step as such:

ChangeControl = #{ChangeControl}

That seems to work fine as long as the deployment occurs in production and the variable gets defined. When the deployment occurs in any other environment and the variable is undefined, then an exception is being thrown regarding a recursive loop in the variable value. I’ve tried guarding against this by setting a run condition on my auditing steps to look for #{ChangeControl} to be true, that way the step would only run if it was defined, but that is no longer working. I’m positive that was once working but it seems like maybe upgrades along the way have broken this functionality.

Currently running v2019.2.4

Please let me know if you need any additional information. I look forward to hearing your suggestions.

Thank you,

Hi @tfbryan ,

Great question, thanks for reaching out with it! I think I can see this issue when I try to recreate those conditions.

Could you confirm for me that this is the exception message that you are seeing?

System.InvalidOperationException: An attempt to parse the variable symbol "ChangeControl" appears to have resulted in a self referencing loop (ChangeControl). Ensure that recursive loops do not exist in the variable values. 

If not, please feel free to set me straight with a task log or screenshot!

Assuming I’m on the right track here, I can confirm that using a second variable name as a run condition should work - like this:



However, in the scenario that you saw this issue - we expect it to fail in this way for the case in Dev because we cannot resolve the value for the run condition, since we need to try and evaluate the ‘passed down’ variables before we evaluate the run condition, which is why it probably works OK on the child project in isolation.

It is quite possible that we added some guards around this since you last upgraded, if you have a look in your [dbo].[OctopusServerInstallationHistory] table and get me your previous version, I’d be happy to do some further digging to help us understand if & why functionality might have shifted on you.

Hope that helps!

Jim

Jim,

Thanks for the reply. You are correct about the error, that’s exactly what I’m seeing. Unfortunately I don’t know the version I was on when this was last working. I last tested this a few months ago and we’ve upgraded a few times since then. It seems pretty clear that the child project is trying to resolve a variable even though it’s not in scope to exist.

No problem @tfbryan,

I’m not seeing any recent changes here but I can’t rule out other changes to when this code is called.

Let me know if there is anything else I can help with.

All the best,
Jim

So is this not being considered a bug?

Hi @tfbryan

Sorry if I didn’t clarify on that point, yes, we feel that this behavior is working as intended.

In your production environment, the variable exists, and therefore, the octostache replacement of #{ChangeControl} resolves as expected.

In other environments, the variable doesn’t exist, so when octostache tries to replace it, it can only find itself, and throws this error up to prevent some nasty recursion problems.

While I cant determine exactly why this used to work for you, and now doesn’t, the behaviour you are describing is expected, and not a bug.

The way this presents itself in the task log does make it appear like a bug rather than a safety net, and we will make some moves to tidy that up.

To get yourself unblocked you can use a differently named variable in your child project, or take up the option described above.

All the best,

Jim

Jim,

My variable is globally inherited through a set. Adding a variable with a different name isn’t an option. Setting a default value, such as “not required”, for all non-production environments does seem to work around this behavior, but feels hacky as I never had to do this before.

Hi @tfbryan,

Sorry that you don’t feel like you have a good way forward here, but as I mentioned this type of check against recursively assigned variable values ensures that you don’t get an incorrect variable resolution at deployment time, which was possible prior to this check existing.

The approach I outlined with screenshots above also uses a globally inherited variable set, but the run condition works via a second variable UseChangeControl which is correctly scoped in all environments (to either true or false). If you add this to the library (global) variable set and then update your change control steps to use this for the run condition, then you shouldn’t need to worry about a default value for the ChangeControl variable.

Hope that helps
Jim

Jim,

I did set up that 2nd variable for the Run Condition, as that seems like a good idea. It did not resolve the recursion error I am getting. That is what I am referring to as a possible bug. The only thing that has helped around this issue so far is assigning a default value for the non-prod ChangeControl variable.

Hey @tfbryan,

Thanks for letting me know - we’re struggling to reproduce that when we follow these steps. Are you able to take some screenshots of how you did it in your project? If you can include the Library variable Set and the the project variables, as well as the run condition details that would be great.

Hopefully we can get to the bottom of this.

Assuming this is a bug - are you in a position to run this query and send me the result?

SELECT * FROM  [dbo].[OctopusServerInstallationHistory]

These results will tell me which versions you were on and save me from having to pick a point in time in the past few months.

Could you also export your deployment process for me? There is an overflow menu on the right that you can use to export it as JSON. If there is anything sensitive there feel free to redact it or you can send it via our email support@octopus.com

Kind regards,

Jim

Jim,

One thing I noticed in your screenshots above. When you set up your ChangeControl variable, you set a default value of “change me”. What happens if your variable has no default value?

For our production scope, the ChangeControl variable is left as an empty user prompted variable and it’s up the to user to supply a value. No default value is used.

Also, keep in mind that I have a Parent project using a Deploy A Release step to call to the Child project. Both projects inherit the ChangeControl variable from a set. In both projects, I have the Run Condition set to evaluate the UseChangeControl variable, also inherited through the variable set.

Thanks for this additional detail Todd, this should help steer our research more efficiently!

What happens if your variable has no default value?

Alas, I’ve re-run my test scenario that uses the UseChangeControl variable as the run condition - removing the default value, on 2019.2.4 and it all looks OK here. Could you confirm if this works for you on a pair of small test projects?

However, in my previous attempts I didn’t have a run condition on the parent, so that does change my test.

So I’ve re-run this test based on these details and we still aren’t seeing things quite as you are though, so I suspect there is some nuance we’re missing.

If you can give me an export of your deployment processes for the parent and child processes, I should have the best chance of replicating your issue. Here is how you can do that per project.

I’ll do my best to describe how I’ve setup my new test. I started with an instance I have here with 2018.9.16 on it - which takes us back to last year, one version before your 2018.9.17 upgrade. It is also ‘pre-spaces’ so seemed like a good place to start. A lot of new code was introduced for spaces so it is plausible that things have changed.

As you’ve asserted, I’ve confirmed that the run condition on the parent project step works as expected on this version - it evaluates to false and doesn’t attempt to release the child project.

I then upgraded this instance straight to 2019.9.4 and re-ran the process. In the Development environment the parent project run condition also evaluated to false and skipped the step - it does get formatted a little differently though:

Unfortunately, I believe this is where you are seeing the error?

For reference - here is my global variable set - I’ve removed the default value (the UseChangeControl values are there but I didn’t use them for this test run)

I’ve applied that Set to both parent and child projects.

Child project ‘Run a script’ step:


Parent project ‘Deploy a release’ step:


I can confirm that I’ve applied the set and the run condition to both the child and parent projects.

For the test run itself, I first create a release for the Child project (without deploying it), and then go through a full realease creation and deployment on the parent project.

My lifecycle is configured using optional phases so I can test Dev and Prod.

image
I’ve applied this lifecycle to both projects.

If you aren’t able to send through your deployment process export, please let me know if you would like me to change anything else about this configuration, and I’ll give it another try.

Kind regards,

Jim

Jim,

I just built out a quick example Child and Parent project and replicated the issue. I’ll email you the json for each.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.