Skip to content

Commit

Permalink
Merge pull request #86 from chef/shack-154
Browse files Browse the repository at this point in the history
[SHACK-154] Create and run with a config file
  • Loading branch information
tyler-ball authored Apr 20, 2018
2 parents 2ad2904 + fc05023 commit eaf28a5
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 27 deletions.
3 changes: 3 additions & 0 deletions components/chef-workstation/i18n/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@ errors:
CHEFUPL002: |
Uploading resource to target failed.
CHEFUPL003: |
Uploading config to target failed.
# Maps to: SSL::SSLError with message text indicating verification failure
CHEFNET002: |
SSL host verification failed.
Expand Down
12 changes: 8 additions & 4 deletions components/chef-workstation/lib/chef-workstation/action/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ def initialize(config = {})
windows: "cmd /c C:/opscode/chef/bin/chef-client",
other: "/opt/chef/bin/chef-client",
},
cache_path: {
windows: '#{ENV[\'APPDATA\']}/chef-workstation',
other: "/var/chef-workstation",
},
read_chef_stacktrace: {
windows: "type C:/chef/cache/chef-stacktrace.out",
other: "cat /var/chef/cache/chef-stacktrace.out",
windows: "type $env:APPDATA/chef-workstation/cache/chef-stacktrace.out",
other: "cat /var/chef-workstation/cache/chef-stacktrace.out",
},
delete_chef_stacktrace: {
windows: "del /f C:/chef/cache/chef-stacktrace.out",
other: "rm -f /var/chef/cache/chef-stacktrace.out",
windows: "del /f $env:APPDATA/chef-workstation/chef-stacktrace.out",
other: "rm -f /var/chef-workstation/cache/chef-stacktrace.out",
},
tempdir: {
windows: "%TEMP%",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ module ChefWorkstation::Action
class ConvergeTarget < Base

def perform_action
remote_recipe_path = create_remote_recipe(@config)
c = connection.run_command("#{chef_client} #{remote_recipe_path} --local-mode --no-color --config-option file_cache_path=/var/chef/cache")
remote_dir_path = File.dirname(remote_recipe_path)
remote_tmp = connection.run_command!(mktemp)
remote_dir_path = escape_windows_path(remote_tmp.stdout.strip)
remote_recipe_path = create_remote_recipe(@config, remote_dir_path)
remote_config_path = create_remote_config(remote_dir_path)

c = connection.run_command("#{chef_client} #{remote_recipe_path} --config #{remote_config_path}")

connection.run_command!("#{delete_folder} #{remote_dir_path}")
if c.exit_status == 0
Expand All @@ -21,9 +24,7 @@ def perform_action
end
end

def create_remote_recipe(config)
c = connection.run_command!(mktemp)
dir = escape_windows_path(c.stdout.strip)
def create_remote_recipe(config, dir)
remote_recipe_path = File.join(dir, "recipe.rb")

if config.has_key?(:recipe_path)
Expand Down Expand Up @@ -51,6 +52,28 @@ def create_remote_recipe(config)
remote_recipe_path
end

def create_remote_config(dir)
remote_config_path = File.join(dir, "workstation.rb")

workstation_rb = <<~EOM
local_mode true
color false
cache_path "#{cache_path}"
EOM

begin
config_file = Tempfile.new
config_file.write(workstation_rb)
config_file.close
connection.upload_file(config_file.path, remote_config_path)
rescue RuntimeError
raise ConfigUploadFailed.new()
ensure
config_file.unlink
end
remote_config_path
end

def handle_ccr_error
require "chef-workstation/errors/ccr_failure_mapper"
mapper_opts = {}
Expand Down Expand Up @@ -98,5 +121,9 @@ class ResourceUploadFailed < ChefWorkstation::Error
def initialize(); super("CHEFUPL002"); end
end

class ConfigUploadFailed < ChefWorkstation::Error
def initialize(); super("CHEFUPL003"); end
end

end
end
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
}
end

it "convertes the properties to chef-client args" do
it "converts the properties to chef-client args" do
expected = <<-EOH.gsub(/^\s{10}/, "")
directory '/tmp' do
key1 'value'
Expand All @@ -50,24 +50,20 @@
describe "#create_remote_recipe" do
let(:remote_folder) { "/tmp/foo" }
let(:remote_recipe) { "#{remote_folder}/recipe.rb" }
let(:tmpdir) { double("tmpdir", exit_status: 0, stdout: remote_folder) }
before do
expect(connection).to receive(:run_command!).with(action.mktemp).and_return(tmpdir)
end

context "when using a local recipe" do
let(:local_recipe) { "/local" }
let(:config) { { recipe_path: local_recipe } }

it "pushes it to the remote machine" do
expect(connection).to receive(:upload_file).with(local_recipe, remote_recipe)
expect(action.create_remote_recipe(config)).to eq(remote_recipe)
expect(action.create_remote_recipe(config, remote_folder)).to eq(remote_recipe)
end

it "raises an error if the upload fails" do
expect(connection).to receive(:upload_file).with(local_recipe, remote_recipe).and_raise("foo")
err = ChefWorkstation::Action::ConvergeTarget::RecipeUploadFailed
expect { action.create_remote_recipe(config) }.to raise_error(err)
expect { action.create_remote_recipe(config, remote_folder) }.to raise_error(err)
end
end

