Skip to content

Commit

Permalink
Merge pull request #82 from chef/shack-141/cookbook_lookup
Browse files Browse the repository at this point in the history
[SHACK-141] Lookup cookbooks in repo for remote target execution
  • Loading branch information
tyler-ball authored Apr 20, 2018
2 parents d5cd6df + aa08031 commit 8dcd1f7
Show file tree
Hide file tree
Showing 12 changed files with 367 additions and 65 deletions.
2 changes: 1 addition & 1 deletion components/chef-workstation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ TODO: Write usage instructions here

## Development

After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
After checking out the repository, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

Expand Down
40 changes: 37 additions & 3 deletions components/chef-workstation/i18n/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ commands:
<RECIPE>. For example:
chef target converge myec2node path/to/cookbook/recipe.rb
chef target converge myec2node path/to/cookbook
chef target converge myec2node cookbook_name
chef target converge myec2node cookbook_name::recipe_name
ARGUMENTS:
<TARGET> The host or IP address to converge. Can also be an SSH or WinRM URL
Expand All @@ -90,7 +93,11 @@ commands:
the name of the user you wanted to create.
<RECIPE> The recipe to converge. This can be provided as one of:
1. Full path to a recipe file
2. Cookbook name. First we check the working directory for this
cookbook, then we check in the chef repository path. If a
cookbook is found we run the default recipe.
3. This behaves similarly to 'cookbook name' above, but it also allows
you to specify which recipe to use from the cookbook.
root_description: "Whether to use root permissions on the target. Defaults to true."
identity_file: "SSH identity file to use when connecting."
ssl:
Expand All @@ -100,6 +107,8 @@ commands:
Use --ssl-no-verify when using SSL for WinRM and
the remote host is using a self-signed certificate.
Current default: %1
cookbook_repo_paths:
desc: "Comma separated list of cookbook repository paths."


# Status updates shared across commands.
Expand Down Expand Up @@ -237,11 +246,36 @@ errors:
Property '%1' did not match the 'key=value' syntax required
CHEFVAL004: |
Please provide a recipe in the form 'path/to/recipe/file', 'cookbook_name',
or 'cookbook_name::recipe_name'.
Please provide a recipe in the form 'path/to/recipe/file.rb',
'path/to/cookbook', 'cookbook_name' or 'cookbook_name::recipe_name'.
You provided '%1'.
CHEFVAL005: |
The cookbook provided could not be loaded. Ensure it contains a valid
'metadata.rb'.
Cookbook path is '%1'.
CHEFVAL006: |
Cookbook '%1' could not be found in any of the following directorys
%2
CHEFVAL007: |
There is no default recipe in cookbook '%2'. Please provide the name of the recipe to run, for example:
%2::some_recipe
Cookbook path is '%1'.
CHEFVAL008: |
There is no recipe named '%2' in the cookbook '%4', which I found at '%1'.
Please include the name of the recipe you wish to converge on the remote target.
These are the available recipes in '%4':
%3
# General errors/unknown errors are handled with CHEFINT
CHEFINT001: |
An unexpected error has occurred:
Expand Down
3 changes: 1 addition & 2 deletions components/chef-workstation/lib/chef-workstation/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ def setup_cli
Config.create_default_config_file
end
Config.load
ChefWorkstation::Log.setup(Config.log.location)
Log.level = Config.log.level.to_sym
ChefWorkstation::Log.setup(Config.log.location, Config.log.level.to_sym)
ChefWorkstation::Log.info("Initialized logger")
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@
require "chef-workstation/ui/terminal"
require "chef-workstation/log"
require "chef-workstation/config"
require "chef-workstation/recipe_lookup"
require "chef-config/config"
require "chef-config/logger"
require "chef/log"

module ChefWorkstation
module Command
class Target
class Converge < ChefWorkstation::Command::Base
T = ChefWorkstation::Text.commands.target.converge
TS = ChefWorkstation::Text.status
Config = ChefWorkstation::Config

option :root,
:long => "--[no-]root",
Expand All @@ -52,19 +55,26 @@ class Converge < ChefWorkstation::Command::Base
option :ssl,
:long => "--[no-]ssl",
:short => "-s",
:description => T.ssl.desc(Config.connection.winrm.ssl),
:description => T.ssl.desc(ChefWorkstation::Config.connection.winrm.ssl),
:boolean => true,
:default => Config.connection.winrm.ssl
:default => ChefWorkstation::Config.connection.winrm.ssl

option :ssl_verify,
:long => "--[no-]ssl-verify",
:short => "-s",
:description => T.ssl.verify_desc(Config.connection.winrm.ssl_verify),
:description => T.ssl.verify_desc(ChefWorkstation::Config.connection.winrm.ssl_verify),
:boolean => true,
:default => Config.connection.winrm.ssl_verify
:default => ChefWorkstation::Config.connection.winrm.ssl_verify

option :cookbook_repo_paths,
:long => "--cookbook-repo-paths PATH",
:description => T.cookbook_repo_paths.desc,
:default => ChefWorkstation::Config.chef.cookbook_repo_paths,
:proc => Proc.new { |paths| paths.split(",") }

def run(params)
validate_params(cli_arguments)
configure_chef

target = cli_arguments.shift

Expand Down Expand Up @@ -109,6 +119,15 @@ def validate_params(params)
end
end

