summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <jkeiser@opscode.com>2014-09-01 20:34:09 -0700
committerJohn Keiser <jkeiser@opscode.com>2014-09-03 10:28:23 -0700
commitb338ff7dfaefd64eee4465ae060d12cd7346a655 (patch)
tree1cf018a0e03ba4775e5b66970783b6e8aa4ed5cf
parentb6f92cf2eac4a8056d8594a94aa026b69e348386 (diff)
downloadchef-b338ff7dfaefd64eee4465ae060d12cd7346a655.tar.gz
Make local mode multi-tenant by default, add organization
and chef_server_root options.
-rw-r--r--lib/chef/application.rb6
-rw-r--r--lib/chef/chef_fs/file_system/chef_server_root_dir.rb11
-rw-r--r--lib/chef/config.rb115
-rw-r--r--lib/chef/knife.rb10
-rw-r--r--lib/chef/knife/serve.rb10
-rw-r--r--lib/chef/local_mode.rb165
-rw-r--r--spec/integration/knife/common_options_spec.rb6
-rw-r--r--spec/integration/knife/serve_spec.rb72
-rw-r--r--spec/unit/config_spec.rb104
9 files changed, 446 insertions, 53 deletions
diff --git a/lib/chef/application.rb b/lib/chef/application.rb
index 7a80b700d6..ce74c5b710 100644
--- a/lib/chef/application.rb
+++ b/lib/chef/application.rb
@@ -41,6 +41,8 @@ class Chef::Application
# from failing due to permissions when launched as a less privileged user.
end
+ attr_reader :local_mode
+
# Reconfigure the application. You'll want to override and super this method.
def reconfigure
configure_chef
@@ -186,7 +188,8 @@ class Chef::Application
# Initializes Chef::Client instance and runs it
def run_chef_client(specific_recipes = [])
- Chef::LocalMode.with_server_connectivity do
+ Chef::LocalMode.start do |local_mode|
+ @local_mode = local_mode
override_runlist = config[:override_runlist]
if specific_recipes.size > 0
override_runlist ||= []
@@ -201,6 +204,7 @@ class Chef::Application
@chef_client.run
@chef_client = nil
+ @local_mode = nil
end
end
diff --git a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb b/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
index 0083ee4cfa..f34cc8e6c0 100644
--- a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
@@ -81,10 +81,13 @@ class Chef
end
def org
- @org ||= if URI.parse(chef_server_url).path =~ /^\/+organizations\/+([^\/]+)$/
- $1
- else
- nil
+ @org ||= begin
+ path = Pathname.new(URI.parse(chef_server_url).path).cleanpath
+ if File.basename(File.dirname(path)) == 'organizations'
+ File.basename(path)
+ else
+ nil
+ end
end
end
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index e8a9839d71..d57f398f4d 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -25,6 +25,7 @@ require 'mixlib/config'
require 'chef/util/selinux'
require 'chef/util/path_helper'
require 'pathname'
+require 'uri'
class Chef
class Config
@@ -126,8 +127,8 @@ class Chef
end
def self.find_chef_repo_path(cwd)
- # In local mode, we auto-discover the repo root by looking for a path with "cookbooks" under it.
- # This allows us to run config-free.
+ # In local mode, we auto-discover the repo root by looking for a path with
+ # "cookbooks" under it. This allows us to run config-free.
path = cwd
until File.directory?(PathHelper.join(path, "cookbooks"))
new_path = File.expand_path('..', path)
@@ -272,7 +273,7 @@ class Chef
# context. When a tty is available (usually becase the user is running chef
# in a console), the log level is set to :warn, and output formatters are
# used as the primary mode of output. When a tty is not available, the
- # logger is the primary mode of output, and the log level is set to :info
+ # logger is the primary mode of output, and the log level is set to :info.
default :log_level, :auto
# Logging location as either an IO stream or string representing log file path
@@ -295,17 +296,123 @@ class Chef
default :diff_disabled, false
default :diff_filesize_threshold, 10000000
default :diff_output_threshold, 1000000
+
+ # Local mode (-z). When this is on, two major things happen:
+ # 1. A local Chef server (chef-zero) starts up, serving up the files in your
+ # local Chef repository directory.
+ # 2. The chef repository directory is *inferred* from your current directory
+ # by crawling up the directory tree until a cookbooks/ directory is found.
+ # If one is not found, the chef repository is assumed to be "."
+ # Default: false
default :local_mode, false
default :pid_file, nil
+ # The set of parameters for chef-zero in local mode.
config_context :chef_zero do
config_strict_mode true
+ # Whether chef_zero should run. If this is true, chef_zero will be started
+ # with the parameters in the chef_zero config, and the chef_server_root
+ # or chef_server_url will be replaced according to it.
+ # Defaults to true if local_mode is true.
default(:enabled) { Chef::Config.local_mode }
+ # The host chef_zero will listen on. Defaults to localhost.
default :host, 'localhost'
+ # The port for chef_zero to run on. If set to an array or enumerable like
+ # [100,105,110] or 100.upto(200), it will try each port until it finds an
+ # open one. Defaults to 8889.upto(9999)
default :port, 8889.upto(9999) # Will try ports from 8889-9999 until one works
+ # Whether to run with Chef 11 OSC compatibility on. Defaults to false;
+ # it will run in Enterprise mode with the following changes:
+ # - organization will default to "chef"
+ # - Chef::Config.organization will automatically be created
+ # - chef_server_root will be set to https://#{chef_zero.host}:#{chef_zero.port}
+ # - chef_server_url will be set to #{chef_server_root}/organizations/#{organization}
+ default :chef_11_osc_compat, false
+ end
+
+ # The URL to the Chef Server / organization (the location under which most
+ # objects like nodes, cookbooks and roles will be found).
+ #
+ # Default:
+ # - if organization is set, this is #{chef_server_root}/organizations/#{organization}.
+ # - if chef_zero.enabled = true, this will be set to the chef-zero server url
+ # when it starts.
+ # - otherwise, it is "https://localhost:443".
+ default :chef_server_url do
+ if chef_server_root
+ if has_key?(:organization)
+ File.join(chef_server_root, 'organizations', organization)
+ end
+ elsif chef_zero.enabled
+ # If chef-zero is enabled, we wait until local mode gives us a value
+ # instead of reporting a false one like localhost:443
+ nil
+ else
+ 'https://localhost:443'
+ end
+ end
+
+ # The URL to the top of the Chef Server, under which /organizations and
+ # /users can be found. Typically chef_server_url is the URL that will be
+ # used for client operations, but this is a convenient way to work in a
+ # multi-org environment (defined your root url once and set
+ # Chef::Config.organization, and chef_server_url will be automatically set
+ # to #{chef_server_root}/organizations/#{organization}).
+ #
+ # Default:
+ # - if chef_server_url is set, we try to infer chef_server_root from it:
+ # when chef_server_url = https://blah.com/organizations/orgname,
+ # chef_server_root = https://blah.com.
+ # - if chef_zero is enabled, this will be set when chef-zero starts.
+ # - if organization is set, chef_server_root is https://api.opscode.com
+ # - otherwise, chef_server_root = nil.
+ #
+ default(:chef_server_root) do
+ if has_key?(:chef_server_url)
+ # https://blah.com/organizations/foo -> https://blah.com
+ path = Pathname.new(URI.parse(chef_server_url).path).cleanpath
+ if !has_key?(:organization) || path.basename.to_s == organization
+ path = path.dirname
+ if path.basename.to_s == 'organizations'
+ URI.join(chef_server_url, path.dirname.to_s).to_s.chomp('/')
+ end
+ end
+ elsif chef_zero.enabled
+ nil
+ elsif has_key?(:organization)
+ # If the user has not defined chef_server_url or chef_server_root,
+ # assume they meant Hosted Chef. This way, if they define
+ # Chef::Config.organization, chef_server_url will turn out to be
+ # https://api.opscode.com/organizations/#{Chef::Config.organization}.
+ "https://api.opscode.com"
+ end
+ end
+
+ # The organization the user is working with in Hosted or Enterprise Chef.
+ # If this is not set, the user is assumed to be working with Open Source Chef
+ # 10 or 11.
+ #
+ # Default:
+ # - If chef_zero.enabled is true and chef_zero.chef_11_osc_compat is false,
+ # the default is "chef".
+ # - If chef_server_url is set, we try to infer organization from it:
+ # when chef_server_url = https://blah.com/organizations/orgname,
+ # organization = orgname.
+ default(:organization) do
+ if chef_zero.enabled
+ unless chef_zero.chef_11_osc_compat
+ 'chef'
+ end
+
+ elsif has_key?(:chef_server_url)
+ # https://blah.com/organizations/foo -> foo
+ path = Pathname.new(URI.parse(chef_server_url).path).cleanpath
+ if path.dirname.basename.to_s == 'organizations'
+ path.basename.to_s
+ end
+ end
end
- default :chef_server_url, "https://localhost:443"
default :rest_timeout, 300
default :yum_timeout, 900
diff --git a/lib/chef/knife.rb b/lib/chef/knife.rb
index 038ab61715..df72d5d612 100644
--- a/lib/chef/knife.rb
+++ b/lib/chef/knife.rb
@@ -58,6 +58,7 @@ class Chef
attr_accessor :name_args
attr_accessor :ui
+ attr_reader :local_mode
# Configure mixlib-cli to always separate defaults from user-supplied CLI options
def self.use_separate_defaults?
@@ -489,8 +490,13 @@ class Chef
ui.error "You need to add a #run method to your knife command before you can use it"
end
enforce_path_sanity
- Chef::LocalMode.with_server_connectivity do
- run
+ Chef::LocalMode.start do |local_mode|
+ @local_mode = local_mode
+ begin
+ run
+ ensure
+ @local_mode = nil
+ end
end
rescue Exception => e
raise if raise_exception || Chef::Config[:verbosity] == 2
diff --git a/lib/chef/knife/serve.rb b/lib/chef/knife/serve.rb
index 870177e0be..7d06e53d7b 100644
--- a/lib/chef/knife/serve.rb
+++ b/lib/chef/knife/serve.rb
@@ -31,13 +31,13 @@ class Chef
end
def run
- server = Chef::LocalMode.chef_zero_server
+ server = local_mode.chef_zero_server
begin
- output "Serving files from:\n#{Chef::LocalMode.chef_fs.fs_description}"
- server.stop
- server.start(stdout) # to print header
+ output "Serving files from:\n#{local_mode.chef_fs.fs_description}"
+ local_mode.chef_zero_server.stop
+ local_mode.chef_zero_server.start(stdout) # to print header
ensure
- server.stop
+ local_mode.chef_zero_server.stop
end
end
end
diff --git a/lib/chef/local_mode.rb b/lib/chef/local_mode.rb
index e66acb6b66..8c7cbf2237 100644
--- a/lib/chef/local_mode.rb
+++ b/lib/chef/local_mode.rb
@@ -17,76 +17,187 @@
require 'chef/config'
class Chef
- module LocalMode
- # Create a chef local server (if the configuration requires one) for the
+ class LocalMode
+ #
+ # Create a chef local server (if the config[:ration] requires one) for the
# duration of the given block.
#
+ # If given a block, local mode will be stopped before returning.
# # This ...
- # with_server_connectivity { stuff }
+ # Chef::LocalMode.start { |local_mode| stuff }
#
# # Is exactly equivalent to this ...
- # Chef::LocalMode.setup_server_connectivity
+ # local_mode = Chef::LocalMode.new(Chef::Config)
+ # local_mode.start
# begin
# stuff
# ensure
- # Chef::LocalMode.destroy_server_connectivity
+ # local_mode.stop
# end
#
- def self.with_server_connectivity
- setup_server_connectivity
- begin
- yield
- ensure
- destroy_server_connectivity
+ def self.start(config = Chef::Config)
+ local_mode = LocalMode.new(config)
+ local_mode.start
+ if block_given?
+ begin
+ yield local_mode
+ ensure
+ local_mode.stop
+ local_mode = nil
+ end
+ else
+ local_mode
end
end
- # If Chef::Config.chef_zero.enabled is true, sets up a chef-zero server
- # according to the Chef::Config.chef_zero and path options, and sets
+ # Create a new LocalMode-honoring object.
+ # == Input
+ #
+ # Takes a config[:hash] with the keys:
+ # :chef_zero - hash with config[:for] chef_zero, with these keys:
+ # :enabled - whether to run chef-zero (if false, this class does nothing)
+ # :host - the host to run chef-zero on
+ # :port - the port (or array/enumerable range of ports) to start chef-zero on
+ # :chef_11_osc_compat - true if we should run in Chef 11 OSC compatibility mode,
+ # with no ACLs/groups/containers/organizations.
+ # :organization - the default organization to create in chef-zero (nil for none).
+ # :chef_repo_path - the directory where Chef objects are stored (nodes,
+ # roles, etc.). May be an array of paths.
+ # :acl_path, :client_path, :container_path, :cookbook_path,
+ # :environment_path, :group_path, :node_path, :role_path, :user_path -
+ # directory where given objects are stored (if different from
+ # chef_repo_path/roles, chef_repo_path/nodes, etc.). May be an array
+ # of paths.
+ # :repo_mode - the mode of the repository: :hosted_everything, :everything
+ # or :static. :hosted_everything is the default. :everything
+ # is the default if chef_11_osc_compat is on.
+ # :node_name - the name of the user to connect to the server with
+ # :client_key - a path to a private key to sign requests with
+ #
+ # == Output
+ #
+ # When start is called, these "config" hash keys will be updated:
+ # :chef_server_root - https://{chef_zero.host}:{chef_zero.port}
+ # :chef_server_url - {chef_server_root}/organizations/#{organization}
+ #
+ # If chef_11_osc_compat is on, chef_server_url will be set to the root,
+ # and chef_server_root will be set to nil.
+ #
+ def initialize(config)
+ @config = config
+ end
+
+ attr_reader :config
+
+ # If config[:chef_zero][:enabled] is true, sets up a chef-zero server
+ # according to the config[:chef_zero][:and] path options, and sets
# chef_server_url to point at it.
- def self.setup_server_connectivity
- if Chef::Config.chef_zero.enabled
- destroy_server_connectivity
+ def start
+ if config[:chef_zero][:enabled]
+ stop
+ # Try not to incur the cost of loading things unless we need them
require 'chef_zero/server'
require 'chef/chef_fs/chef_fs_data_store'
require 'chef/chef_fs/config'
- @chef_fs = Chef::ChefFS::Config.new.local_fs
+ @saved_config = config.save
+
+ #
+ # Start up the chef repo filesystem
+ #
+ @chef_fs = Chef::ChefFS::Config.new(config).local_fs
@chef_fs.write_pretty_json = true
data_store = Chef::ChefFS::ChefFSDataStore.new(@chef_fs)
- data_store = ChefZero::DataStore::V1ToV2Adapter.new(data_store, 'chef')
+ # If the data store already has an org.json, grab an org name
+ # from that.
+ if !config.has_key?(:organization) && data_store.exists?([ 'org' ])
+ org = JSON.parse(data_store.get([ 'org' ]), :create_additions => false)
+ config[:organization] = org['name'] if org.is_a?(Hash)
+ end
+ config[:organization] ||= 'chef'
+ data_store = ChefZero::DataStore::V1ToV2Adapter.new(data_store, config[:organization] || 'chef')
+
+ #
+ # Start the chef-zero server
+ #
server_options = {}
server_options[:data_store] = data_store
server_options[:log_level] = Chef::Log.level
- server_options[:host] = Chef::Config.chef_zero.host
- server_options[:port] = parse_port(Chef::Config.chef_zero.port)
+ server_options[:host] = config[:chef_zero][:host]
+ server_options[:port] = parse_port(config[:chef_zero][:port])
+ if config[:chef_zero][:chef_11_osc_compat]
+ server_options[:osc_compat] = true
+ server_options[:single_org] = config[:organization]
+ else
+ server_options[:osc_compat] = false
+ server_options[:single_org] = false
+ end
@chef_zero_server = ChefZero::Server.new(server_options)
@chef_zero_server.start_background
- Chef::Log.info("Started chef-zero at #{@chef_zero_server.url} with #{@chef_fs.fs_description}")
- Chef::Config.chef_server_url = @chef_zero_server.url
+ Chef::Log.info("Started#{config[:chef_zero][:chef_11_osc_compat] ? " OSC-compatible" : ""} chef-zero at #{@chef_zero_server.url} with #{@chef_fs.fs_description}")
+ Chef::Log.debug("Server options #{server_options}")
+
+ # Set server url in config
+ if config[:chef_zero][:chef_11_osc_compat]
+ config[:chef_server_url] = @chef_zero_server.url
+ config.delete(:chef_server_root)
+ config.delete(:organization)
+ else
+ config[:chef_server_root] = @chef_zero_server.url
+ config.delete(:chef_server_url) # Default will do us just fine, thanks.
+ begin
+ root.post('/organizations', { 'name' => config[:organization] })
+ rescue Net::HTTPServerException => e
+ if e.response.code != '409'
+ raise
+ end
+ end
+ end
end
end
- # Return the current chef-zero server set up by setup_server_connectivity.
- def self.chef_zero_server
+ def root
+ Chef::ServerAPI.new(config[:chef_server_root], :client_name => config[:node_name], :signing_key_filename => config[:client_key])
+ end
+
+ # Return the current chef-zero server set up by start.
+ def chef_zero_server
@chef_zero_server
end
# Return the chef_fs object for the current chef-zero server.
- def self.chef_fs
+ def chef_fs
@chef_fs
end
# If chef_zero_server is non-nil, stop it and remove references to it.
- def self.destroy_server_connectivity
+ def stop
if @chef_zero_server
@chef_zero_server.stop
@chef_zero_server = nil
end
+ # Restore config
+ if @saved_config
+ # We are trying to be surgical with our restore, and only restore
+ # values that we put there.
+ [:chef_server_url, :chef_server_root, :organization].each do |key|
+ # TODO give mixlib-config a better restore method that is willing
+ # to delete keys that are not saved
+ if @saved_config.has_key?(key)
+ config[:chef_server_url] = @saved_config[key]
+ else
+ config.delete(key)
+ end
+ end
+
+ @saved_config = nil
+ end
end
- def self.parse_port(port)
+ private
+
+ def parse_port(port)
if port.is_a?(String)
parts = port.split(',')
if parts.size == 1
diff --git a/spec/integration/knife/common_options_spec.rb b/spec/integration/knife/common_options_spec.rb
index 7a48f14ad3..d8319b168f 100644
--- a/spec/integration/knife/common_options_spec.rb
+++ b/spec/integration/knife/common_options_spec.rb
@@ -39,7 +39,6 @@ describe 'knife common options' do
it 'knife raw /nodes/x should retrieve the node' do
knife('raw /nodes/x').should_succeed( /"name": "x"/ )
- Chef::Config.chef_server_url.should == 'http://localhost:9999'
end
end
@@ -101,7 +100,6 @@ EOM
it 'knife raw -z --chef-zero-port=9999 /nodes/x retrieves the node' do
knife('raw -z --chef-zero-port=9999 /nodes/x').should_succeed( /"name": "x"/ )
- Chef::Config.chef_server_url.should == 'http://localhost:9999'
end
context 'when the default port (8889) is already bound' do
@@ -119,7 +117,6 @@ EOM
it 'knife raw -z /nodes/x retrieves the node' do
knife('raw -z /nodes/x').should_succeed( /"name": "x"/ )
- expect(URI(Chef::Config.chef_server_url).port).to be > 8889
end
end
@@ -138,18 +135,15 @@ EOM
it 'knife raw -z --chef-zero-port=9999-20000 /nodes/x' do
knife('raw -z --chef-zero-port=9999-20000 /nodes/x').should_succeed( /"name": "x"/ )
- expect(URI(Chef::Config.chef_server_url).port).to be > 9999
end
it 'knife raw -z --chef-zero-port=9999-9999,19423' do
knife('raw -z --chef-zero-port=9999-9999,19423 /nodes/x').should_succeed( /"name": "x"/ )
- expect(URI(Chef::Config.chef_server_url).port).to be == 19423
end
end
it 'knife raw -z --chef-zero-port=9999 /nodes/x retrieves the node' do
knife('raw -z --chef-zero-port=9999 /nodes/x').should_succeed( /"name": "x"/ )
- Chef::Config.chef_server_url.should == 'http://localhost:9999'
end
end
end
diff --git a/spec/integration/knife/serve_spec.rb b/spec/integration/knife/serve_spec.rb
index 32e633543d..c12c9ffd75 100644
--- a/spec/integration/knife/serve_spec.rb
+++ b/spec/integration/knife/serve_spec.rb
@@ -24,10 +24,10 @@ describe 'knife serve' do
include KnifeSupport
include AppServerSupport
- when_the_repository 'also has one of each thing' do
+ when_the_repository 'has a node named x' do
before { file 'nodes/x.json', { 'foo' => 'bar' } }
- it 'knife serve serves up /nodes/x' do
+ it 'knife serve serves up /organizations/chef/nodes/x' do
exception = nil
t = Thread.new do
begin
@@ -38,7 +38,7 @@ describe 'knife serve' do
end
begin
Chef::Config.log_level = :debug
- Chef::Config.chef_server_url = 'http://localhost:8889'
+ Chef::Config.chef_server_url = 'http://localhost:8889/organizations/chef'
Chef::Config.node_name = nil
Chef::Config.client_key = nil
api = Chef::ServerAPI.new
@@ -53,5 +53,71 @@ describe 'knife serve' do
t.kill
end
end
+
+ context 'and organization = foo' do
+ before do
+ Chef::Config.organization = 'foo'
+ end
+
+ it 'knife serve serves up /organizations/foo/nodes/x' do
+ exception = nil
+ t = Thread.new do
+ begin
+ knife('serve --chef-zero-port=8889')
+ rescue
+ exception = $!
+ end
+ end
+ begin
+ Chef::Config.log_level = :debug
+ Chef::Config.chef_server_url = 'http://localhost:8889/organizations/foo'
+ Chef::Config.node_name = nil
+ Chef::Config.client_key = nil
+ api = Chef::ServerAPI.new
+ api.get('nodes/x')['name'].should == 'x'
+ rescue
+ if exception
+ raise exception
+ else
+ raise
+ end
+ ensure
+ t.kill
+ end
+ end
+ end
+
+ context 'and chef_zero.chef_11_osc_compat = true' do
+ before do
+ Chef::Config.chef_zero.chef_11_osc_compat = true
+ end
+
+ it 'knife serve serves up /nodes/x' do
+ exception = nil
+ t = Thread.new do
+ begin
+ knife('serve --chef-zero-port=8889')
+ rescue
+ exception = $!
+ end
+ end
+ begin
+ Chef::Config.log_level = :debug
+ Chef::Config.chef_server_url = 'http://localhost:8889'
+ Chef::Config.node_name = nil
+ Chef::Config.client_key = nil
+ api = Chef::ServerAPI.new
+ api.get('nodes/x')['name'].should == 'x'
+ rescue
+ if exception
+ raise exception
+ else
+ raise
+ end
+ ensure
+ t.kill
+ end
+ end
+ end
end
end
diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb
index af71c43b77..fff09c48f8 100644
--- a/spec/unit/config_spec.rb
+++ b/spec/unit/config_spec.rb
@@ -27,8 +27,10 @@ describe Chef::Config do
Chef::Config.chef_server_url = "https://junglist.gen.nz"
end
- it "sets the server url" do
+ it "sets chef_server_url, and leaves chef_server_root and organization blank" do
Chef::Config.chef_server_url.should == "https://junglist.gen.nz"
+ Chef::Config.organization.should == nil
+ Chef::Config.chef_server_root.should == nil
end
context "when the url has a leading space" do
@@ -52,6 +54,106 @@ describe Chef::Config do
end
end
+ context "when the url is https://api.blah.com:9000/organizations/foo" do
+ before do
+ Chef::Config.chef_server_url = "https://api.blah.com:9000/organizations/foo"
+ end
+
+ it "sets organization to foo and chef_server_root to https://api.blah.com:9000" do
+ Chef::Config.chef_server_root.should == "https://api.blah.com:9000"
+ Chef::Config.organization.should == "foo"
+ end
+ end
+
+ context "when the url is https://api.blah.com:9000/organizations/foo/" do
+ before do
+ Chef::Config.chef_server_url = "https://api.blah.com:9000/organizations/foo/"
+ end
+
+ it "sets organization to foo and chef_server_root to https://api.blah.com:9000" do
+ Chef::Config.chef_server_root.should == "https://api.blah.com:9000"
+ Chef::Config.organization.should == "foo"
+ end
+ end
+
+ context "when the url is https://api.blah.com:9000/supercool/organizations/foo" do
+ before do
+ Chef::Config.chef_server_url = "https://api.blah.com:9000/supercool/organizations/foo"
+ end
+
+ it "sets organization to foo and chef_server_root to https://api.blah.com:9000/supercool" do
+ Chef::Config.chef_server_root.should == "https://api.blah.com:9000/supercool"
+ Chef::Config.organization.should == "foo"
+ end
+ end
+
+ context "when the url is https://api.blah.com:9000/organization/foo" do
+ before do
+ Chef::Config.chef_server_url = "https://api.blah.com:9000/organization/foo"
+ end
+
+ it "leaves chef_server_root and organization nil" do
+ Chef::Config.chef_server_root.should == nil
+ Chef::Config.organization.should == nil
+ end
+ end
+ end
+
+ describe "chef_server_root and organization" do
+ context "when organization is foo" do
+ before do
+ Chef::Config.organization = 'foo'
+ end
+
+ it "sets chef_server_root to api.opscode.com and chef_server_url to root/organizations/foo" do
+ Chef::Config.chef_server_root.should == 'https://api.opscode.com'
+ Chef::Config.chef_server_url.should == 'https://api.opscode.com/organizations/foo'
+ end
+ end
+
+ context "when chef_server_root is http://a.b.com:9000 and organization is foo" do
+ before do
+ Chef::Config.chef_server_root = 'http://a.b.com:9000'
+ Chef::Config.organization = 'foo'
+ end
+
+ it "sets chef_server_url to http://a.b.com:9000/organizations/foo" do
+ Chef::Config.chef_server_url.should == 'http://a.b.com:9000/organizations/foo'
+ end
+ end
+
+ context "when chef_server_root is http://a.b.com:9000/supercool and organization is foo" do
+ before do
+ Chef::Config.chef_server_root = 'http://a.b.com:9000/supercool'
+ Chef::Config.organization = 'foo'
+ end
+
+ it "sets chef_server_url to http://a.b.com:9000/supercool/organizations/foo" do
+ Chef::Config.chef_server_url.should == 'http://a.b.com:9000/supercool/organizations/foo'
+ end
+ end
+
+ context "when chef_server_root is http://a.b.com:9000/supercool/ and organization is foo" do
+ before do
+ Chef::Config.chef_server_root = 'http://a.b.com:9000/supercool/'
+ Chef::Config.organization = 'foo'
+ end
+
+ it "sets chef_server_url to http://a.b.com:9000/supercool/organizations/foo" do
+ Chef::Config.chef_server_url.should == 'http://a.b.com:9000/supercool/organizations/foo'
+ end
+ end
+
+ context "when chef_server_root is http://a.b.com:9000 and organization is not set" do
+ before do
+ Chef::Config.chef_server_root = 'http://a.b.com:9000'
+ end
+
+ it "sets chef_server_url and organization to nil" do
+ Chef::Config.chef_server_url.should == nil
+ Chef::Config.organization.should == nil
+ end
+ end
end
describe "when configuring formatters" do