Skip to content

Commit

Permalink
Fixes #37741 - Fix save_to_file to be indentation independent
Browse files Browse the repository at this point in the history
  • Loading branch information
ShimShtein committed Sep 5, 2024
1 parent fd21a88 commit 9ac7e27
Show file tree
Hide file tree
Showing 17 changed files with 229 additions and 168 deletions.
17 changes: 12 additions & 5 deletions app/services/foreman/renderer/scope/macros/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,22 @@ def pxe_kernel_options
example "save_to_file(shell_escape('/tmp/a file with spaces'), nil) # => 'cp /dev/null /tmp/a\ file\ with\ spaces'"
end
def save_to_file(filename, content, verbatim: false)
delimiter = 'EOF-' + Digest::SHA512.hexdigest(filename)[0..7]
if content.empty?
"cp /dev/null #{filename}"
elsif verbatim
content = Base64.encode64(content)
"cat << #{delimiter} | base64 -d > #{filename}\n#{content}#{delimiter}"
param_name = "CONTENT#{Digest::SHA512.hexdigest(filename)[0..7]}"
base64 = Base64.encode64(content)
content_assignments = base64.split("\n").map { |l| "#{param_name}+=#{Shellwords.shellescape(l)}" }.join("\n")
"#{content_assignments}\necho $#{param_name} | base64 -d > #{filename}"
else
content += "\n" unless content.end_with?("\n")
"cat << #{delimiter} > #{filename}\n#{content}#{delimiter}"
content_echos = content.split("\n").map do |content_line|
# to make sure there the substitutions are working, have the bash script
# handle all special characters except double quotes.
"echo \"#{content_line.gsub('"', '\"')}\" >> #{filename}"
end.join("\n")

# prefix the append commands with a cleanup command
"> #{filename}\n#{content_echos}"
end
end

Expand Down
2 changes: 2 additions & 0 deletions test/static_fixtures/interpolated_text.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
foo: bar
baz: $INTERPOLATED
5 changes: 5 additions & 0 deletions test/static_fixtures/script.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/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/
echo "DONE"
5 changes: 4 additions & 1 deletion test/unit/foreman/renderer/renderers_shared_tests.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,10 @@ module RenderersSharedTests
test "should render a save_to_file macro" do
source = OpenStruct.new(content: '<%= save_to_file("/etc/puppet/puppet.conf", "[main]\nserver=example.com\n") %>')
assert_nothing_raised do
assert_equal("cat << EOF-728d4ec4 > /etc/puppet/puppet.conf\n[main]\nserver=example.com\nEOF-728d4ec4", renderer.render(source, @scope))
actual = renderer.render(source, @scope)
assert_match /[main]/, actual
assert_match /server=example.com/, actual
assert_match /\/etc\/puppet\/puppet.conf/, actual
end
end

Expand Down
72 changes: 64 additions & 8 deletions test/unit/foreman/renderer/scope/macros/base_test.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'test_helper'
require 'tempfile'

class BaseMacrosTest < ActiveSupport::TestCase
setup do
Expand Down Expand Up @@ -249,21 +250,76 @@ class BaseMacrosTest < ActiveSupport::TestCase
end

test "should add a missing newline" do
delimiter = 'EOF-e6fb375b'
command = @scope.save_to_file('/tmp/test', 'echo hello')
assert_equal command, "cat << #{delimiter} > /tmp/test\necho hello\n#{delimiter}"
tmp_file = Tempfile.new('save_to_file')
tmp_file.close

file_content = 'echo hello'

command = @scope.save_to_file(tmp_file.path, file_content)

system({'INTERPOLATED' => 'test_value_123'}, command)

actual = `cat #{tmp_file.path}`

assert_equal "#{file_content}\n", actual
ensure
tmp_file.unlink
end

test "should encode content as base64" do
delimiter = 'EOF-e6fb375b'
base64 = Base64.encode64('echo hello')
command = @scope.save_to_file('/tmp/test', 'echo hello', verbatim: true)
assert_equal command, "cat << #{delimiter} | base64 -d > /tmp/test\n#{base64}#{delimiter}"
test "should not interpolate content with verbatim on" do
tmp_file = Tempfile.new('save_to_file')
tmp_file.close

file_content = File.read(Rails.root.join('test', 'static_fixtures', 'interpolated_text.txt'))

command = @scope.save_to_file(tmp_file.path, file_content, verbatim: true)

