From b357899959c07932e233522968590da9d3b8aa30 Mon Sep 17 00:00:00 2001 From: Pete Higgins Date: Fri, 22 May 2020 17:26:56 -0700 Subject: Add an input property to the execute resource for passing input on STDIN. Signed-off-by: Pete Higgins --- lib/chef/provider/execute.rb | 3 ++- lib/chef/resource/execute.rb | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/chef/provider/execute.rb b/lib/chef/provider/execute.rb index 4ae1e794fc..20b8a40bf1 100644 --- a/lib/chef/provider/execute.rb +++ b/lib/chef/provider/execute.rb @@ -27,7 +27,7 @@ class Chef provides :execute, target_mode: true - def_delegators :new_resource, :command, :returns, :environment, :user, :domain, :password, :group, :cwd, :umask, :creates, :elevated, :default_env, :timeout + def_delegators :new_resource, :command, :returns, :environment, :user, :domain, :password, :group, :cwd, :umask, :creates, :elevated, :default_env, :timeout, :input def load_current_resource current_resource = Chef::Resource::Execute.new(new_resource.name) @@ -91,6 +91,7 @@ class Chef opts[:group] = group if group opts[:cwd] = cwd if cwd opts[:umask] = umask if umask + opts[:input] = input if input opts[:default_env] = default_env opts[:log_level] = :info opts[:log_tag] = new_resource.to_s diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb index 5a6b7ee960..38329a0bb5 100644 --- a/lib/chef/resource/execute.rb +++ b/lib/chef/resource/execute.rb @@ -103,6 +103,10 @@ class Chef description: "Determines whether the script will run with elevated permissions to circumvent User Access Control (UAC) interactively blocking the process.\nThis will cause the process to be run under a batch login instead of an interactive login. The user running #{Chef::Dist::CLIENT} needs the 'Replace a process level token' and 'Adjust Memory Quotas for a process' permissions. The user that is running the command needs the 'Log on as a batch job' permission.\nBecause this requires a login, the user and password properties are required.", introduced: "13.3" + property :input, [String, nil], + introduced: "16.1", + description: "An optional property to set the input sent to the command as STDIN." + alias :env :environment def self.set_guard_inherited_attributes(*inherited_attributes) -- cgit v1.2.1 From 6ec102cae769e517a2ec304458c3ec5d591b4fb3 Mon Sep 17 00:00:00 2001 From: Pete Higgins Date: Tue, 26 May 2020 12:43:19 -0700 Subject: Fix a small style inconsistency. Signed-off-by: Pete Higgins --- lib/chef/resource/apt_package.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/chef/resource/apt_package.rb b/lib/chef/resource/apt_package.rb index 369330be9f..0a31f89af3 100644 --- a/lib/chef/resource/apt_package.rb +++ b/lib/chef/resource/apt_package.rb @@ -46,7 +46,7 @@ class Chef apt_package %(package1 package2 package3) ``` - **Install without using recommend packages as a dependency** + **Install without using recommend packages as a dependency**: ```ruby package 'apache2' do -- cgit v1.2.1 From e8b970318998f46ad964947fade8d3980ef92641 Mon Sep 17 00:00:00 2001 From: Pete Higgins Date: Tue, 26 May 2020 12:43:48 -0700 Subject: Fix property definition according to PR feedback. --- lib/chef/resource/execute.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb index 38329a0bb5..643248bf70 100644 --- a/lib/chef/resource/execute.rb +++ b/lib/chef/resource/execute.rb @@ -103,8 +103,8 @@ class Chef description: "Determines whether the script will run with elevated permissions to circumvent User Access Control (UAC) interactively blocking the process.\nThis will cause the process to be run under a batch login instead of an interactive login. The user running #{Chef::Dist::CLIENT} needs the 'Replace a process level token' and 'Adjust Memory Quotas for a process' permissions. The user that is running the command needs the 'Log on as a batch job' permission.\nBecause this requires a login, the user and password properties are required.", introduced: "13.3" - property :input, [String, nil], - introduced: "16.1", + property :input, [String], + introduced: "16.2", description: "An optional property to set the input sent to the command as STDIN." alias :env :environment -- cgit v1.2.1 From 6b5baedecd8d6b89e9f6e96a797c3c3bf3341118 Mon Sep 17 00:00:00 2001 From: Pete Higgins Date: Tue, 26 May 2020 13:07:06 -0700 Subject: Reformat description and add note. Signed-off-by: Pete Higgins --- lib/chef/resource/execute.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb index 643248bf70..aecf272444 100644 --- a/lib/chef/resource/execute.rb +++ b/lib/chef/resource/execute.rb @@ -27,10 +27,15 @@ class Chef provides :execute, target_mode: true - description "Use the **execute** resource to execute a single command. Commands that"\ - " are executed with this resource are (by their nature) not idempotent,"\ - " as they are typically unique to the environment in which they are run."\ - " Use not_if and only_if to guard this resource for idempotence." + description <<~DESC + Use the **execute** resource to execute a single command. Commands that + are executed with this resource are (by their nature) not idempotent, + as they are typically unique to the environment in which they are run. + Use not_if and only_if to guard this resource for idempotence. + + Note: Use the **script** resource to execute a script using a specific + interpreter (Ruby, Python, Perl, csh, or Bash).' + DESC # The ResourceGuardInterpreter wraps a resource's guards in another resource. That inner resource # needs to behave differently during (for example) why_run mode, so we flag it here. For why_run mode -- cgit v1.2.1 From 7491610f0dea9ce2695bee936312111880571162 Mon Sep 17 00:00:00 2001 From: Pete Higgins Date: Tue, 26 May 2020 13:59:29 -0700 Subject: Add examples for execute resource. Signed-off-by: Pete Higgins --- lib/chef/resource/execute.rb | 521 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 521 insertions(+) diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb index aecf272444..18d652a1f2 100644 --- a/lib/chef/resource/execute.rb +++ b/lib/chef/resource/execute.rb @@ -37,6 +37,527 @@ class Chef interpreter (Ruby, Python, Perl, csh, or Bash).' DESC + examples <<~EXAMPLES + **Run a command upon notification**: + + ```ruby + execute 'slapadd' do + command 'slapadd < /tmp/something.ldif' + creates '/var/lib/slapd/uid.bdb' + + action :nothing + end + + template '/tmp/something.ldif' do + source 'something.ldif' + + notifies :run, 'execute[slapadd]', :immediately + end + ``` + + **Run a touch file only once while running a command**: + + ```ruby + execute 'upgrade script' do + command 'php upgrade-application.php && touch /var/application/.upgraded' + + creates '/var/application/.upgraded' + action :run + end + ``` + + **Run a command which requires an environment variable**: + + ```ruby + execute 'slapadd' do + command 'slapadd < /tmp/something.ldif' + creates '/var/lib/slapd/uid.bdb' + + action :run + environment ({'HOME' => '/home/myhome'}) + end + ``` + + **Delete a repository using yum to scrub the cache**: + + ```ruby + # the following code sample thanks to gaffneyc @ https://gist.github.com/918711 + execute 'clean-yum-cache' do + command 'yum clean all' + action :nothing + end + + file '/etc/yum.repos.d/bad.repo' do + action :delete + notifies :run, 'execute[clean-yum-cache]', :immediately + + notifies :create, 'ruby_block[reload-internal-yum-cache]', :immediately + end + ``` + + **Install repositories from a file, trigger a command, and force the internal cache to reload**: + + The following example shows how to install new Yum repositories from a file, + where the installation of the repository triggers a creation of the Yum cache + that forces the internal cache for Chef Infra Client to reload. + + ```ruby + execute 'create-yum-cache' do + command 'yum -q makecache' + action :nothing + end + + ruby_block 'reload-internal-yum-cache' do + block do + Chef::Provider::Package::Yum::YumCache.instance.reload + end + action :nothing + end + + cookbook_file '/etc/yum.repos.d/custom.repo' do + source 'custom' + mode '0755' + notifies :run, 'execute[create-yum-cache]', :immediately + notifies :create, 'ruby_block[reload-internal-yum-cache]', :immediately + end + ``` + + **Prevent restart and reconfigure if configuration is broken**: + + Use the `:nothing` action (common to all resources) to prevent the test from + starting automatically, and then use the `subscribes` notification to run a + configuration test when a change to the template is detected. + + ```ruby + execute 'test-nagios-config' do + command 'nagios3 --verify-config' + action :nothing + subscribes :run, 'template[/etc/nagios3/configures-nagios.conf]', :immediately + end + ``` + + **Notify in a specific order**: + + To notify multiple resources, and then have these resources run in a certain + order, do something like the following. + + ```ruby + execute 'foo' do + command '...' + notifies :create, 'template[baz]', :immediately + notifies :install, 'package[bar]', :immediately + notifies :run, 'execute[final]', :immediately + end + + template 'baz' do + #... + notifies :run, 'execute[restart_baz]', :immediately + end + + package 'bar' + execute 'restart_baz' + execute 'final' do + command '...' + end + ``` + + where the sequencing will be in the same order as the resources are listed in + the recipe: `execute 'foo'`, `template 'baz'`, `execute [restart_baz]`, + `package 'bar'`, and `execute 'final'`. + + **Execute a command using a template**: + + The following example shows how to set up IPv4 packet forwarding using the + **execute** resource to run a command named `forward_ipv4` that uses a template + defined by the **template** resource. + + ```ruby + execute 'forward_ipv4' do + command 'echo > /proc/.../ipv4/ip_forward' + action :nothing + end + + template '/etc/file_name.conf' do + source 'routing/file_name.conf.erb' + + notifies :run, 'execute[forward_ipv4]', :delayed + end + ``` + + where the `command` property for the **execute** resource contains the command + that is to be run and the `source` property for the **template** resource + specifies which template to use. The `notifies` property for the **template** + specifies that the `execute[forward_ipv4]` (which is defined by the **execute** + resource) should be queued up and run at the end of a Chef Infra Client run. + + **Add a rule to an IP table**: + + The following example shows how to add a rule named `test_rule` to an IP table + using the **execute** resource to run a command using a template that is defined + by the **template** resource: + + ```ruby + execute 'test_rule' do + command 'command_to_run + --option value + --option value + --source #{node[:name_of_node][:ipsec][:local][:subnet]} + -j test_rule' + + action :nothing + end + + template '/etc/file_name.local' do + source 'routing/file_name.local.erb' + notifies :run, 'execute[test_rule]', :delayed + end + ``` + + where the `command` property for the **execute** resource contains the command + that is to be run and the `source` property for the **template** resource + specifies which template to use. The `notifies` property for the **template** + specifies that the `execute[test_rule]` (which is defined by the **execute** + resource) should be queued up and run at the end of a Chef Infra Client run. + + **Stop a service, do stuff, and then restart it**: + + The following example shows how to use the **execute**, **service**, and + **mount** resources together to ensure that a node running on Amazon EC2 is + running MySQL. This example does the following: + + - Checks to see if the Amazon EC2 node has MySQL + - If the node has MySQL, stops MySQL + - Installs MySQL + - Mounts the node + - Restarts MySQL + + ```ruby + # the following code sample comes from the ``server_ec2`` + # recipe in the following cookbook: + # https://github.com/chef-cookbooks/mysql + + if (node.attribute?('ec2') && !FileTest.directory?(node['mysql']['ec2_path'])) + service 'mysql' do + action :stop + end + + execute 'install-mysql' do + command "mv #{node['mysql']['data_dir']} #{node['mysql']['ec2_path']}" + not_if do + FileTest.directory?(node['mysql']['ec2_path']) + end + end + + [node['mysql']['ec2_path'], node['mysql']['data_dir']].each do |dir| + directory dir do + owner 'mysql' + group 'mysql' + end + end + + mount node['mysql']['data_dir'] do + device node['mysql']['ec2_path'] + fstype 'none' + options 'bind,rw' + action [:mount, :enable] + end + + service 'mysql' do + action :start + end + end + ``` + + where + + - the two **service** resources are used to stop, and then restart the MySQL service + - the **execute** resource is used to install MySQL + - the **mount** resource is used to mount the node and enable MySQL + + **Use the platform_family? method**: + + The following is an example of using the `platform_family?` method in the Recipe + DSL to create a variable that can be used with other resources in the same + recipe. In this example, `platform_family?` is being used to ensure that a + specific binary is used for a specific platform before using the **remote_file** + resource to download a file from a remote location, and then using the + **execute** resource to install that file by running a command. + + ```ruby + if platform_family?('rhel') + pip_binary = '/usr/bin/pip' + else + pip_binary = '/usr/local/bin/pip' + end + + remote_file "#{Chef::Config[:file_cache_path]}/distribute_setup.py" do + source 'http://python-distribute.org/distribute_setup.py' + mode '0755' + + not_if { File.exist?(pip_binary) } + end + + execute 'install-pip' do + cwd Chef::Config[:file_cache_path] + command <<~EOF + # command for installing Python goes here + EOF + not_if { File.exist?(pip_binary) } + end + ``` + + where a command for installing Python might look something like: + + ```ruby + #{node['python']['binary']} distribute_setup.py #{::File.dirname(pip_binary)}/easy_install pip + ``` + + **Control a service using the execute resource**: + +
+