# Now that we are leveraging Chef locally we want to perform some initial setup of it
def configure_chef
ChefConfig.logger = ChefWorkstation::Log
# Setting the config isn't enough, we need to ensure the logger is initialized
# or automatic initialization will still go to stdout
Chef::Log.init(ChefWorkstation::Log)
Chef::Log.level = ChefWorkstation::Log.level
end

def format_properties(string_props)
properties = {}
string_props.each do |a|
Expand Down Expand Up @@ -147,21 +166,22 @@ def parse_converge_args(converge_args, cli_arguments)
if recipe_strategy?(cli_arguments)
recipe_specifier = cli_arguments.shift
ChefWorkstation::Log.debug("Beginning to look for recipe specified as #{recipe_specifier}")

# First, we check to see if the user has specified the full path (absolute or relative)
# to a file. If they have, we assume that is a recipe they want to execute.
if File.file?(recipe_specifier)
ChefWorkstation::Log.debug("#{recipe_specifier} is a valid path to a recipe")
converge_args[:recipe_path] = recipe_specifier
spinner_msg = TS.converge.converging_recipe(recipe_specifier)
recipe_path = recipe_specifier
else
raise "Cannot specify anything besides full path yet"
rl = RecipeLookup.new(config[:cookbook_repo_paths])
cookbook_path_or_name, optional_recipe_name = rl.split(recipe_specifier)
cookbook = rl.load_cookbook(cookbook_path_or_name)
recipe_path = rl.find_recipe(cookbook, optional_recipe_name)
end
converge_args[:recipe_path] = recipe_path
spinner_msg = TS.converge.converging_recipe(recipe_specifier)
else
resource = converge_args[:resource_type] = cli_arguments.shift
resource_name = converge_args[:resource_name] = cli_arguments.shift
converge_args[:resource_type] = cli_arguments.shift
converge_args[:resource_name] = cli_arguments.shift
converge_args[:properties] = format_properties(cli_arguments)
full_rs_name = "#{resource}[#{resource_name}]"
full_rs_name = "#{converge_args[:resource_type]}[#{converge_args[:resource_name]}]"
ChefWorkstation::Log.debug("Converging resource #{full_rs_name} on target")
spinner_msg = TS.converge.converging_resource(full_rs_name)
end
Expand Down
79 changes: 47 additions & 32 deletions components/chef-workstation/lib/chef-workstation/config.rb
Original file line number Diff line number Diff line change
@@ -1,46 +1,24 @@
require "mixlib/config"
require "fileutils"
require "pathname"
require "chef-config/config"
require "chef-config/workstation_config_loader"

module ChefWorkstation
class Config
WS_BASE_PATH = File.join(Dir.home, ".chef-workstation/")

extend Mixlib::Config

config_strict_mode true

# When working on chef-workstation itself,
# developers should set telemetry.dev to true
# in their local configuration to ensure that dev usage
# doesn't skew customer telemetry.
config_context :telemetry do
default(:dev, false)
end

config_context :log do
default(:level, "warn")
default(:location, File.join(WS_BASE_PATH, "logs/default.log"))
end

config_context :cache do
default(:path, File.join(WS_BASE_PATH, "cache"))
end

config_context :connection do
config_context :winrm do
default(:ssl, false)
default(:ssl_verify, true)
end
end

config_context :dev do
default(:spinner, "TTY::Spinner")
end

class << self
@custom_location = nil

# Ensure when we extend Mixlib::Config that we load
# up the workstation config since we will need that
# to converge later
def initialize_mixlib_config
super
ChefConfig::WorkstationConfigLoader.new(nil).load
end

def custom_location(path)
@custom_location = path
raise "No config file located at #{path}" unless exist?
Expand Down Expand Up @@ -84,5 +62,42 @@ def reset
super
end
end

extend Mixlib::Config

config_strict_mode true

# When working on chef-workstation itself,
# developers should set telemetry.dev to true
# in their local configuration to ensure that dev usage
# doesn't skew customer telemetry.
config_context :telemetry do
default(:dev, false)
end

config_context :log do
default(:level, "warn")
default(:location, File.join(WS_BASE_PATH, "logs/default.log"))
end

config_context :cache do
default(:path, File.join(WS_BASE_PATH, "cache"))
end

config_context :connection do
config_context :winrm do
default(:ssl, false)
default(:ssl_verify, true)
end
end

config_context :dev do
default(:spinner, "TTY::Spinner")
end

config_context :chef do
default(:cookbook_repo_paths, ChefConfig::Config[:cookbook_path])
end

end
end
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ def exception_args_from_cause
when /.*Chef::Exceptions::ValidationFailed:\s+(.*)/
# Invalid resource property value
["CHEFCCR004", $1]
when /.*NameError: undefined local variable or method `(.+)' for cookbook.+/
# Invalid resource type in most cases
["CHEFCCR005", $1]
when /.*NoMethodError: undefined method `(.+)' for cookbook.+/
# Invalid resource type in most cases
["CHEFCCR005", $1]
Expand Down
3 changes: 2 additions & 1 deletion components/chef-workstation/lib/chef-workstation/log.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module ChefWorkstation
class Log
extend Mixlib::Log

def self.setup(location, log_level = "warn")
def self.setup(location, log_level)
@location = location
if location.is_a?(String)
if location.casecmp("stdout") == 0
Expand All @@ -14,6 +14,7 @@ def self.setup(location, log_level = "warn")
end
end
init(location)
Log.level = log_level
end

def self.location
Expand Down
Loading

0 comments on commit 8dcd1f7

Please sign in to comment.