system({'INTERPOLATED' => 'test_value_123'}, command)

actual = `cat #{tmp_file.path}`

assert_equal file_content, actual

Check failure on line 281 in test/unit/foreman/renderer/scope/macros/base_test.rb

View workflow job for this annotation

GitHub Actions / test:units - Ruby 2.7 and Node 18 on PostgreSQL 13

Failure: test_0004_should not interpolate content with verbatim on --- expected +++ actual @@ -1,3 +1 @@ -"foo: bar -baz: $INTERPOLATED -" +""

Check failure on line 281 in test/unit/foreman/renderer/scope/macros/base_test.rb

View workflow job for this annotation

GitHub Actions / test:units - Ruby 3.0 and Node 14 on PostgreSQL 13

Failure: test_0004_should not interpolate content with verbatim on --- expected +++ actual @@ -1,3 +1 @@ -"foo: bar -baz: $INTERPOLATED -" +""

Check failure on line 281 in test/unit/foreman/renderer/scope/macros/base_test.rb

View workflow job for this annotation

GitHub Actions / test:units - Ruby 2.7 and Node 14 on PostgreSQL 13

Failure: test_0004_should not interpolate content with verbatim on --- expected +++ actual @@ -1,3 +1 @@ -"foo: bar -baz: $INTERPOLATED -" +""
ensure
tmp_file.unlink
end

test "should ignore escaping of filename by default" do
command = @scope.save_to_file('/tmp/ifcfg-$sanitized_real', nil)
assert_equal command, 'cp /dev/null /tmp/ifcfg-$sanitized_real'
end

test "Should create a correct script even when indented" do
tmp_file = Tempfile.new('save_to_file')
tmp_file.close

file_content = File.read(Rails.root.join('test', 'static_fixtures', 'script.txt'))

command = @scope.indent(2) { @scope.save_to_file(tmp_file.path, file_content) }

system(command)

actual = `cat #{tmp_file.path}`

assert_equal file_content, actual
ensure
tmp_file.unlink
end

test "Should interpolate ENV values to the script" do
tmp_file = Tempfile.new('save_to_file')
tmp_file.close

file_content = File.read(Rails.root.join('test', 'static_fixtures', 'interpolated_text.txt'))

command = @scope.indent(2) { @scope.save_to_file(tmp_file.path, file_content) }

system({'INTERPOLATED' => 'test_value_123'}, command)

actual = `cat #{tmp_file.path}`

assert_match /test_value_123/, actual
ensure
tmp_file.unlink
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,12 @@ echo "Performing initial puppet run for --tags no_such_tag"



cat << EOF-9f037ba1 > /root/ansible_provisioning_call.sh
#!/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/
echo "DONE"
EOF-9f037ba1
> /root/ansible_provisioning_call.sh
echo "#!/bin/sh" >> /root/ansible_provisioning_call.sh
echo "" >> /root/ansible_provisioning_call.sh
echo "echo \"Calling Ansible AWX/Tower provisioning callback...\"" >> /root/ansible_provisioning_call.sh
echo "/usr/bin/curl -v -k -s --data \"host_config_key=\" https:///api/v2/job_templates//callback/" >> /root/ansible_provisioning_call.sh
echo "echo \"DONE\"" >> /root/ansible_provisioning_call.sh
chmod +x /root/ansible_provisioning_call.sh
/root/ansible_provisioning_call.sh

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,19 @@ allow-hotplug $real
iface $real inet dhcp
EOF

cat << EOF-2929810d > /etc/systemd/system/ansible-callback.service
[Unit]
Description=Provisioning callback to Ansible Tower
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/curl -k -s --data "host_config_key=" https:///api/v2/job_templates//callback/
ExecStartPost=/usr/bin/systemctl disable ansible-callback

[Install]
WantedBy=multi-user.target
EOF-2929810d
> /etc/systemd/system/ansible-callback.service
echo "[Unit]" >> /etc/systemd/system/ansible-callback.service
echo "Description=Provisioning callback to Ansible Tower" >> /etc/systemd/system/ansible-callback.service
echo "Wants=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "After=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Service]" >> /etc/systemd/system/ansible-callback.service
echo "Type=oneshot" >> /etc/systemd/system/ansible-callback.service
echo "ExecStart=/usr/bin/curl -k -s --data \"host_config_key=\" https:///api/v2/job_templates//callback/" >> /etc/systemd/system/ansible-callback.service
echo "ExecStartPost=/usr/bin/systemctl disable ansible-callback" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Install]" >> /etc/systemd/system/ansible-callback.service
echo "WantedBy=multi-user.target" >> /etc/systemd/system/ansible-callback.service
# Runs during first boot, removes itself
systemctl enable ansible-callback
if [ -x /usr/bin/curl ]; then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,19 @@ allow-hotplug $real
iface $real inet dhcp
EOF