Warning

+
+ This is an example of something that should NOT be done. Use the **service** + resource to control a service, not the **execute** resource. +
+
+ + Do something like this: + + ```ruby + service 'tomcat' do + action :start + end + ``` + + and NOT something like this: + + ```ruby + execute 'start-tomcat' do + command '/etc/init.d/tomcat6 start' + action :run + end + ``` + + There is no reason to use the **execute** resource to control a service because + the **service** resource exposes the `start_command` property directly, which + gives a recipe full control over the command issued in a much cleaner, more + direct manner. + + **Use the search recipe DSL method to find users**: + + The following example shows how to use the `search` method in the Recipe DSL to + search for users: + + ```ruby + # the following code sample comes from the openvpn cookbook: https://github.com/chef-cookbooks/openvpn + + search("users", "*:*") do |u| + execute "generate-openvpn-#{u['id']}" do + command "./pkitool #{u['id']}" + cwd '/etc/openvpn/easy-rsa' + + environment( + 'EASY_RSA' => '/etc/openvpn/easy-rsa', + 'KEY_CONFIG' => '/etc/openvpn/easy-rsa/openssl.cnf', + 'KEY_DIR' => node['openvpn']['key_dir'], + 'CA_EXPIRE' => node['openvpn']['key']['ca_expire'].to_s, + 'KEY_EXPIRE' => node['openvpn']['key']['expire'].to_s, + 'KEY_SIZE' => node['openvpn']['key']['size'].to_s, + 'KEY_COUNTRY' => node['openvpn']['key']['country'], + 'KEY_PROVINCE' => node['openvpn']['key']['province'], + 'KEY_CITY' => node['openvpn']['key']['city'], + 'KEY_ORG' => node['openvpn']['key']['org'], + 'KEY_EMAIL' => node['openvpn']['key']['email'] + ) + not_if { File.exist?("#{node['openvpn']['key_dir']}/#{u['id']}.crt") } + end + + %w{ conf ovpn }.each do |ext| + template "#{node['openvpn']['key_dir']}/#{u['id']}.#{ext}" do + source 'client.conf.erb' + variables :username => u['id'] + end + end + + execute "create-openvpn-tar-#{u['id']}" do + cwd node['openvpn']['key_dir'] + command <<~EOH + tar zcf #{u['id']}.tar.gz ca.crt #{u['id']}.crt #{u['id']}.key #{u['id']}.conf #{u['id']}.ovpn + EOH + not_if { File.exist?("#{node['openvpn']['key_dir']}/#{u['id']}.tar.gz") } + end + end + ``` + + where + + - the search will use both of the **execute** resources, unless the condition + specified by the `not_if` commands are met + - the `environments` property in the first **execute** resource is being used to + define values that appear as variables in the OpenVPN configuration + - the **template** resource tells Chef Infra Client which template to use + + **Enable remote login for macOS**: + + ```ruby + execute 'enable ssh' do + command '/usr/sbin/systemsetup -setremotelogin on' + not_if '/usr/sbin/systemsetup -getremotelogin | /usr/bin/grep On' + action :run + end + ``` + + **Execute code immediately, based on the template resource**: + + By default, notifications are `:delayed`, that is they are queued up as they are + triggered, and then executed at the very end of a Chef Infra Client run. To run + kan action immediately, use `:immediately`: + + ```ruby + template '/etc/nagios3/configures-nagios.conf' do + # other parameters + notifies :run, 'execute[test-nagios-config]', :immediately + end + ``` + + and then Chef Infra Client would immediately run the following: + + ```ruby + execute 'test-nagios-config' do + command 'nagios3 --verify-config' + action :nothing + end + ``` + + **Sourcing a file**: + + The **execute** resource cannot be used to source a file (e.g. `command 'source + filename'`). The following example will fail because `source` is not an + executable: + + ```ruby + execute 'foo' do + command 'source /tmp/foo.sh' + end + ``` + + + Instead, use the **script** resource or one of the **script**-based resources + (**bash**, **csh**, **perl**, **python**, or **ruby**). For example: + + ```ruby + bash 'foo' do + code 'source /tmp/foo.sh' + end + ``` + + **Run a Knife command**: + + ```ruby + execute 'create_user' do + command <<~EOM + knife user create #{user} + --admin + --password password + --disable-editing + --file /home/vagrant/.chef/user.pem + --config /tmp/knife-admin.rb + EOM + end + ``` + + **Run install command into virtual environment**: + + The following example shows how to install a lightweight JavaScript framework + into Vagrant: + + ```ruby + execute "install q and zombiejs" do + cwd "/home/vagrant" + user "vagrant" + environment ({'HOME' => '/home/vagrant', 'USER' => 'vagrant'}) + command "npm install -g q zombie should mocha coffee-script" + action :run + end + ``` + + **Run a command as a named user**: + + The following example shows how to run `bundle install` from a Chef Infra Client + run as a specific user. This will put the gem into the path of the user + (`vagrant`) instead of the root user (under which the Chef Infra Client runs): + + ```ruby + execute '/opt/chefdk/embedded/bin/bundle install' do + cwd node['chef_workstation']['bundler_path'] + user node['chef_workstation']['user'] + + environment ({ + 'HOME' => "/home/#{node['chef_workstation']['user']}", + 'USER' => node['chef_workstation']['user'] + }) + not_if 'bundle check' + end + ``` + + **Run a command as an alternate user**: + + *Note*: When Chef is running as a service, this feature requires that the user + that Chef runs as has 'SeAssignPrimaryTokenPrivilege' (aka + 'SE_ASSIGNPRIMARYTOKEN_NAME') user right. By default only LocalSystem and + NetworkService have this right when running as a service. This is necessary + even if the user is an Administrator. + + This right can be added and checked in a recipe using this example: + + ```ruby + # Add 'SeAssignPrimaryTokenPrivilege' for the user + Chef::ReservedNames::Win32::Security.add_account_right('', 'SeAssignPrimaryTokenPrivilege') + + # Check if the user has 'SeAssignPrimaryTokenPrivilege' rights + Chef::ReservedNames::Win32::Security.get_account_right('').include?('SeAssignPrimaryTokenPrivilege') + ``` + + The following example shows how to run `mkdir test_dir` from a Chef Infra Client + run as an alternate user. + + ```ruby + # Passing only username and password + execute 'mkdir test_dir' do + cwd Chef::Config[:file_cache_path] + + user "username" + password "password" + end + + # Passing username and domain + execute 'mkdir test_dir' do + cwd Chef::Config[:file_cache_path] + + domain "domain-name" + user "user" + password "password" + end + + # Passing username = 'domain-name\\username'. No domain is passed + execute 'mkdir test_dir' do + cwd Chef::Config[:file_cache_path] + + user "domain-name\\username" + password "password" + end + + # Passing username = 'username@domain-name'. No domain is passed + execute 'mkdir test_dir' do + cwd Chef::Config[:file_cache_path] + + user "username@domain-name" + password "password" + end + ``` + EXAMPLES + # The ResourceGuardInterpreter wraps a resource's guards in another resource. That inner resource # needs to behave differently during (for example) why_run mode, so we flag it here. For why_run mode # we still want to execute the guard resource even if we are not executing the wrapping resource. -- cgit v1.2.1 From f5b40f789d91ddab616ac61c66202d950781b983 Mon Sep 17 00:00:00 2001 From: Pete Higgins Date: Tue, 26 May 2020 16:14:09 -0700 Subject: Add an example using the input property. Signed-off-by: Pete Higgins --- lib/chef/resource/execute.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb index 18d652a1f2..b09401e57a 100644 --- a/lib/chef/resource/execute.rb +++ b/lib/chef/resource/execute.rb @@ -556,6 +556,12 @@ class Chef password "password" end ``` + + **Run a command with an external input file**: + + execute 'md5sum' do + input File.read(__FILE__) + end EXAMPLES # The ResourceGuardInterpreter wraps a resource's guards in another resource. That inner resource -- cgit v1.2.1 From 448c95de608c33905a82fcbbc8f66579f941703b Mon Sep 17 00:00:00 2001 From: Pete Higgins Date: Tue, 26 May 2020 17:00:29 -0700 Subject: Escape interpolation in code examples. Signed-off-by: Pete Higgins --- lib/chef/resource/execute.rb | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb index b09401e57a..1fc8922e71 100644 --- a/lib/chef/resource/execute.rb +++ b/lib/chef/resource/execute.rb @@ -201,7 +201,7 @@ class Chef command 'command_to_run --option value --option value - --source #{node[:name_of_node][:ipsec][:local][:subnet]} + --source \#{node[:name_of_node][:ipsec][:local][:subnet]} -j test_rule' action :nothing @@ -242,7 +242,7 @@ class Chef end execute 'install-mysql' do - command "mv #{node['mysql']['data_dir']} #{node['mysql']['ec2_path']}" + command "mv \#{node['mysql']['data_dir']} \#{node['mysql']['ec2_path']}" not_if do FileTest.directory?(node['mysql']['ec2_path']) end @@ -290,7 +290,7 @@ class Chef pip_binary = '/usr/local/bin/pip' end - remote_file "#{Chef::Config[:file_cache_path]}/distribute_setup.py" do + remote_file "\#{Chef::Config[:file_cache_path]}/distribute_setup.py" do source 'http://python-distribute.org/distribute_setup.py' mode '0755' @@ -309,7 +309,7 @@ class Chef where a command for installing Python might look something like: ```ruby - #{node['python']['binary']} distribute_setup.py #{::File.dirname(pip_binary)}/easy_install pip + \#{node['python']['binary']} distribute_setup.py \#{::File.dirname(pip_binary)}/easy_install pip ``` **Control a service using the execute resource**: @@ -353,8 +353,8 @@ class Chef # the following code sample comes from the openvpn cookbook: https://github.com/chef-cookbooks/openvpn search("users", "*:*") do |u| - execute "generate-openvpn-#{u['id']}" do - command "./pkitool #{u['id']}" + execute "generate-openvpn-\#{u['id']}" do + command "./pkitool \#{u['id']}" cwd '/etc/openvpn/easy-rsa' environment( @@ -370,22 +370,22 @@ class Chef 'KEY_ORG' => node['openvpn']['key']['org'], 'KEY_EMAIL' => node['openvpn']['key']['email'] ) - not_if { File.exist?("#{node['openvpn']['key_dir']}/#{u['id']}.crt") } + not_if { File.exist?("\#{node['openvpn']['key_dir']}/\#{u['id']}.crt") } end %w{ conf ovpn }.each do |ext| - template "#{node['openvpn']['key_dir']}/#{u['id']}.#{ext}" do + template "\#{node['openvpn']['key_dir']}/\#{u['id']}.\#{ext}" do source 'client.conf.erb' variables :username => u['id'] end end - execute "create-openvpn-tar-#{u['id']}" do + execute "create-openvpn-tar-\#{u['id']}" do cwd node['openvpn']['key_dir'] command <<~EOH - tar zcf #{u['id']}.tar.gz ca.crt #{u['id']}.crt #{u['id']}.key #{u['id']}.conf #{u['id']}.ovpn + tar zcf \#{u['id']}.tar.gz ca.crt \#{u['id']}.crt \#{u['id']}.key \#{u['id']}.conf \#{u['id']}.ovpn EOH - not_if { File.exist?("#{node['openvpn']['key_dir']}/#{u['id']}.tar.gz") } + not_if { File.exist?("\#{node['openvpn']['key_dir']}/\#{u['id']}.tar.gz") } end end ``` @@ -457,7 +457,7 @@ class Chef ```ruby execute 'create_user' do command <<~EOM - knife user create #{user} + knife user create \#{user} --admin --password password --disable-editing @@ -494,7 +494,7 @@ class Chef user node['chef_workstation']['user'] environment ({ - 'HOME' => "/home/#{node['chef_workstation']['user']}", + 'HOME' => "/home/\#{node['chef_workstation']['user']}", 'USER' => node['chef_workstation']['user'] }) not_if 'bundle check' -- cgit v1.2.1