Class: ChefApply::Action::ConvergeTarget
  
  
  
  
  
    - Inherits:
- 
      Base
      
        
          - Object
- Base
- ChefApply::Action::ConvergeTarget
 show all
    - Defined in:
- lib/chef_apply/action/converge_target.rb,
 lib/chef_apply/action/converge_target/ccr_failure_mapper.rb
 
Defined Under Namespace
  
    
  
    
      Classes: CCRFailureMapper, ConfigUploadFailed, HandlerUploadFailed, PolicyUploadFailed
    
  
  Instance Attribute Summary
  
  Attributes inherited from Base
  #config, #target_host
  
    
      Instance Method Summary
      collapse
    
    
  
  
  
  
  
  
  
  
  
  Methods inherited from Base
  #initialize, #name, #notify, #run
  
    Instance Method Details
    
      
  
  
    #chef_report_path  ⇒ Object 
  
  
  
  
    | 
157
158
159 | # File 'lib/chef_apply/action/converge_target.rb', line 157
def chef_report_path
  @chef_report_path ||= target_host.normalize_path(File.join(target_host.ws_cache_path, "cache", "run-report.json"))
end | 
 
    
      
  
  
    #create_remote_config(dir)  ⇒ Object 
  
  
  
  
    | 
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 | # File 'lib/chef_apply/action/converge_target.rb', line 71
def create_remote_config(dir)
  remote_config_path = File.join(dir, "workstation.rb")
  workstation_rb = <<~EOM
    local_mode true
    color false
    cache_path "#{target_host.ws_cache_path}"
    chef_repo_path "#{target_host.ws_cache_path}"
    require_relative "reporter"
    reporter = ChefApply::Reporter.new
    report_handlers << reporter
    exception_handlers << reporter
  EOM
  unless ChefApply::Config.chef.chef_license.nil?
    workstation_rb << <<~EOM
      chef_license "#{ChefApply::Config.chef.chef_license}"
    EOM
  end
        log_settings = ChefApply::Config.log
  unless log_settings.target_level.nil?
    workstation_rb << <<~EOM
      log_level :#{log_settings.target_level}
    EOM
  end
    dc = ChefApply::Config.data_collector
  if !dc.url.nil? && !dc.token.nil?
    workstation_rb << <<~EOM
      data_collector.server_url "#{dc.url}"
      data_collector.token "#{dc.token}"
      data_collector.mode :solo
      data_collector.organization "Chef Workstation"
    EOM
  end
  begin
    config_file = Tempfile.new
    config_file.write(workstation_rb)
    config_file.close
    target_host.upload_file(config_file.path, remote_config_path)
  rescue RuntimeError
    raise ConfigUploadFailed.new
  ensure
    config_file.unlink
  end
  remote_config_path
end | 
 
    
      
  
  
    #create_remote_handler(remote_dir)  ⇒ Object 
  
  
  
  
    | 
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 | # File 'lib/chef_apply/action/converge_target.rb', line 125
def create_remote_handler(remote_dir)
  remote_handler_path = File.join(remote_dir, "reporter.rb")
  begin
        handler_file = Tempfile.new
        handler_file.write(File.read(File.join(__dir__, "reporter.rb")))
    handler_file.close
    target_host.upload_file(handler_file.path, remote_handler_path)
    rescue RuntimeError
    raise HandlerUploadFailed.new
  ensure
    handler_file.unlink
  end
  remote_handler_path
end | 
 
    
      
  
  
    #create_remote_policy(local_policy_path, remote_dir_path)  ⇒ Object 
  
  
  
  
    | 
59
60
61
62
63
64
65
66
67
68
69 | # File 'lib/chef_apply/action/converge_target.rb', line 59
def create_remote_policy(local_policy_path, remote_dir_path)
  remote_policy_path = File.join(remote_dir_path, File.basename(local_policy_path))
  notify(:creating_remote_policy)
  begin
    target_host.upload_file(local_policy_path, remote_policy_path)
  rescue RuntimeError => e
    ChefApply::Log.error(e)
    raise PolicyUploadFailed.new
  end
  remote_policy_path
