-
Notifications
You must be signed in to change notification settings - Fork 991
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
Fix save_to_file to be indentation independent #10283
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you're going to find any solution that works together with indent.
content += "\n" unless content.end_with?("\n") | ||
"cat << #{delimiter} > #{filename}\n#{content}#{delimiter}" | ||
content_echos = content.split("\n").map do |content_line| | ||
"echo #{Shellwords.shellescape(content_line)} >> #{filename}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously the code allowed to use variables like $var
but now that's going to be escaped, making it backwards incompatible. If you want it really verbatim, we have the base64 method above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be possible now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now the verbatim
will escape everything and the else
will escape only double quotes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adamruzicka you initially introduced this because you found a case where it broke. Do you think this is sufficient?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really see where this wouldn't work, but I don't have a good feeling about it.
As a counter-proposal, how about we keep base64, but on the ruby side we drop the newlines from it and then echo
it? Something like
content = Base64.encode64(content).tr("\n", "")
"echo #{content} | base64 -d > #{filename}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adamruzicka https://serverfault.com/questions/163371/linux-command-line-character-limit says that there is some limit.
I agree that it's quite long and we probably won't hit it soon, but I preferred not to rely on any of it.
I have tried to work with base64, but somehow I wasn't able to make it work properly with multiple lines and variable name. I can use a tempfile, but it seems a bit of overkill.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
says that there is some limit.
Well, yes and no. From what I've seen, what's written there applies when launching things that are external to the shell, but it doesn't seem to apply to shell builtins, such as echo in this case.
I have tried to work with base64, but somehow I wasn't able to make it work properly with multiple lines and variable name
How about we mix the two approaches?
b64 = Base64.encode64(content)
content_echos = b64.each_line.map { |l| "echo #{l}" }.join
"(#{content_echos}) | base64 -d >#{filename}"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you go the echo
path, you need to accumulate the result somewhere. and once you have the whole base64 string accumulated, you can pass it into base64
.
Let me try to accumulate the base64 value without newlines and then pipe it into base64.
Something like:
b64 = Base64.encode64(content)
content_var = b64.each_line.map { |l| "FOO+=#{l}" }.join("\n")
content_var + "echo $FOO | base64 -d >#{filename}"
Mostly I had trouble with the line endings. Maybe in this approach it will be a bit easier.
But let's say this works, we will have different implementations for verbatim
and else
use cases.
On the other hand, if we go with the escaping approach, we will be able to DRY the code by extracting most of the generation into a single method, and just changing the escaping method of the input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you go the echo path, you need to accumulate the result somewhere
Well, you can always spawn a subshell just like I did in the previous suggestion.
On the other hand, if we go with the escaping approach, we will be able to DRY the code by extracting most of the generation into a single method, and just changing the escaping method of the input.
True, at the same time we lose the option to write out binary blobs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reimplemented as base64 single string.
@@ -124,8 +124,12 @@ def save_to_file(filename, content, verbatim: false) | |||
content = Base64.encode64(content) | |||
"cat << #{delimiter} | base64 -d > #{filename}\n#{content}#{delimiter}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This case will still have an issue with indent()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we will have \n
symbols there? I can implement the same solution here too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the verbatim option to stop using heredoc too
01a722f
to
f464a5b
Compare
This should fix the indentation error mentioned in #10283 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a change I feel comfortable cherry picking so I'd still prefer to revert the offending change in the short term and then figure this out.
but then we will be left with broken cloud-init, unless we redesign it as you suggest. Additionally we will be left with |
So I tracked down the whole chain of events:
Now this PR tries to avoid reverting the previous two |
I think you mean #10153 |
Updated the original comment |
f464a5b
to
100eece
Compare
#!/bin/sh | ||
|
||
echo "Calling Ansible AWX/Tower provisioning callback..." | ||
/usr/bin/curl -v -k -s --data "host_config_key=" https:///api/v2/job_templates//callback/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is missing some interpolated values. Can we somehow set up the environment so those are set?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added another test with interpolated values.
18101e9
to
7b9056c
Compare
I have replaced base64 implementation with I have implemented them both in a similar manner with the only difference what symbols should be escaped: in verbatim everything is escaped, in non-verbatim only |
end.join("\n") | ||
|
||
# prefix the append commands with a cleanup command | ||
"> #{filename}\n#{content_echos}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This relies on stdin being closed, right? Can we safely assume that stdin will be closed in all the scenarios where the save_to_file macro might be used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Now the implementation does not rely on stdin.
content += "\n" unless content.end_with?("\n") | ||
"cat << #{delimiter} > #{filename}\n#{content}#{delimiter}" | ||
content_echos = content.split("\n").map do |content_line| | ||
"echo #{Shellwords.shellescape(content_line)} >> #{filename}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really see where this wouldn't work, but I don't have a good feeling about it.
As a counter-proposal, how about we keep base64, but on the ruby side we drop the newlines from it and then echo
it? Something like
content = Base64.encode64(content).tr("\n", "")
"echo #{content} | base64 -d > #{filename}
7b9056c
to
9ac7e27
Compare
23660fd
to
bde58c1
Compare
bde58c1
to
132a978
Compare
@adamruzicka forgot to push the version. Now it should work on all OS-es. What do you think about this implementation? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One last question, otherwise lgtm
base64 = Base64.encode64(content) | ||
content_assignments = base64.split("\n").map { |l| "echo #{Shellwords.shellescape(l)}" }.join("\n") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the escaping even needed? Base64 shouldn't contain any problematic characters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ShimShtein ping
Heredoc notation is very sensitive to leading spaces.
This implementation makes the
save_to_file
macro safe for indentation.