Expand All @@ -78,7 +74,7 @@
it "pushes it to the remote machine" do
expect(Tempfile).to receive(:new).and_return(local_tempfile)
expect(connection).to receive(:upload_file).with(local_tempfile.path, remote_recipe)
expect(action.create_remote_recipe(config)).to eq(remote_recipe)
expect(action.create_remote_recipe(config, remote_folder)).to eq(remote_recipe)
# ensure the tempfile is deleted locally
expect(local_tempfile.closed?).to eq(true)
end
Expand All @@ -87,7 +83,33 @@
expect(Tempfile).to receive(:new).and_return(local_tempfile)
expect(connection).to receive(:upload_file).with(local_tempfile.path, remote_recipe).and_raise("foo")
err = ChefWorkstation::Action::ConvergeTarget::ResourceUploadFailed
expect { action.create_remote_recipe(config) }.to raise_error(err)
expect { action.create_remote_recipe(config, remote_folder) }.to raise_error(err)
# ensure the tempfile is deleted locally
expect(local_tempfile.closed?).to eq(true)
end
end
end

describe "#create_remote_config" do
let(:remote_folder) { "/tmp/foo" }
let(:remote_config) { "#{remote_folder}/workstation.rb" }

context "when using a config file" do
let!(:local_tempfile) { Tempfile.new }

it "pushes it to the remote machine" do
expect(Tempfile).to receive(:new).and_return(local_tempfile)
expect(connection).to receive(:upload_file).with(local_tempfile.path, remote_config)
expect(action.create_remote_config(remote_folder)).to eq(remote_config)
# ensure the tempfile is deleted locally
expect(local_tempfile.closed?).to eq(true)
end

it "raises an error if the upload fails" do
expect(Tempfile).to receive(:new).and_return(local_tempfile)
expect(connection).to receive(:upload_file).with(local_tempfile.path, remote_config).and_raise("foo")
err = ChefWorkstation::Action::ConvergeTarget::ConfigUploadFailed
expect { action.create_remote_config(remote_folder) }.to raise_error(err)
# ensure the tempfile is deleted locally
expect(local_tempfile.closed?).to eq(true)
end
Expand All @@ -96,14 +118,21 @@

describe "#perform_action" do
let(:config) { { resource_type: r1, resource_name: r2, properties: props } }
let(:remote_recipe) { "/tmp/recipe.rb" }
let(:remote_folder) { "/tmp/foo" }
let(:remote_recipe) { "#{remote_folder}/recipe.rb" }
let(:remote_config) { "#{remote_folder}/workstation.rb" }
let(:tmpdir) { double("tmpdir", exit_status: 0, stdout: remote_folder) }
before do
expect(connection).to receive(:run_command!).with(action.mktemp).and_return(tmpdir)
end
let(:result) { double("command result", exit_status: 0, stdout: "") }

it "runs the converge and reports back success" do
expect(action).to receive(:create_remote_recipe).with(config).and_return(remote_recipe)
expect(action).to receive(:create_remote_recipe).with(config, remote_folder).and_return(remote_recipe)
expect(action).to receive(:create_remote_config).with(remote_folder).and_return(remote_folder)
expect(connection).to receive(:run_command).with(/chef-client.+#{remote_recipe}/).and_return(result)
expect(connection).to receive(:run_command!)
.with("#{action.delete_folder} #{File.dirname(remote_recipe)}")
.with("#{action.delete_folder} #{remote_folder}")
.and_return(result)
expect(action).to receive(:notify).with(:success)
action.perform_action
Expand All @@ -119,10 +148,11 @@
end

it "reports back failure and scrapes the remote log" do
expect(action).to receive(:create_remote_recipe).with(config).and_return(remote_recipe)
expect(connection).to receive(:run_command).with("#{action.chef_client} #{remote_recipe} --local-mode --no-color --config-option file_cache_path=/var/chef/cache").and_return(result)
expect(action).to receive(:create_remote_recipe).with(config, remote_folder).and_return(remote_recipe)
expect(action).to receive(:create_remote_config).with(remote_folder).and_return(remote_config)
expect(connection).to receive(:run_command).with("#{action.chef_client} #{remote_recipe} --config #{remote_config}").and_return(result)
expect(connection).to receive(:run_command!)
.with("#{action.delete_folder} #{File.dirname(remote_recipe)}")
.with("#{action.delete_folder} #{remote_folder}")
expect(action).to receive(:notify).with(:error)
expect(connection).to receive(:run_command).with(action.read_chef_stacktrace).and_return(stacktrace_result)
expect(connection).to receive(:run_command!).with(action.delete_chef_stacktrace)
Expand All @@ -133,8 +163,9 @@
context "when remote log cannot be scraped" do
let(:stacktrace_result) { double("stacktrace scrape result", exit_status: 1, stdout: "", stderr: "") }
it "reports back failure" do
expect(action).to receive(:create_remote_recipe).with(config).and_return(remote_recipe)
expect(connection).to receive(:run_command).with("#{action.chef_client} #{remote_recipe} --local-mode --no-color --config-option file_cache_path=/var/chef/cache").and_return(result)
expect(action).to receive(:create_remote_recipe).with(config, remote_folder).and_return(remote_recipe)
expect(action).to receive(:create_remote_config).with(remote_folder).and_return(remote_config)
expect(connection).to receive(:run_command).with("#{action.chef_client} #{remote_recipe} --config #{remote_config}").and_return(result)
expect(connection).to receive(:run_command!)
.with("#{action.delete_folder} #{File.dirname(remote_recipe)}")
expect(action).to receive(:notify).with(:error)
Expand Down

0 comments on commit eaf28a5

Please sign in to comment.