cat << EOF-2929810d > /etc/systemd/system/ansible-callback.service
[Unit]
Description=Provisioning callback to Ansible Tower
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/curl -k -s --data "host_config_key=" https:///api/v2/job_templates//callback/
ExecStartPost=/usr/bin/systemctl disable ansible-callback

[Install]
WantedBy=multi-user.target
EOF-2929810d
> /etc/systemd/system/ansible-callback.service
echo "[Unit]" >> /etc/systemd/system/ansible-callback.service
echo "Description=Provisioning callback to Ansible Tower" >> /etc/systemd/system/ansible-callback.service
echo "Wants=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "After=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Service]" >> /etc/systemd/system/ansible-callback.service
echo "Type=oneshot" >> /etc/systemd/system/ansible-callback.service
echo "ExecStart=/usr/bin/curl -k -s --data \"host_config_key=\" https:///api/v2/job_templates//callback/" >> /etc/systemd/system/ansible-callback.service
echo "ExecStartPost=/usr/bin/systemctl disable ansible-callback" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Install]" >> /etc/systemd/system/ansible-callback.service
echo "WantedBy=multi-user.target" >> /etc/systemd/system/ansible-callback.service
# Runs during first boot, removes itself
systemctl enable ansible-callback
if [ -x /usr/bin/curl ]; then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,20 +249,19 @@ echo "Performing initial puppet run for --tags no_such_tag"



cat << EOF-2929810d > /etc/systemd/system/ansible-callback.service
[Unit]
Description=Provisioning callback to Ansible Tower
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/curl -k -s --data "host_config_key=" https:///api/v2/job_templates//callback/
ExecStartPost=/usr/bin/systemctl disable ansible-callback

[Install]
WantedBy=multi-user.target
EOF-2929810d
> /etc/systemd/system/ansible-callback.service
echo "[Unit]" >> /etc/systemd/system/ansible-callback.service
echo "Description=Provisioning callback to Ansible Tower" >> /etc/systemd/system/ansible-callback.service
echo "Wants=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "After=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Service]" >> /etc/systemd/system/ansible-callback.service
echo "Type=oneshot" >> /etc/systemd/system/ansible-callback.service
echo "ExecStart=/usr/bin/curl -k -s --data \"host_config_key=\" https:///api/v2/job_templates//callback/" >> /etc/systemd/system/ansible-callback.service
echo "ExecStartPost=/usr/bin/systemctl disable ansible-callback" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Install]" >> /etc/systemd/system/ansible-callback.service
echo "WantedBy=multi-user.target" >> /etc/systemd/system/ansible-callback.service
# Runs during first boot, removes itself
systemctl enable ansible-callback

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,20 +249,19 @@ echo "Performing initial puppet run for --tags no_such_tag"



cat << EOF-2929810d > /etc/systemd/system/ansible-callback.service
[Unit]
Description=Provisioning callback to Ansible Tower
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/curl -k -s --data "host_config_key=" https:///api/v2/job_templates//callback/
ExecStartPost=/usr/bin/systemctl disable ansible-callback

[Install]
WantedBy=multi-user.target
EOF-2929810d
> /etc/systemd/system/ansible-callback.service
echo "[Unit]" >> /etc/systemd/system/ansible-callback.service
echo "Description=Provisioning callback to Ansible Tower" >> /etc/systemd/system/ansible-callback.service
echo "Wants=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "After=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Service]" >> /etc/systemd/system/ansible-callback.service
echo "Type=oneshot" >> /etc/systemd/system/ansible-callback.service
echo "ExecStart=/usr/bin/curl -k -s --data \"host_config_key=\" https:///api/v2/job_templates//callback/" >> /etc/systemd/system/ansible-callback.service
echo "ExecStartPost=/usr/bin/systemctl disable ansible-callback" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Install]" >> /etc/systemd/system/ansible-callback.service
echo "WantedBy=multi-user.target" >> /etc/systemd/system/ansible-callback.service
# Runs during first boot, removes itself
systemctl enable ansible-callback

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,20 +249,19 @@ echo "Performing initial puppet run for --tags no_such_tag"



