Chef: Read variable from file and use it in one converge
Asked Answered
C

3

7

I have the following code which downloads a file and then reads the contents of the file into a variable. Using that variable, it executes a command. This recipe will not converge because /root/foo does not exist during the compile phase.

I can workaround the issue with multiple converges and an

if File.exist

but I would like to do it with one converge. Any ideas on how to do it?

execute 'download_joiner' do
  command "aws s3 cp s3://bucket/foo /root/foo"
  not_if { ::File.exist?('/root/foo') }
end

password = ::File.read('/root/foo').chomp

execute 'join_domain' do
  command "net ads join -U joiner%#{password}"
end
Cornie answered 26/2, 2016 at 17:36 Comment(0)
L
5

You can download the file at compile time by using run_action and wrap the second part in the conditional block which will be executed at run time.

execute 'download_joiner' do
  command "aws s3 cp s3://bucket/foo /root/foo"
  not_if { ::File.exist?('/root/foo') }
end.run_action(:run)

if File.exist?('/root/foo')
  password = ::File.read('/root/foo').chomp

  execute 'join_domain' do
    command "net ads join -U joiner%#{password}"
  end
end
Limp answered 26/2, 2016 at 18:10 Comment(0)
F
9

The correct solution is to use a lazy property:

execute 'download_joiner' do
  command "aws s3 cp s3://bucket/foo /root/foo"
  creates '/root/foo'
  sensitive true
end


execute 'join_domain' do
  command lazy {
    password = IO.read('/root/foo').strip
    "net ads join -U joiner%#{password}"
  }
  sensitive true
end

That delays the file read until after it is written. Also I included the sensitive property so the password is not displayed.

Fenrir answered 26/2, 2016 at 19:27 Comment(0)
L
5

You can download the file at compile time by using run_action and wrap the second part in the conditional block which will be executed at run time.

execute 'download_joiner' do
  command "aws s3 cp s3://bucket/foo /root/foo"
  not_if { ::File.exist?('/root/foo') }
end.run_action(:run)

if File.exist?('/root/foo')
  password = ::File.read('/root/foo').chomp

  execute 'join_domain' do
    command "net ads join -U joiner%#{password}"
  end
end
Limp answered 26/2, 2016 at 18:10 Comment(0)
U
0

You should read the file from the second command, so that reading happens during convergence too:

execute 'download_joiner' do
  command "aws s3 cp s3://bucket/foo /root/foo"
  not_if { ::File.exist?('/root/foo') }
end

execute 'join_domain' do
  command "net ads join -U joiner%`cat /root/foo`"
end

Note that both your approach and mine will break if the password contains funny characters. If net lets you provide the password on stdin or an env var, I'd do that instead.

Underlet answered 26/2, 2016 at 18:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.