end | 
 
    
      
  
  
    #handle_ccr_error  ⇒ Object 
  
  
  
  
    | 
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180 | # File 'lib/chef_apply/action/converge_target.rb', line 161
def handle_ccr_error
  require_relative "converge_target/ccr_failure_mapper"
  mapper_opts = {}
  content = target_host.fetch_file_contents(chef_report_path)
  if content.nil?
    report = {}
    mapper_opts[:failed_report_path] = chef_report_path
    ChefApply::Log.error("Could not read remote report at #{chef_report_path}")
  else
                target_host.del_file(chef_report_path)
    report = JSON.parse(content)
    ChefApply::Log.error("Remote chef-client error follows:")
    ChefApply::Log.error(report["exception"])
  end
  mapper = ConvergeTarget::CCRFailureMapper.new(report["exception"], mapper_opts)
  mapper.raise_mapped_exception!
end | 
 
    
      
  
  
    | 
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 | # File 'lib/chef_apply/action/converge_target.rb', line 27
def perform_action
  local_policy_path = config.delete :local_policy_path
  remote_tmp = target_host.temp_dir
  remote_dir_path = target_host.normalize_path(remote_tmp)
      remote_policy_path = create_remote_policy(local_policy_path, remote_dir_path)
  remote_config_path = create_remote_config(remote_dir_path)
  create_remote_handler(remote_dir_path)
  upload_trusted_certs(remote_dir_path)
  notify(:running_chef)
    cmd_str = run_chef_cmd(remote_dir_path,
    File.basename(remote_config_path),
    File.basename(remote_policy_path))
  c = target_host.run_command(cmd_str)
  target_host.del_dir(remote_dir_path)
  if c.exit_status == 0
    ChefApply::Log.info(c.stdout)
    notify(:success)
  elsif c.exit_status == 35
    notify(:reboot)
  else
    notify(:converge_error)
    ChefApply::Log.error("Error running command [#{cmd_str}]")
    ChefApply::Log.error("stdout: #{c.stdout}")
    ChefApply::Log.error("stderr: #{c.stderr}")
    handle_ccr_error
  end
end | 
 
    
      
  
  
    #run_chef_cmd(working_dir, config_file, policy)  ⇒ Object 
  
  
  
  
    
Chef will try ‘downloading’ the policy from the internet unless we pass it a valid, local file in the working directory. By pointing it at a local file it will just copy it instead of trying to download it.
Chef 13 on Linux requires full path specifiers for –config and –recipe-url while on Chef 13 and 14 on Windows must use relative specifiers to prevent URI from causing an error (github.com/chef/chef/pull/7223/files).
   
 
  
  
    | 
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203 | # File 'lib/chef_apply/action/converge_target.rb', line 189
def run_chef_cmd(working_dir, config_file, policy)
  case target_host.base_os
  when :windows
    "Set-Location -Path #{working_dir}; " +
            "chef-client -z --config #{File.join(working_dir, config_file)} --recipe-url #{File.join(working_dir, policy)} | Out-Null; " +
            "Set-Location C:/; " +
      "exit $LASTEXITCODE"
  else
            "bash -c 'cd #{working_dir}; /opt/chef/bin/chef-client -z --config #{File.join(working_dir, config_file)} --recipe-url #{File.join(working_dir, policy)}'"
  end
end | 
 
    
      
  
  
    #upload_trusted_certs(dir)  ⇒ Object 
  
  
  
  
    | 
143
144
145
146
147
148
149
150
151
152
153
154
155 | # File 'lib/chef_apply/action/converge_target.rb', line 143
def upload_trusted_certs(dir)
    local_tcd = Chef::Util::PathHelper.escape_glob_dir(ChefApply::Config.chef.trusted_certs_dir)
  certs = Dir.glob(File.join(local_tcd, "*.{crt,pem}"))
  return if certs.empty?
  notify(:uploading_trusted_certs)
  remote_tcd = "#{dir}/trusted_certs"
  target_host.make_directory(remote_tcd)
  certs.each do |cert_file|
    target_host.upload_file(cert_file, "#{remote_tcd}/#{File.basename(cert_file)}")
  end
end |