summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <jkeiser@opscode.com>2014-04-21 07:36:46 -0700
committerJohn Keiser <jkeiser@opscode.com>2014-04-21 07:36:46 -0700
commite908aa35f5b62f646557a9b932189e184fc093e1 (patch)
treef9f75e440b3c4405da10bffdfcc1d263cb204677
parent09de5c7174277e1d0f1b67dce4cff74daa2cbb1f (diff)
downloadchef-zero-e908aa35f5b62f646557a9b932189e184fc093e1.tar.gz
Support ChefFSDataStore from prior versions
-rw-r--r--lib/chef_zero/data_store/interface_v1.rb49
-rw-r--r--lib/chef_zero/data_store/interface_v2.rb18
-rw-r--r--lib/chef_zero/data_store/memory_store.rb8
-rw-r--r--lib/chef_zero/data_store/v1_to_v2_adapter.rb117
-rw-r--r--lib/chef_zero/server.rb16
-rw-r--r--spec/run.rb106
6 files changed, 284 insertions, 30 deletions
diff --git a/lib/chef_zero/data_store/interface_v1.rb b/lib/chef_zero/data_store/interface_v1.rb
new file mode 100644
index 0000000..7568fdc
--- /dev/null
+++ b/lib/chef_zero/data_store/interface_v1.rb
@@ -0,0 +1,49 @@
+module ChefZero
+ module DataStore
+ class InterfaceV1
+ def interface_version
+ 1
+ end
+
+ def clear
+ raise "clear not implemented by class #{self.class}"
+ end
+
+ def create_dir(path, name, *options)
+ raise "create_dir not implemented by class #{self.class}"
+ end
+
+ def create(path, name, data, *options)
+ raise "create_dir not implemented by class #{self.class}"
+ end
+
+ def get(path, request=nil)
+ raise "create_dir not implemented by class #{self.class}"
+ end
+
+ def set(path, data, *options)
+ raise "create_dir not implemented by class #{self.class}"
+ end
+
+ def delete(path)
+ raise "create_dir not implemented by class #{self.class}"
+ end
+
+ def delete_dir(path, *options)
+ raise "create_dir not implemented by class #{self.class}"
+ end
+
+ def list(path)
+ raise "create_dir not implemented by class #{self.class}"
+ end
+
+ def exists?(path)
+ raise "create_dir not implemented by class #{self.class}"
+ end
+
+ def exists_dir?(path)
+ raise "create_dir not implemented by class #{self.class}"
+ end
+ end
+ end
+end
diff --git a/lib/chef_zero/data_store/interface_v2.rb b/lib/chef_zero/data_store/interface_v2.rb
new file mode 100644
index 0000000..fa1ba41
--- /dev/null
+++ b/lib/chef_zero/data_store/interface_v2.rb
@@ -0,0 +1,18 @@
+require 'chef_zero/data_store/interface_v1'
+
+module ChefZero
+ module DataStore
+ # V2 assumes paths starting with /organizations/ORGNAME. It also REQUIRES that
+ # new organizations have these defaults:
+ # chef-validator client: '{ "validator": true }',
+ # chef-webui client: '{ "admin": true }'
+ # _default environment: '{ "description": "The default Chef environment" }'
+ # admin user: '{ "admin": "true" }'
+
+ class InterfaceV2 < ChefZero::DataStore::InterfaceV1
+ def interface_version
+ 2
+ end
+ end
+ end
+end
diff --git a/lib/chef_zero/data_store/memory_store.rb b/lib/chef_zero/data_store/memory_store.rb
index c7e5b7f..aba052d 100644
--- a/lib/chef_zero/data_store/memory_store.rb
+++ b/lib/chef_zero/data_store/memory_store.rb
@@ -18,14 +18,19 @@
require 'chef_zero/data_store/data_already_exists_error'
require 'chef_zero/data_store/data_not_found_error'
+require 'chef_zero/data_store/interface_v2'
module ChefZero
module DataStore
- class MemoryStore
+ class MemoryStore < ChefZero::DataStore::InterfaceV2
def initialize
clear
end
+ def interface_version
+ 2
+ end
+
def clear
@data = {}
@@ -33,7 +38,6 @@ module ChefZero
end
def create_org
- # Create containers
org = {
'clients' => {
'chef-validator' => '{ "validator": true }',
diff --git a/lib/chef_zero/data_store/v1_to_v2_adapter.rb b/lib/chef_zero/data_store/v1_to_v2_adapter.rb
new file mode 100644
index 0000000..aaa3b64
--- /dev/null
+++ b/lib/chef_zero/data_store/v1_to_v2_adapter.rb
@@ -0,0 +1,117 @@
+require 'chef_zero/data_store/interface_v2'
+
+module ChefZero
+ module DataStore
+ class V1ToV2Adapter < ChefZero::DataStore::InterfaceV2
+ def initialize(real_store, single_org)
+ @real_store = real_store
+ @single_org = single_org
+ # Handle defaults per V2 specification
+ @defaults = {
+ 'clients' => {
+ 'chef-validator' => '{ "validator": true }',
+ 'chef-webui' => '{ "admin": true }'
+ },
+ 'environments' => {
+ '_default' => '{ "description": "The default Chef environment" }'
+ },
+ 'users' => {
+ 'admin' => '{ "admin": "true" }'
+ }
+ }
+ end
+
+ attr_reader :real_store
+ attr_reader :single_org
+
+ def clear
+ real_store.clear
+ end
+
+ def create_dir(path, name, *options)
+ return nil if skip_organizations(path, name)
+ real_store.create_dir(path[2..-1], name, *options)
+ end
+
+ def create(path, name, data, *options)
+ return nil if skip_organizations(path, name)
+ remove_default(path, name)
+ real_store.create(path[2..-1], name, data, *options)
+ end
+
+ def get(path, request=nil)
+ return nil if skip_organizations(path)
+ begin
+ real_store.get(path[2..-1], request)
+ rescue DataNotFoundError
+ if path.size == 2 && @defaults[path[0]] && @defaults[path[0]][path[1]]
+ @defaults[path[0]][path[1]]
+ else
+ raise
+ end
+ end
+ end
+
+ def set(path, data, *options)
+ return nil if skip_organizations(path)
+ remove_default(path, name)
+ real_store.set(path[2..-1], data, *options)
+ end
+
+ def delete(path)
+ return nil if skip_organizations(path)
+ remove_default(path)
+ real_store.delete(path[2..-1])
+ end
+
+ def delete_dir(path, *options)
+ return nil if skip_organizations(path)
+ real_store.delete_dir(path[2..-1], *options)
+ end
+
+ def list(path)
+ return nil if skip_organizations(path)
+ real_store.list(path[2..-1])
+ end
+
+ def exists?(path)
+ return nil if skip_organizations(path)
+ if path.size == 2 && @defaults[path[0]] && @defaults[path[0]][path[1]]
+ @defaults[path[0]][path[1]]
+ else
+ real_store.exists?(path[2..-1])
+ end
+ end
+
+ def exists_dir?(path)
+ return nil if skip_organizations(path)
+ real_store.exists_dir?(path[2..-1])
+ end
+
+ private
+
+ def remove_default(path, name = nil)
+ path = path + [name] if name
+ if path.size == 2 && @defaults[path[0]] && @defaults[path[0]][path[1]]
+ @defaults[path[0]].delete(path[1])
+ end
+ end
+
+ def skip_organizations(path, name = nil)
+ if path == []
+ raise "" if name == nil || name != 'organizations'
+ true
+ elsif path == ['organizations']
+ raise "" if name == nil || name != single_org
+ true
+ else
+ raise "Path #{path} must start with /organizations/#{single_org}" if path[0..1] != [ 'organizations', single_org ]
+ if !name
+ raise "Path #{path} must start with /organizations/#{single_org}/<something>" if path.size <= 2
+ end
+ false
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef_zero/server.rb b/lib/chef_zero/server.rb
index a5c0c0d..be628af 100644
--- a/lib/chef_zero/server.rb
+++ b/lib/chef_zero/server.rb
@@ -29,6 +29,7 @@ require 'chef_zero'
require 'chef_zero/cookbook_data'
require 'chef_zero/rest_router'
require 'chef_zero/data_store/memory_store'
+require 'chef_zero/data_store/v1_to_v2_adapter'
require 'chef_zero/version'
require 'chef_zero/endpoints/authenticate_user_endpoint'
@@ -103,14 +104,23 @@ module ChefZero
#
# The data store for this server (default is in-memory).
#
- # @return [~ChefZero::DataStore]
+ # @return [ChefZero::DataStore]
#
def data_store
@data_store ||= begin
result = @options[:data_store] || DataStore::MemoryStore.new
if options[:single_org]
- result.create_dir([ 'organizations' ], options[:single_org])
+ if result.respond_to?(:interface_version) && result.interface_version >= 2 && result.interface_version < 3
+ result.create_dir([ 'organizations' ], options[:single_org])
+ else
+ result = ChefZero::DataStore::V1ToV2Adapter.new(result, options[:single_org])
+ end
+ else
+ if !(result.respond_to?(:interface_version) && result.interface_version >= 2 && result.interface_version < 3)
+ raise "Multi-org not supported by data store #{result}!"
+ end
end
+
result
end
end
@@ -407,7 +417,7 @@ module ChefZero
def dejsonize_children(hash)
result = {}
hash.each_pair do |key, value|
- result[key] = value.is_a?(Hash) ? JSON.pretty_generate(value) : value
+ result[key] = value.is_a?(Hash) ? JSON.pretty_generate(value) : value
end
result
end
diff --git a/spec/run.rb b/spec/run.rb
index 01dffe9..d538c2f 100644
--- a/spec/run.rb
+++ b/spec/run.rb
@@ -5,33 +5,89 @@ require 'bundler/setup'
require 'chef_zero/server'
require 'rspec/core'
-server = ChefZero::Server.new(:port => 8889)
-server.start_background
-
-unless ENV['SKIP_PEDANT']
- require 'pedant'
- require 'pedant/opensource'
-
- Pedant.config.suite = 'api'
- Pedant.config[:config_file] = 'spec/support/pedant.rb'
- Pedant.setup([
- '--skip-validation',
- '--skip-authentication',
- '--skip-authorization',
- '--skip-omnibus'
- ])
-
- result = RSpec::Core::Runner.run(Pedant.config.rspec_args)
-else
- require 'net/http'
- response = Net::HTTP.new('127.0.0.1', 8889).get("/environments", { 'Accept' => 'application/json'}).body
- if response =~ /_default/
- result = 0
+tmpdir = nil
+
+def start_server(chef_repo_path)
+ # Create the chef repo
+ Dir.mkdir(chef_repo_path)
+ # 11.6 and below had a bug where it couldn't create the repo children automatically
+ if Chef::VERSION.to_f < 11.8
+ %w(clients cookbooks data_bags environments nodes roles users).each do |child|
+ Dir.mkdir("#{chef_repo_path}/#{child}")
+ end
+ end
+
+ # Start the new server
+ Chef::Config.repo_mode = 'everything'
+ Chef::Config.chef_repo_path = chef_repo_path
+ chef_fs = Chef::ChefFS::Config.new.local_fs
+ data_store = Chef::ChefFS::ChefFSDataStore.new(chef_fs)
+ server = ChefZero::Server.new(:port => 8889, :data_store => data_store)
+ server.start_background
+ server
+end
+
+begin
+ if ENV['CHEF_FS']
+ require 'chef/chef_fs/chef_fs_data_store'
+ require 'chef/chef_fs/config'
+ require 'tmpdir'
+ require 'fileutils'
+ require 'chef/version'
+
+ # Create chef repository
+ tmpdir = Dir.mktmpdir
+ chef_repo_path = "#{tmpdir}/repo"
+ server = start_server(chef_repo_path)
+
+ # Delete everything before each test
+ RSpec.configure do |config|
+ config.before(:each) do
+ # Stop the old server
+ if server
+ server.stop
+ server = nil
+ FileUtils.rm_rf(chef_repo_path)
+ end
+
+ server = start_server(chef_repo_path)
+ end
+ end
+
else
- puts "GET /environments returned #{response}. Expected _default!"
- result = 1
+ server = ChefZero::Server.new(:port => 8889)
+ server.start_background
end
+
+ unless ENV['SKIP_PEDANT']
+ require 'pedant'
+ require 'pedant/opensource'
+
+ Pedant.config.suite = 'api'
+ Pedant.config[:config_file] = 'spec/support/pedant.rb'
+ Pedant.setup([
+ '--skip-knife',
+ '--skip-validation',
+ '--skip-authentication',
+ '--skip-authorization',
+ '--skip-omnibus'
+ ])
+
+ result = RSpec::Core::Runner.run(Pedant.config.rspec_args)
+ else
+ require 'net/http'
+ response = Net::HTTP.new('127.0.0.1', 8889).get("/environments", { 'Accept' => 'application/json'}).body
+ if response =~ /_default/
+ result = 0
+ else
+ puts "GET /environments returned #{response}. Expected _default!"
+ result = 1
+ end
+ end
+
+ server.stop
+ensure
+ FileUtils.remove_entry_secure(tmpdir) if tmpdir
end
-server.stop
exit(result)