cat << EOF-2929810d > /etc/systemd/system/ansible-callback.service
[Unit]
Description=Provisioning callback to Ansible Tower
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/curl -k -s --data "host_config_key=" https:///api/v2/job_templates//callback/
ExecStartPost=/usr/bin/systemctl disable ansible-callback

[Install]
WantedBy=multi-user.target
EOF-2929810d
> /etc/systemd/system/ansible-callback.service
echo "[Unit]" >> /etc/systemd/system/ansible-callback.service
echo "Description=Provisioning callback to Ansible Tower" >> /etc/systemd/system/ansible-callback.service
echo "Wants=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "After=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Service]" >> /etc/systemd/system/ansible-callback.service
echo "Type=oneshot" >> /etc/systemd/system/ansible-callback.service
echo "ExecStart=/usr/bin/curl -k -s --data \"host_config_key=\" https:///api/v2/job_templates//callback/" >> /etc/systemd/system/ansible-callback.service
echo "ExecStartPost=/usr/bin/systemctl disable ansible-callback" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Install]" >> /etc/systemd/system/ansible-callback.service
echo "WantedBy=multi-user.target" >> /etc/systemd/system/ansible-callback.service
# Runs during first boot, removes itself
systemctl enable ansible-callback

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,20 +249,19 @@ echo "Performing initial puppet run for --tags no_such_tag"



cat << EOF-2929810d > /etc/systemd/system/ansible-callback.service
[Unit]
Description=Provisioning callback to Ansible Tower
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/curl -k -s --data "host_config_key=" https:///api/v2/job_templates//callback/
ExecStartPost=/usr/bin/systemctl disable ansible-callback

[Install]
WantedBy=multi-user.target
EOF-2929810d
> /etc/systemd/system/ansible-callback.service
echo "[Unit]" >> /etc/systemd/system/ansible-callback.service
echo "Description=Provisioning callback to Ansible Tower" >> /etc/systemd/system/ansible-callback.service
echo "Wants=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "After=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Service]" >> /etc/systemd/system/ansible-callback.service
echo "Type=oneshot" >> /etc/systemd/system/ansible-callback.service
echo "ExecStart=/usr/bin/curl -k -s --data \"host_config_key=\" https:///api/v2/job_templates//callback/" >> /etc/systemd/system/ansible-callback.service
echo "ExecStartPost=/usr/bin/systemctl disable ansible-callback" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Install]" >> /etc/systemd/system/ansible-callback.service
echo "WantedBy=multi-user.target" >> /etc/systemd/system/ansible-callback.service
# Runs during first boot, removes itself
systemctl enable ansible-callback

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,20 +249,19 @@ echo "Performing initial puppet run for --tags no_such_tag"



cat << EOF-2929810d > /etc/systemd/system/ansible-callback.service
[Unit]
Description=Provisioning callback to Ansible Tower
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/bin/curl -k -s --data "host_config_key=" https:///api/v2/job_templates//callback/
ExecStartPost=/usr/bin/systemctl disable ansible-callback

[Install]
WantedBy=multi-user.target
EOF-2929810d
> /etc/systemd/system/ansible-callback.service
echo "[Unit]" >> /etc/systemd/system/ansible-callback.service
echo "Description=Provisioning callback to Ansible Tower" >> /etc/systemd/system/ansible-callback.service
echo "Wants=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "After=network-online.target" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Service]" >> /etc/systemd/system/ansible-callback.service
echo "Type=oneshot" >> /etc/systemd/system/ansible-callback.service
echo "ExecStart=/usr/bin/curl -k -s --data \"host_config_key=\" https:///api/v2/job_templates//callback/" >> /etc/systemd/system/ansible-callback.service
echo "ExecStartPost=/usr/bin/systemctl disable ansible-callback" >> /etc/systemd/system/ansible-callback.service
echo "" >> /etc/systemd/system/ansible-callback.service
echo "[Install]" >> /etc/systemd/system/ansible-callback.service
echo "WantedBy=multi-user.target" >> /etc/systemd/system/ansible-callback.service
# Runs during first boot, removes itself
systemctl enable ansible-callback

Expand Down
Loading

0 comments on commit 9ac7e27

Please sign in to comment.