diff options
27 files changed, 253 insertions, 121 deletions
@@ -8,6 +8,7 @@ InstalledFiles _yardoc coverage doc/ +binstubs/ lib/bundler/man pkg rdoc diff --git a/.travis.yml b/.travis.yml index 46648d9..4994db3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -rvm: 2.0 +rvm: 2.1 gemfile: Gemfile # This prevents testing branches that are created just for PRs @@ -18,8 +18,6 @@ script: matrix: include: - - rvm: 2.0 - - rvm: 2.1 - rvm: 2.1 env: PEDANT_KNIFE_TESTS=true PEDANT_ALLOW_RVM=1 - rvm: 2.1 @@ -39,11 +37,3 @@ matrix: script: bundle exec rake spec env: TEST=rake_spec -# allow_failures: -# - rvm: 2.1 -# gemfile: gemfiles/latest-chef.gemfile -# script: bundle exec rake chef_spec -# enc: TEST=chef_spec_latest -# - rvm: 2.1.1 -# gemfile: gemfiles/berkshelf.gemfile -# script: bundle exec rake berkshelf_spec diff --git a/CHANGELOG.md b/CHANGELOG.md index cce1efb..8627141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,59 @@ # Change Log -## [Unreleased](https://github.com/chef/chef-zero/tree/HEAD) +## [4.7.1](https://github.com/chef/chef-zero/tree/4.7.1) (2016-07-07) +[Full Changelog](https://github.com/chef/chef-zero/compare/v4.7.0...4.7.1) -[Full Changelog](https://github.com/chef/chef-zero/compare/v4.4.2...HEAD) +**Implemented enhancements:** + +- Downgrade info log message to debug [\#221](https://github.com/chef/chef-zero/pull/221) ([stanhu](https://github.com/stanhu)) + +## [v4.7.0](https://github.com/chef/chef-zero/tree/v4.7.0) (2016-06-30) +[Full Changelog](https://github.com/chef/chef-zero/compare/v4.6.2...v4.7.0) + +**Implemented enhancements:** + +- Add external\_authentication\_uid to actors endpoint for querying [\#217](https://github.com/chef/chef-zero/pull/217) ([kmacgugan](https://github.com/kmacgugan)) + +**Merged pull requests:** + +- Depend on rack \< 2 to restore Ruby 2.1 compat [\#219](https://github.com/chef/chef-zero/pull/219) ([tas50](https://github.com/tas50)) + +## [v4.6.2](https://github.com/chef/chef-zero/tree/v4.6.2) (2016-04-28) +[Full Changelog](https://github.com/chef/chef-zero/compare/v4.6.1...v4.6.2) + +**Fixed bugs:** + +- Log responses only at debug log level [\#216](https://github.com/chef/chef-zero/pull/216) ([stevendanna](https://github.com/stevendanna)) + +## [v4.6.1](https://github.com/chef/chef-zero/tree/v4.6.1) (2016-04-14) +[Full Changelog](https://github.com/chef/chef-zero/compare/v4.6.0...v4.6.1) + +**Fixed bugs:** + +- Actually merge key data in user PUT response [\#214](https://github.com/chef/chef-zero/pull/214) ([jkeiser](https://github.com/jkeiser)) +- Fix users endpoint in OSC compat mode to use a data store URL [\#213](https://github.com/chef/chef-zero/pull/213) ([jkeiser](https://github.com/jkeiser)) + +## [v4.6.0](https://github.com/chef/chef-zero/tree/v4.6.0) (2016-04-14) +[Full Changelog](https://github.com/chef/chef-zero/compare/v4.5.0...v4.6.0) + +**Implemented enhancements:** + +- Enable listening on more than one address [\#208](https://github.com/chef/chef-zero/pull/208) ([jaymzh](https://github.com/jaymzh)) +- Implemented GET /orgs/ORG/users/USER/keys\(/key\) endpoint recently added to server. [\#205](https://github.com/chef/chef-zero/pull/205) ([tylercloke](https://github.com/tylercloke)) +- Implement APIv1 behaviors [\#201](https://github.com/chef/chef-zero/pull/201) ([danielsdeleo](https://github.com/danielsdeleo)) +- Make user and client keys endpoints pass Pedant specs [\#199](https://github.com/chef/chef-zero/pull/199) ([jrunning](https://github.com/jrunning)) +- fix necessary for metadata gem [\#197](https://github.com/chef/chef-zero/pull/197) ([lamont-granquist](https://github.com/lamont-granquist)) + +**Fixed bugs:** + +- Fix bugs related to Array vs Enumerator vs Port for options\[:port/host\]. [\#212](https://github.com/chef/chef-zero/pull/212) ([tylercloke](https://github.com/tylercloke)) + +## [v4.5.0](https://github.com/chef/chef-zero/tree/v4.5.0) (2016-01-29) +[Full Changelog](https://github.com/chef/chef-zero/compare/v4.4.2...v4.5.0) **Merged pull requests:** +- Run chef-zero against master Chef in travis [\#195](https://github.com/chef/chef-zero/pull/195) ([jkeiser](https://github.com/jkeiser)) - Make ACLs for policies/policy\_groups/cookbook\_artifacts work [\#194](https://github.com/chef/chef-zero/pull/194) ([jkeiser](https://github.com/jkeiser)) - Return 410 on /controls so we stop skipping that pedant spec. [\#192](https://github.com/chef/chef-zero/pull/192) ([randomcamel](https://github.com/randomcamel)) - Enable container specs. [\#191](https://github.com/chef/chef-zero/pull/191) ([randomcamel](https://github.com/randomcamel)) @@ -5,6 +5,10 @@ gemspec gem 'oc-chef-pedant', :github => 'chef/chef-server' +group :changelog do + gem "github_changelog_generator" +end + # bundler resolve failure on "rspec_junit_formatter" # gem 'chef-pedant', :github => 'opscode/chef-pedant', :ref => "server-cli-option" @@ -52,11 +52,15 @@ task :berkshelf_spec do system("cd #{gem_path} && thor spec:ci") end -require 'github_changelog_generator/task' +begin + require "github_changelog_generator/task" -GitHubChangelogGenerator::RakeTask.new :changelog do |config| - # config.future_release = ChefZero::VERSION - config.enhancement_labels = "enhancement,Enhancement,New Feature".split(',') - config.bug_labels = "bug,Bug,Improvement,Upstream Bug".split(',') - config.exclude_labels = "duplicate,question,invalid,wontfix,no_changelog".split(',') + GitHubChangelogGenerator::RakeTask.new :changelog do |config| + config.future_release = ChefZero::VERSION + config.enhancement_labels = "enhancement,Enhancement,New Feature,Feature".split(",") + config.bug_labels = "bug,Bug,Improvement,Upstream Bug".split(",") + config.exclude_labels = "duplicate,question,invalid,wontfix,no_changelog,Exclude From Changelog,Question,Discussion".split(",") + end +rescue LoadError + puts "github_changelog_generator is not available. gem install github_changelog_generator to generate changelogs" end diff --git a/bin/chef-zero b/bin/chef-zero index 231d71b..33fc0e1 100755 --- a/bin/chef-zero +++ b/bin/chef-zero @@ -31,7 +31,8 @@ OptionParser.new do |opts| opts.banner = "Usage: chef-zero [ARGS]" opts.on("-H", "--host HOST", "Host to bind to (default: 127.0.0.1)") do |value| - options[:host] = value + options[:host] ||= [] + options[:host] << value end opts.on("-p", "--port PORT", "Port to listen on (e.g. 8889, or 8500-8600 or 8885,8888)") do |value| @@ -98,7 +99,11 @@ if options[:daemon] Process.daemon(true) server.start(true) else - abort 'Process.daemon requires Ruby >= 1.9' + if ENV['OS'] == 'Windows_NT' + abort 'Daemonization is not supported on Windows. Running 'start chef-zero' will fork the process.' + else + abort 'Process.daemon requires Ruby >= 1.9' + end end else server.start(true) diff --git a/chef-zero.gemspec b/chef-zero.gemspec index d512955..8114a81 100644 --- a/chef-zero.gemspec +++ b/chef-zero.gemspec @@ -8,22 +8,23 @@ Gem::Specification.new do |s| s.summary = 'Self-contained, easy-setup, fast-start in-memory Chef server for testing and solo setup purposes' s.description = s.summary s.author = 'John Keiser' - s.email = 'jkeiser@opscode.com' - s.homepage = 'http://www.opscode.com' + s.email = 'jkeiser@chef.io' + s.homepage = 'http://www.chef.io' s.license = 'Apache 2.0' - s.add_dependency 'mixlib-log', '~> 1.3' - s.add_dependency 'hashie', '>= 2.0', '< 4.0' + s.required_ruby_version = ">= 2.1.0" + + s.add_dependency 'mixlib-log', '~> 1.3' + s.add_dependency 'hashie', '>= 2.0', '< 4.0' s.add_dependency 'uuidtools', '~> 2.1' s.add_dependency 'ffi-yajl', '~> 2.2' - s.add_dependency 'rack' + s.add_dependency 'rack', '< 2' # 2.0 requires Ruby 2.2+ s.add_development_dependency 'pry' s.add_development_dependency 'pry-byebug' s.add_development_dependency 'pry-stack_explorer' s.add_development_dependency 'rake' s.add_development_dependency 'rspec' - s.add_development_dependency 'github_changelog_generator' s.add_development_dependency 'chef' s.bindir = 'bin' diff --git a/gemfiles/berkshelf.gemfile b/gemfiles/berkshelf.gemfile deleted file mode 100644 index ca99e91..0000000 --- a/gemfiles/berkshelf.gemfile +++ /dev/null @@ -1,15 +0,0 @@ -source 'https://rubygems.org' - -gemspec :path => "../" - -gem 'berkshelf', :github => 'berkshelf' - -# development dependencies of berkshelf -gem 'aruba', '~> 0.5' -gem 'fuubar', '~> 1.1' -gem 'rake', '~> 0.9' -gem 'rspec', '~> 2.13' -gem 'spork', '~> 0.9' -gem 'test-kitchen', '~> 1.2' -gem 'webmock', '~> 1.11' -gem 'yard', '~> 0.8' diff --git a/gemfiles/latest-chef.gemfile b/gemfiles/latest-chef.gemfile deleted file mode 100644 index 47420d6..0000000 --- a/gemfiles/latest-chef.gemfile +++ /dev/null @@ -1,5 +0,0 @@ -source 'https://rubygems.org' - -gemspec :path => "../" - -gem 'chef', :github => 'chef/chef' diff --git a/gemfiles/no-pedant.gemfile b/gemfiles/no-pedant.gemfile deleted file mode 100644 index 7784f18..0000000 --- a/gemfiles/no-pedant.gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source 'https://rubygems.org' - -gemspec :path => "../" - diff --git a/gemfiles/oc-chef-pedant.gemfile b/gemfiles/oc-chef-pedant.gemfile deleted file mode 100644 index dcdee27..0000000 --- a/gemfiles/oc-chef-pedant.gemfile +++ /dev/null @@ -1,6 +0,0 @@ -source 'https://rubygems.org' -gemspec :path => '../' - -gem 'rest-client', :github => 'chef/rest-client', :branch => 'lcg/1.6.7-version-lying' -gem 'oc-chef-pedant', :github => 'chef/oc-chef-pedant', :tag => '2.0.0' -gem 'chef', :github => 'chef/chef' diff --git a/lib/chef_zero/chef_data/cookbook_data.rb b/lib/chef_zero/chef_data/cookbook_data.rb index e690fde..4fd0320 100644 --- a/lib/chef_zero/chef_data/cookbook_data.rb +++ b/lib/chef_zero/chef_data/cookbook_data.rb @@ -129,11 +129,15 @@ module ChefZero self[key][cookbook] = version_constraints.first || ">= 0.0.0" end - def method_missing(key, value = nil) - if value.nil? + def method_missing(key, *values) + if values.nil? self[key.to_sym] else - store key.to_sym, value + if values.length > 1 + store key.to_sym, values + else + store key.to_sym, values.first + end end end end diff --git a/lib/chef_zero/chef_data/data_normalizer.rb b/lib/chef_zero/chef_data/data_normalizer.rb index da3802d..e819f1d 100644 --- a/lib/chef_zero/chef_data/data_normalizer.rb +++ b/lib/chef_zero/chef_data/data_normalizer.rb @@ -163,7 +163,7 @@ module ChefZero node['chef_type'] ||= 'node' node['chef_environment'] ||= '_default' node['override'] ||= {} - node['normal'] ||= {} + node['normal'] ||= {"tags" => []} node['default'] ||= {} node['automatic'] ||= {} node['run_list'] ||= [] diff --git a/lib/chef_zero/endpoints/actor_endpoint.rb b/lib/chef_zero/endpoints/actor_endpoint.rb index 28d8131..dd2caf2 100644 --- a/lib/chef_zero/endpoints/actor_endpoint.rb +++ b/lib/chef_zero/endpoints/actor_endpoint.rb @@ -161,22 +161,23 @@ module ChefZero # Return the data store keys path for the request client or user, e.g. # - # [ "organizations", <org>, "client_keys", <client>, "keys" ] - # - # Or: - # - # [ "user_keys", <user>, "keys" ] + # /organizations/ORG/clients/CLIENT -> /organizations/ORG/client_keys/CLIENT/keys + # /organizations/ORG/users/USER -> /organizations/ORG/user_keys/USER/keys + # /users/USER -> /user_keys/USER # def keys_path_base(request, client_or_user_name=nil) rest_path = (rest_path || request.rest_path).dup - rest_path[-1] = client_or_user_name if client_or_user_name - - if client?(request, rest_path) - [ *rest_path[0..1], "client_keys" ] + rest_path = rest_path.dup + case rest_path[-2] + when "users" + rest_path[-2] = "user_keys" + when "clients" + rest_path[-2] = "client_keys" else - [ "user_keys" ] + raise "Unexpected URL #{rest_path.join("/")}: cannot determine key path" end - .push(rest_path.last, "keys") + rest_path << "keys" + rest_path end end end diff --git a/lib/chef_zero/endpoints/actor_keys_endpoint.rb b/lib/chef_zero/endpoints/actor_keys_endpoint.rb index ba91a6b..f3624d6 100644 --- a/lib/chef_zero/endpoints/actor_keys_endpoint.rb +++ b/lib/chef_zero/endpoints/actor_keys_endpoint.rb @@ -8,7 +8,7 @@ module ChefZero DEFAULT_PUBLIC_KEY_NAME = "default" DATE_FORMAT = "%FT%TZ" # e.g. 2015-12-24T21:00:00Z - def get(request) + def get(request, alt_uri_root=nil) path = data_path(request) # Get actor or 404 if it doesn't exist @@ -18,7 +18,7 @@ module ChefZero key_names.unshift(DEFAULT_PUBLIC_KEY_NAME) if actor_has_default_public_key?(actor_json) result = key_names.map do |key_name| - list_key(request, [ *path, key_name ]) + list_key(request, [ *path, key_name ], alt_uri_root) end json_response(200, result) @@ -90,7 +90,7 @@ module ChefZero end end - def list_key(request, data_path) + def list_key(request, data_path, alt_uri_root=nil) key_name, expiration_date = if data_path[-1] == DEFAULT_PUBLIC_KEY_NAME [ DEFAULT_PUBLIC_KEY_NAME, "infinity" ] @@ -103,7 +103,7 @@ module ChefZero DateTime.now > DateTime.strptime(expiration_date, DATE_FORMAT) { "name" => key_name, - "uri" => key_uri(request, key_name), + "uri" => key_uri(request, key_name, alt_uri_root), "expired" => expired } end @@ -111,8 +111,9 @@ module ChefZero request.rest_path[2] == "clients" end - def key_uri(request, key_name) - build_uri(request.base_uri, [ *request.rest_path, key_name ]) + def key_uri(request, key_name, alt_uri_root=nil) + uri_root = alt_uri_root.nil? ? request.rest_path : alt_uri_root + build_uri(request.base_uri, [ *uri_root, key_name ]) end def actor_path(request) diff --git a/lib/chef_zero/endpoints/actors_endpoint.rb b/lib/chef_zero/endpoints/actors_endpoint.rb index cc02246..6297aed 100644 --- a/lib/chef_zero/endpoints/actors_endpoint.rb +++ b/lib/chef_zero/endpoints/actors_endpoint.rb @@ -8,17 +8,12 @@ module ChefZero def get(request) response = super(request) - if request.query_params['email'] - results = parse_json(response[2]) - new_results = {} - results.each do |name, url| - record = get_data(request, request.rest_path + [ name ], :nil) - if record - record = parse_json(record) - new_results[name] = url if record['email'] == request.query_params['email'] - end - end - response[2] = to_json(new_results) + # apply query filters: if one applies, stop processing rest + # (precendence matches chef-server: https://github.com/chef/chef-server/blob/268a0c9/src/oc_erchef/apps/chef_objects/src/chef_user.erl#L554-L559) + if value = request.query_params['external_authentication_uid'] + response[2] = filter('external_authentication_uid', value, request, response[2]) + elsif value = request.query_params['email'] + response[2] = filter('email', value, request, response[2]) end if request.query_params['verbose'] @@ -65,7 +60,7 @@ module ChefZero response = if request.api_v0? - user_data.merge(key_data) + user_data.merge!(key_data) elsif skip_key_create && !public_key user_data else @@ -85,6 +80,21 @@ module ChefZero result end end + + private + + def filter(key, value, request, resp) + results = parse_json(resp) + new_results = {} + results.each do |name, url| + record = get_data(request, request.rest_path + [ name ], :nil) + if record + record = parse_json(record) + new_results[name] = url if record[key] == value + end + end + to_json(new_results) + end end end end diff --git a/lib/chef_zero/endpoints/organization_user_default_key_endpoint.rb b/lib/chef_zero/endpoints/organization_user_default_key_endpoint.rb new file mode 100644 index 0000000..953edc1 --- /dev/null +++ b/lib/chef_zero/endpoints/organization_user_default_key_endpoint.rb @@ -0,0 +1,16 @@ +require 'chef_zero/rest_base' + +module ChefZero + module Endpoints + # GET /organizations/ORG/users/USER/keys/default + class OrganizationUserDefaultKeyEndpoint < RestBase + def get(request) + # 404 if it doesn't exist + get_data(request, request.rest_path[0..3]) + # Just use the /users/USER/keys/default endpoint + request.rest_path = request.rest_path[2..-1] + ActorDefaultKeyEndpoint.new(server).get(request) + end + end + end +end diff --git a/lib/chef_zero/endpoints/organization_user_key_endpoint.rb b/lib/chef_zero/endpoints/organization_user_key_endpoint.rb new file mode 100644 index 0000000..e0c114c --- /dev/null +++ b/lib/chef_zero/endpoints/organization_user_key_endpoint.rb @@ -0,0 +1,17 @@ +require 'chef_zero/rest_base' +require 'chef_zero/endpoints/actor_keys_endpoint' + +module ChefZero + module Endpoints + # GET /organizations/ORG/users/USER/keys/NAME + class OrganizationUserKeyEndpoint < RestBase + def get(request) + # 404 if not a member of the org + get_data(request, request.rest_path[0..3]) + # Just use the /users/USER/keys endpoint + request.rest_path = request.rest_path[2..-1] + ActorKeyEndpoint.new(server).get(request) + end + end + end +end diff --git a/lib/chef_zero/endpoints/organization_user_keys_endpoint.rb b/lib/chef_zero/endpoints/organization_user_keys_endpoint.rb new file mode 100644 index 0000000..96a84fe --- /dev/null +++ b/lib/chef_zero/endpoints/organization_user_keys_endpoint.rb @@ -0,0 +1,17 @@ +require 'chef_zero/rest_base' + +module ChefZero + module Endpoints + # GET /organizations/ORG/users/USER/keys + class OrganizationUserKeysEndpoint < RestBase + def get(request) + # 404 if it doesn't exist + get_data(request, request.rest_path[0..3]) + # Just use the /users/USER/keys/key endpoint + original_path = request.rest_path + request.rest_path = request.rest_path[2..-1] + ActorKeysEndpoint.new(server).get(request, original_path) + end + end + end +end diff --git a/lib/chef_zero/rest_request.rb b/lib/chef_zero/rest_request.rb index 60738cf..c12ea31 100644 --- a/lib/chef_zero/rest_request.rb +++ b/lib/chef_zero/rest_request.rb @@ -14,7 +14,13 @@ module ChefZero attr_accessor :rest_base_prefix def base_uri - @base_uri ||= "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}#{env['SCRIPT_NAME']}" + # Load balancer awareness + if env['HTTP_X_FORWARDED_PROTO'] + scheme = env['HTTP_X_FORWARDED_PROTO'] + else + scheme = env['rack.url_scheme'] + end + @base_uri ||= "#{scheme}://#{env['HTTP_HOST']}#{env['SCRIPT_NAME']}" end def base_uri=(value) @@ -41,6 +47,10 @@ module ChefZero @rest_path ||= rest_base_prefix + env['PATH_INFO'].split('/').select { |part| part != "" } end + def rest_path=(rest_path) + @rest_path = rest_path + end + def body=(body) @body = body end diff --git a/lib/chef_zero/rest_router.rb b/lib/chef_zero/rest_router.rb index 889c810..a93af8b 100644 --- a/lib/chef_zero/rest_router.rb +++ b/lib/chef_zero/rest_router.rb @@ -39,7 +39,7 @@ module ChefZero end def log_request(request) - ChefZero::Log.info do + ChefZero::Log.debug do "#{request.method} /#{request.rest_path.join("/")}".tap do |msg| next unless request.method =~ /^(POST|PUT)$/ @@ -60,7 +60,7 @@ module ChefZero end def log_response(response) - ChefZero::Log.info { + ChefZero::Log.debug { [ "", "--- RESPONSE (#{response[0]}) ---", response[2].chomp, diff --git a/lib/chef_zero/server.rb b/lib/chef_zero/server.rb index 7d508ca..19744b1 100644 --- a/lib/chef_zero/server.rb +++ b/lib/chef_zero/server.rb @@ -43,6 +43,9 @@ require 'chef_zero/endpoints/acl_endpoint' require 'chef_zero/endpoints/actor_endpoint' require 'chef_zero/endpoints/actors_endpoint' require 'chef_zero/endpoints/actor_key_endpoint' +require 'chef_zero/endpoints/organization_user_key_endpoint' +require 'chef_zero/endpoints/organization_user_default_key_endpoint' +require 'chef_zero/endpoints/organization_user_keys_endpoint' require 'chef_zero/endpoints/actor_default_key_endpoint' require 'chef_zero/endpoints/actor_keys_endpoint' require 'chef_zero/endpoints/cookbooks_endpoint' @@ -108,7 +111,7 @@ module ChefZero class Server DEFAULT_OPTIONS = { - :host => '127.0.0.1', + :host => ['127.0.0.1'], :port => 8889, :log_level => :warn, :generate_real_keys => true, @@ -139,6 +142,7 @@ module ChefZero def port if @port @port + # If options[:port] is not an Array or an Enumerable, it is just an Integer. elsif !options[:port].respond_to?(:each) options[:port] else @@ -161,10 +165,11 @@ module ChefZero # def url sch = @options[:ssl] ? 'https' : 'http' - @url ||= if @options[:host].include?(':') - URI("#{sch}://[#{@options[:host]}]:#{port}").to_s + hosts = Array(@options[:host]) + @url ||= if hosts.first.include?(':') + URI("#{sch}://[#{hosts.first}]:#{port}").to_s else - URI("#{sch}://#{@options[:host]}:#{port}").to_s + URI("#{sch}://#{hosts.first}:#{port}").to_s end end @@ -262,12 +267,26 @@ module ChefZero # @return [Thread] # the thread the background process is running in # + def listen(hosts, port) + hosts.each do |host| + @server.listen(host, port) + end + true + rescue Errno::EADDRINUSE + ChefZero::Log.warn("Port #{port} not available") + @server.listeners.each { |l| l.close } + @server.listeners.clear + false + end + def start_background(wait = 5) @server = WEBrick::HTTPServer.new( :DoNotListen => true, :AccessLog => [], :Logger => WEBrick::Log.new(StringIO.new, 7), + :RequestTimeout => 300, :SSLEnable => options[:ssl], + :SSLOptions => ssl_opts, :SSLCertName => [ [ 'CN', WEBrick::Utils::getservername ] ], :StartCallback => proc { @running = true @@ -277,22 +296,17 @@ module ChefZero @server.mount('/', Rack::Handler::WEBrick, app) # Pick a port - if options[:port].respond_to?(:each) - options[:port].each do |port| - begin - @server.listen(options[:host], port) - @port = port - break - rescue Errno::EADDRINUSE - ChefZero::Log.info("Port #{port} in use: #{$!}") - end - end - if !@port - raise Errno::EADDRINUSE, "No port in :port range #{options[:port]} is available" + # If options[:port] can be an Enumerator, an Array, or an Integer, + # we need something that can respond to .each (Enum and Array can already). + Array(options[:port]).each do |port| + if listen(Array(options[:host]), port) + @port = port + break end - else - @server.listen(options[:host], options[:port]) - @port = options[:port] + end + if !@port + raise Errno::EADDRINUSE, + "No port in :port range #{options[:port]} is available" end # Start the server in the background @@ -526,7 +540,7 @@ module ChefZero [ [ "/organizations/*/users", ActorsEndpoint.new(self) ], [ "/organizations/*/users/*", ActorEndpoint.new(self) ], - [ "/organizations/*/authenticate_user", OrganizationAuthenticateUserEndpoint.new(self) ], + [ "/organizations/*/authenticate_user", OrganizationAuthenticateUserEndpoint.new(self) ] ] else # EC-only @@ -547,7 +561,6 @@ module ChefZero [ "/authenticate_user", AuthenticateUserEndpoint.new(self) ], [ "/system_recovery", SystemRecoveryEndpoint.new(self) ], [ "/license", LicenseEndpoint.new(self) ], - [ "/organizations", OrganizationsEndpoint.new(self) ], [ "/organizations/*", OrganizationEndpoint.new(self) ], [ "/organizations/*/_validator_key", OrganizationValidatorKeyEndpoint.new(self) ], @@ -573,6 +586,9 @@ module ChefZero [ "/organizations/*/clients/*/keys", ActorKeysEndpoint.new(self) ], [ "/organizations/*/clients/*/keys/default", ActorDefaultKeyEndpoint.new(self) ], [ "/organizations/*/clients/*/keys/*", ActorKeyEndpoint.new(self) ], + [ "/organizations/*/users/*/keys", OrganizationUserKeysEndpoint.new(self) ], + [ "/organizations/*/users/*/keys/default", OrganizationUserDefaultKeyEndpoint.new(self) ], + [ "/organizations/*/users/*/keys/*", OrganizationUserKeyEndpoint.new(self) ], [ "/organizations/*/controls", ControlsEndpoint.new(self) ], [ "/organizations/*/cookbooks", CookbooksEndpoint.new(self) ], [ "/organizations/*/cookbooks/*", CookbookEndpoint.new(self) ], @@ -694,5 +710,16 @@ module ChefZero end value end + + ## Disable unsecure ssl + ## Ref: https://www.ruby-lang.org/en/news/2014/10/27/changing-default-settings-of-ext-openssl/ + def ssl_opts + ssl_opts = OpenSSL::SSL::OP_ALL + ssl_opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS) + ssl_opts |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION) + ssl_opts |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2) + ssl_opts |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3) + ssl_opts + end end end diff --git a/lib/chef_zero/solr/query/regexpable_query.rb b/lib/chef_zero/solr/query/regexpable_query.rb index 241e675..cebc011 100644 --- a/lib/chef_zero/solr/query/regexpable_query.rb +++ b/lib/chef_zero/solr/query/regexpable_query.rb @@ -21,8 +21,8 @@ module ChefZero end DEFAULT_FIELD = "text" - WORD_CHARACTER = "[A-Za-z0-9@._':]" - NON_WORD_CHARACTER = "[^A-Za-z0-9@._':]" + WORD_CHARACTER = "[A-Za-z0-9@._':\-]" + NON_WORD_CHARACTER = "[^A-Za-z0-9@._':\-]" end end end diff --git a/lib/chef_zero/solr/query/unary_operator.rb b/lib/chef_zero/solr/query/unary_operator.rb index fc46c0d..a873932 100644 --- a/lib/chef_zero/solr/query/unary_operator.rb +++ b/lib/chef_zero/solr/query/unary_operator.rb @@ -16,8 +16,7 @@ module ChefZero def matches_doc?(doc) case @operator - when '-' - when 'NOT' + when '-', 'NOT' !operand.matches_doc?(doc) when '+' # TODO This operator uses relevance to eliminate other, unrelated @@ -28,8 +27,7 @@ module ChefZero def matches_values?(values) case @operator - when '-' - when 'NOT' + when '-', 'NOT' !operand.matches_values?(values) when '+' # TODO This operator uses relevance to eliminate other, unrelated diff --git a/lib/chef_zero/version.rb b/lib/chef_zero/version.rb index 6fb6e7e..d39f82c 100644 --- a/lib/chef_zero/version.rb +++ b/lib/chef_zero/version.rb @@ -1,3 +1,3 @@ module ChefZero - VERSION = '4.5.0' + VERSION = '4.7.1' end diff --git a/spec/search_spec.rb b/spec/search_spec.rb index df0522c..54392a6 100644 --- a/spec/search_spec.rb +++ b/spec/search_spec.rb @@ -24,6 +24,10 @@ describe ChefZero::Solr::SolrParser do search_for('foo:[a TO c]').size.should eq(1) end + it "handles -" do + search_for('-foo:a').size.should eq(1) + end + it "handles wildcard ranges" do search_for('foo:[* TO c]').size.should eq(1) search_for('foo:[c TO *]').size.should eq(1) diff --git a/spec/server_spec.rb b/spec/server_spec.rb index d46084f..123a13e 100644 --- a/spec/server_spec.rb +++ b/spec/server_spec.rb @@ -27,6 +27,10 @@ describe ChefZero::Server do expect { ChefZero::Server.new(:port => 8889.upto(8889)).start_background }.to raise_error Errno::EADDRINUSE end + it 'has a very patient request timeout' do + expect(@server.server.config[:RequestTimeout]).to eq 300 + end + context 'accept headers' do def get_nodes(accepts) uri = URI(@server.url) |