summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Running <jr@getchef.com>2016-01-28 16:56:30 -0600
committerJordan Running <jr@getchef.com>2016-02-10 17:06:57 -0600
commitc8b79e62f628bd7dccc63b04313e044b13600841 (patch)
tree17df8584ca268a0e75e7f9e52f5244a3b343cf6c
parent96a82ea1050e1dd360035b760c19faca5678251c (diff)
downloadchef-zero-c8b79e62f628bd7dccc63b04313e044b13600841.tar.gz
Make client keys Pedant specs pass
- Implement client keys in: - ActorKeysEndpoint#get, #post - ActorKeyEndpoint#get - ActorsEndpoint#get, #post - ActorEndpoint#delete, #put, #populate_defaults - OrganizationsEndpoint - #post - Extract validator client creation into method. - Store the public key generated for the validator client in the client_keys store. - OrganizationEndpoint - #delete: Delete the validator client and client keys. - OrganizationUserEndpoint - #get, #delete: Don't retrieve default user public key (now handled by `DataNormalizer.normalize_user`; see below). - SearchEndpoint - Simplify `#search_container`. - RestBase - Fix RestErrorResponse exceptions to report actual `rest_path` instead associated with the failed data store operation instead of `request.rest_path`. - DataNormalizer - Fetch client and user default public_key in `DataNormalizer.normalize_{client,user}` instead of doing this in multiple other places. Requires passing `data_store` as argument. - RestRouter - Clean up logging - Print request methods, paths and bodies more readably for log_level >= INFO. - Pretty-print RestRequest objects (only printed when log_level == DEBUG). - Server - Change default log_level to WARN (to enable logging cleanup above). - Rakefile, spec/run_oc_pedant.rb - Consume RSpec, Pedant options from `ENV['RSPEC_OPTS']`, `ENV['PEDANT_OPTS']` (see `rake -D`). - Consume `ENV['LOG_LEVEL'` (see `rake -D`). - Clean up ChefZero::Server default opts and move duplicated logic to `start_chef_server` method.
-rw-r--r--Rakefile36
-rw-r--r--lib/chef_zero/chef_data/data_normalizer.rb25
-rw-r--r--lib/chef_zero/endpoints/actor_endpoint.rb116
-rw-r--r--lib/chef_zero/endpoints/actor_key_endpoint.rb15
-rw-r--r--lib/chef_zero/endpoints/actor_keys_endpoint.rb44
-rw-r--r--lib/chef_zero/endpoints/actors_endpoint.rb30
-rw-r--r--lib/chef_zero/endpoints/authenticate_user_endpoint.rb2
-rw-r--r--lib/chef_zero/endpoints/organization_endpoint.rb27
-rw-r--r--lib/chef_zero/endpoints/organization_user_endpoint.rb48
-rw-r--r--lib/chef_zero/endpoints/organizations_endpoint.rb55
-rw-r--r--lib/chef_zero/endpoints/search_endpoint.rb39
-rw-r--r--lib/chef_zero/endpoints/system_recovery_endpoint.rb2
-rw-r--r--lib/chef_zero/rest_base.rb14
-rw-r--r--lib/chef_zero/rest_router.rb61
-rw-r--r--lib/chef_zero/server.rb2
-rw-r--r--spec/run_oc_pedant.rb104
16 files changed, 407 insertions, 213 deletions
diff --git a/Rakefile b/Rakefile
index d8a0282..bbb984c 100644
--- a/Rakefile
+++ b/Rakefile
@@ -3,33 +3,43 @@ require 'bundler/gem_tasks'
require 'chef_zero/version'
+def run_oc_pedant(env={})
+ ENV.update(env)
+ require File.expand_path('spec/run_oc_pedant')
+end
+
+ENV_DOCS = <<END
+Environment:
+ - RSPEC_OPTS Options to pass to RSpec
+ e.g. RSPEC_OPTS="--fail-fast --profile 5"
+ - PEDANT_OPTS Options to pass to oc-chef-pedant
+ e.g. PEDANT_OPTS="--focus-keys --skip-users"
+ - LOG_LEVEL Set the log level (default: warn)
+ e.g. LOG_LEVEL=debug
+END
+
task :default => :pedant
-desc "run specs"
+desc "Run specs"
task :spec do
system('rspec spec/*_spec.rb')
end
-desc "run oc pedant"
-task :pedant do
- require File.expand_path('spec/run_oc_pedant')
-end
+desc "Run oc-chef-pedant\n\n#{ENV_DOCS}"
+task :pedant => :oc_pedant
-desc "run pedant with CHEF_FS set"
+desc "Run oc-chef-pedant with CHEF_FS set\n\n#{ENV_DOCS}"
task :cheffs do
- ENV['CHEF_FS'] = "yes"
- require File.expand_path('spec/run_oc_pedant')
+ run_oc_pedant('CHEF_FS' => 'yes')
end
-desc "run pedant with FILE_STORE set"
+desc "Run oc-chef-pedant with FILE_STORE set\n\n#{ENV_DOCS}"
task :filestore do
- ENV['FILE_STORE'] = "yes"
- require File.expand_path('spec/run_oc_pedant')
+ run_oc_pedant('FILE_STORE' => 'yes')
end
-desc "run oc pedant"
task :oc_pedant do
- require File.expand_path('spec/run_oc_pedant')
+ run_oc_pedant
end
task :chef_spec do
diff --git a/lib/chef_zero/chef_data/data_normalizer.rb b/lib/chef_zero/chef_data/data_normalizer.rb
index 554bd70..3ab20fa 100644
--- a/lib/chef_zero/chef_data/data_normalizer.rb
+++ b/lib/chef_zero/chef_data/data_normalizer.rb
@@ -5,6 +5,8 @@ require 'chef_zero/chef_data/default_creator'
module ChefZero
module ChefData
class DataNormalizer
+ DEFAULT_PUBLIC_KEY_NAME = "default"
+
def self.normalize_acls(acls)
ChefData::DefaultCreator::PERMISSIONS.each do |perm|
acls[perm] ||= {}
@@ -14,11 +16,14 @@ module ChefZero
acls
end
- def self.normalize_client(client, name, orgname = nil)
+ def self.normalize_client(data_store, client, name, orgname = nil)
+ unless client['public_key']
+ client['public_key'] = get_default_public_key(data_store, :client, name)
+ end
+
client['name'] ||= name
client['clientname'] ||= name
client['admin'] = !!client['admin'] if client.has_key?('admin')
- client['public_key'] ||= PUBLIC_KEY
client['orgname'] ||= orgname
client['validator'] ||= false
client['validator'] = !!client['validator']
@@ -34,7 +39,11 @@ module ChefZero
container
end
- def self.normalize_user(user, name, identity_keys, osc_compat, method=nil)
+ def self.normalize_user(data_store, user, name, identity_keys, osc_compat, method=nil)
+ unless user['public_key']
+ user['public_key'] = get_default_public_key(data_store, :user, name)
+ end
+
user[identity_keys.first] ||= name
user['admin'] ||= false
user['admin'] = !!user['admin']
@@ -221,6 +230,16 @@ module ChefZero
end
}.uniq
end
+
+ private
+
+ def self.get_default_public_key(data_store, user_or_client, user_or_client_name)
+ key_json = data_store.get([ "#{user_or_client}_keys", user_or_client_name, "keys", DEFAULT_PUBLIC_KEY_NAME ])
+ return unless key_json
+
+ FFI_Yajl::Parser.parse(key_json, create_additions: false)["public_key"]
+ rescue DataStore::DataNotFoundError
+ end
end
end
end
diff --git a/lib/chef_zero/endpoints/actor_endpoint.rb b/lib/chef_zero/endpoints/actor_endpoint.rb
index a491965..46b9082 100644
--- a/lib/chef_zero/endpoints/actor_endpoint.rb
+++ b/lib/chef_zero/endpoints/actor_endpoint.rb
@@ -13,22 +13,18 @@ module ChefZero
def delete(request)
result = super
- username = request.rest_path[1]
+ client_or_user_name = request.rest_path.last
if request.rest_path[0] == 'users'
list_data(request, [ 'organizations' ]).each do |org|
begin
- delete_data(request, [ 'organizations', org, 'users', username ], :data_store_exceptions)
+ delete_data(request, [ 'organizations', org, 'users', client_or_user_name ], :data_store_exceptions)
rescue DataStore::DataNotFoundError
end
end
-
- begin
- path = [ 'user_keys', username ]
- delete_data_dir(request, path, :data_store_exceptions)
- rescue DataStore::DataNotFoundError
- end
end
+
+ delete_actor_keys!(request, client_or_user_name)
result
end
@@ -65,32 +61,29 @@ module ChefZero
# Inject private_key into response, delete public_key/password if applicable
if result[0] == 200 || result[0] == 201
- username = identity_key_value(request) || request.rest_path[-1]
+ client_or_user_name = identity_key_value(request) || request.rest_path[-1]
- # TODO Implement for clients
- if request.rest_path[2] != 'clients' && is_rename?(request)
- rename_user_keys!(request, username)
+ if is_rename?(request)
+ rename_keys!(request, client_or_user_name)
end
if request.rest_path[0] == 'users'
response = {
- 'uri' => build_uri(request.base_uri, [ 'users', username ])
+ 'uri' => build_uri(request.base_uri, [ 'users', client_or_user_name ])
}
else
response = FFI_Yajl::Parser.parse(result[2], :create_additions => false)
end
- if request.rest_path[2] == 'clients'
+ if updating_public_key
+ update_default_public_key!(request, client_or_user_name, public_key)
+ response['public_key'] = public_key
+ end
+
+ if client?(request)
response['private_key'] = private_key ? private_key : false
else
response['private_key'] = private_key if private_key
-
- if updating_public_key
- update_user_default_key!(request, public_key)
- end
- end
-
- if request.rest_path[2] == 'users' && !updating_public_key
response.delete('public_key')
end
@@ -107,61 +100,66 @@ module ChefZero
def populate_defaults(request, response_json)
response = FFI_Yajl::Parser.parse(response_json, :create_additions => false)
- response =
- if request.rest_path[2] == 'clients'
- ChefData::DataNormalizer.normalize_client(response, request.rest_path[3], request.rest_path[1])
+ client_or_user_name =
+ if client?(request)
+ response["name"]
else
- public_key = get_user_default_public_key(request, response['username'])
-
- if public_key
- response['public_key'] = public_key
- end
+ response["username"]
+ end || request.rest_path.last
- ChefData::DataNormalizer.normalize_user(response, request.rest_path[3], identity_keys, server.options[:osc_compat], request.method)
+ response =
+ if client?(request)
+ ChefData::DataNormalizer.normalize_client(
+ data_store,
+ response,
+ client_or_user_name,
+ request.rest_path[1]
+ )
+ else
+ ChefData::DataNormalizer.normalize_user(
+ data_store,
+ response,
+ client_or_user_name,
+ identity_keys,
+ server.options[:osc_compat],
+ request.method
+ )
end
FFI_Yajl::Encoder.encode(response, :pretty => true)
end
- # Returns the user's default public_key from user_keys store
- def get_user_default_public_key(request, username)
- path = [ "user_keys", username, "keys", DEFAULT_PUBLIC_KEY_NAME ]
- key_json = get_data(request, path, :nil)
- return unless key_json
-
- key_data = FFI_Yajl::Parser.parse(key_json, create_additions: false)
- key_data && key_data["public_key"]
- end
-
# Move key data to new path
- def rename_user_keys!(request, new_username)
- orig_username = request.rest_path[-1]
- orig_user_keys_path = [ 'user_keys', orig_username, 'keys' ]
- new_user_keys_path = [ 'user_keys', new_username, 'keys' ]
+ def rename_keys!(request, new_client_or_user_name)
+ orig_client_or_user_name = request.rest_path.last
+
+ path_root = "#{client_or_user(request)}_keys"
+ orig_keys_path = [ path_root, orig_client_or_user_name, "keys" ]
+ new_keys_path = [ path_root, new_client_or_user_name, "keys" ]
- user_key_names = list_data(request, orig_user_keys_path, :data_store_exceptions)
+ key_names = list_data(request, orig_keys_path, :data_store_exceptions)
- user_key_names.each do |key_name|
+ key_names.each do |key_name|
# Get old data
- orig_path = orig_user_keys_path + [ key_name ]
+ orig_path = orig_keys_path + [ key_name ]
data = get_data(request, orig_path, :data_store_exceptions)
# Copy data to new path
create_data(
request,
- new_user_keys_path, key_name,
+ new_keys_path, key_name,
data,
:create_dir
)
end
# Delete original data
- delete_data_dir(request, orig_user_keys_path, :data_store_exceptions)
+ delete_data_dir(request, orig_keys_path, :recursive, :data_store_exceptions)
end
- def update_user_default_key!(request, public_key)
- username = request.rest_path[1]
- path = [ "user_keys", username, "keys", DEFAULT_PUBLIC_KEY_NAME ]
+ def update_default_public_key!(request, client_or_user_name, public_key)
+ path = [ "#{client_or_user(request)}_keys", client_or_user_name,
+ "keys", DEFAULT_PUBLIC_KEY_NAME ]
data = FFI_Yajl::Encoder.encode(
"name" => DEFAULT_PUBLIC_KEY_NAME,
@@ -171,6 +169,20 @@ module ChefZero
set_data(request, path, data, :create, :data_store_exceptions)
end
+
+ def delete_actor_keys!(request, client_or_user_name)
+ path = [ "#{client_or_user(request)}_keys", client_or_user_name ]
+ delete_data_dir(request, path, :recursive, :data_store_exceptions)
+ rescue DataStore::DataNotFoundError
+ end
+
+ def client_or_user(request)
+ request.rest_path[2] == "clients" ? :client : :user
+ end
+
+ def client?(request)
+ client_or_user(request) == :client
+ end
end
end
end
diff --git a/lib/chef_zero/endpoints/actor_key_endpoint.rb b/lib/chef_zero/endpoints/actor_key_endpoint.rb
index 4cfd4b2..98229fc 100644
--- a/lib/chef_zero/endpoints/actor_key_endpoint.rb
+++ b/lib/chef_zero/endpoints/actor_key_endpoint.rb
@@ -7,12 +7,12 @@ module ChefZero
# /organizations/ORG/clients/CLIENT/keys/NAME
class ActorKeyEndpoint < RestBase
def get(request)
- path = [ "user_keys", *request.rest_path[1..-1] ]
+ path = data_path(request)
already_json_response(200, get_data(request, path))
end
def delete(request)
- path = [ "user_keys", *request.rest_path[1..-1] ]
+ path = data_path(request)
data = get_data(request, path)
delete_data(request, path)
@@ -21,13 +21,18 @@ module ChefZero
end
def put(request)
- path = [ "user_keys", *request.rest_path[1..-1] ]
-
# We grab the old data to trigger a 404 if it doesn't exist
- get_data(request, path)
+ get_data(request, data_path(request))
set_data(request, path, request.body)
end
+
+ private
+
+ def data_path(request)
+ root = request.rest_path[2] == "clients" ? "client_keys" : "user_keys"
+ [root, *request.rest_path.last(3) ]
+ end
end
end
end
diff --git a/lib/chef_zero/endpoints/actor_keys_endpoint.rb b/lib/chef_zero/endpoints/actor_keys_endpoint.rb
index 405a927..ed3f828 100644
--- a/lib/chef_zero/endpoints/actor_keys_endpoint.rb
+++ b/lib/chef_zero/endpoints/actor_keys_endpoint.rb
@@ -9,8 +9,12 @@ module ChefZero
DATE_FORMAT = "%FT%TZ" # e.g. 2015-12-24T21:00:00Z
def get(request)
- username = request.rest_path[1]
- path = [ "user_keys", username, "keys" ]
+ path =
+ if client?(request)
+ [ "client_keys", request.rest_path[3], "keys" ]
+ else
+ [ "user_keys", request.rest_path[1], "keys" ]
+ end
result = list_data(request, path).map do |key_name|
list_key(request, [ *path, key_name ])
@@ -20,10 +24,10 @@ module ChefZero
end
def post(request)
- username = request.rest_path[1]
+ client_or_user_name = client?(request) ? request.rest_path[3] : request.rest_path[1]
request_body = FFI_Yajl::Parser.parse(request.body)
- validate_user!(request)
+ validate_client_or_user!(request)
generate_keys = request_body["public_key"].nil?
@@ -34,7 +38,7 @@ module ChefZero
end
key_name = request_body["name"]
- path = [ "user_keys", username, "keys" ]
+ path = [ "#{client_or_user(request)}_keys", client_or_user_name, "keys" ]
data = FFI_Yajl::Encoder.encode(
"name" => key_name,
@@ -44,10 +48,7 @@ module ChefZero
create_data(request, path, key_name, data, :create_dir)
- response_body = {
- "uri" => build_uri(request.base_uri,
- [ "users", username, "keys", key_name ])
- }
+ response_body = { "uri" => key_uri(request, key_name) }
response_body["private_key"] = private_key if generate_keys
json_response(201, response_body,
@@ -58,7 +59,7 @@ module ChefZero
def list_key(request, data_path)
data = FFI_Yajl::Parser.parse(get_data(request, data_path), create_additions: false)
- uri = build_uri(request.base_uri, [ "users", *data_path[1..-1] ])
+ key_name = data["name"]
expiration_date = if data["expiration_date"] == "infinity"
Float::INFINITY
@@ -66,14 +67,27 @@ module ChefZero
DateTime.strptime(data["expiration_date"], DATE_FORMAT)
end
- { "name" => data_path[-1],
- "uri" => uri,
+ { "name" => key_name,
+ "uri" => key_uri(request, key_name),
"expired" => DateTime.now > expiration_date }
end
- def validate_user!(request)
- # Try loading the user so a 404 is returned if the user doesn't
- get_data(request, request.rest_path[0, 2])
+ def validate_client_or_user!(request)
+ # Try loading the client or user so a 404 is returned if it doesn't exist
+ path = client?(request) ? request.rest_path[0..3] : request.rest_path[0..1]
+ get_data(request, path)
+ end
+
+ def client_or_user(request)
+ request.rest_path[2] == "clients" ? :client : :user
+ end
+
+ def client?(request)
+ client_or_user(request) == :client
+ end
+
+ def key_uri(request, key_name)
+ build_uri(request.base_uri, [ *request.rest_path, key_name ])
end
end
end
diff --git a/lib/chef_zero/endpoints/actors_endpoint.rb b/lib/chef_zero/endpoints/actors_endpoint.rb
index df6111c..f8d65cb 100644
--- a/lib/chef_zero/endpoints/actors_endpoint.rb
+++ b/lib/chef_zero/endpoints/actors_endpoint.rb
@@ -8,6 +8,7 @@ module ChefZero
DEFAULT_PUBLIC_KEY_NAME = "default"
def get(request)
+ # TODO Refactor this
response = super(request)
if request.query_params['email']
@@ -23,13 +24,13 @@ module ChefZero
response[2] = FFI_Yajl::Encoder.encode(new_results, :pretty => true)
end
- if request.query_params['verbose']
+ if request.query_params['verbose'] && !client?(request)
results = FFI_Yajl::Parser.parse(response[2], :create_additions => false)
results.each do |name, url|
record = get_data(request, request.rest_path + [ name ], :nil)
if record
record = FFI_Yajl::Parser.parse(record, :create_additions => false)
- record = ChefData::DataNormalizer.normalize_user(record, name, identity_keys, server.options[:osc_compat])
+ record = ChefData::DataNormalizer.normalize_user(data_store, record, name, identity_keys, server.options[:osc_compat])
results[name] = record
end
end
@@ -40,7 +41,7 @@ module ChefZero
def post(request)
request_body = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
- username = request_body['username']
+ client_or_user_name = request_body[ client?(request) ? "name" : "username" ]
public_key = request_body["public_key"]
@@ -49,18 +50,14 @@ module ChefZero
private_key, public_key = server.gen_key_pair
end
- if request.rest_path[2] == "clients"
- request_body['public_key'] = public_key
- else
- request_body.delete('public_key')
- end
+ request_body.delete('public_key')
request.body = FFI_Yajl::Encoder.encode(request_body, :pretty => true)
result = super(request)
if result[0] == 201
# Store the received or generated public key
- create_user_default_key!(request, username, public_key)
+ store_default_public_key!(request, client_or_user_name, public_key)
# If we generated a key, stuff it in the response.
response = FFI_Yajl::Parser.parse(result[2], :create_additions => false)
@@ -75,11 +72,8 @@ module ChefZero
private
# Store the public key in user_keys
- def create_user_default_key!(request, username, public_key)
- # TODO Implement for clients
- return if request.rest_path[2] == "clients"
-
- path = [ "user_keys", username, "keys" ]
+ def store_default_public_key!(request, client_or_user_name, public_key)
+ path = [ "#{client_or_user(request)}_keys", client_or_user_name, "keys" ]
data = FFI_Yajl::Encoder.encode(
"name" => DEFAULT_PUBLIC_KEY_NAME,
@@ -89,6 +83,14 @@ module ChefZero
create_data(request, path, DEFAULT_PUBLIC_KEY_NAME, data, :create_dir)
end
+
+ def client_or_user(request)
+ request.rest_path[2] == "clients" ? :client : :user
+ end
+
+ def client?(request)
+ client_or_user(request) == :client
+ end
end
end
end
diff --git a/lib/chef_zero/endpoints/authenticate_user_endpoint.rb b/lib/chef_zero/endpoints/authenticate_user_endpoint.rb
index 5d5bb3b..469e997 100644
--- a/lib/chef_zero/endpoints/authenticate_user_endpoint.rb
+++ b/lib/chef_zero/endpoints/authenticate_user_endpoint.rb
@@ -15,7 +15,7 @@ module ChefZero
raise RestErrorResponse.new(401, "Bad username or password")
end
user = FFI_Yajl::Parser.parse(user, :create_additions => false)
- user = ChefData::DataNormalizer.normalize_user(user, name, [ 'username' ], server.options[:osc_compat])
+ user = ChefData::DataNormalizer.normalize_user(data_store, user, name, [ 'username' ], server.options[:osc_compat])
if user['password'] != password
raise RestErrorResponse.new(401, "Bad username or password")
end
diff --git a/lib/chef_zero/endpoints/organization_endpoint.rb b/lib/chef_zero/endpoints/organization_endpoint.rb
index a5512db..c600f88 100644
--- a/lib/chef_zero/endpoints/organization_endpoint.rb
+++ b/lib/chef_zero/endpoints/organization_endpoint.rb
@@ -33,6 +33,9 @@ module ChefZero
def delete(request)
org = get_data(request, request.rest_path + [ 'org' ])
delete_data_dir(request, request.rest_path, :recursive)
+
+ delete_validator_client!(request, request.rest_path[-1])
+
already_json_response(200, populate_defaults(request, org))
end
@@ -41,6 +44,30 @@ module ChefZero
org = ChefData::DataNormalizer.normalize_organization(org, request.rest_path[1])
FFI_Yajl::Encoder.encode(org, :pretty => true)
end
+
+ private
+
+ def validator_name(org_name)
+ "#{org_name}-validator"
+ end
+
+ def delete_validator_client!(request, org_name)
+ client_path = [ *request.rest_path, 'clients', validator_name(org_name) ]
+ client_data = get_data(request, client_path, :nil)
+
+ if client_data
+ delete_data(request, client_path, :data_store_exceptions)
+ end
+
+ delete_validator_client_keys!(request, org_name)
+ rescue DataStore::DataNotFoundError
+ end
+
+ def delete_validator_client_keys!(request, org_name)
+ keys_path = [ "client_keys", validator_name(org_name) ]
+ delete_data_dir(request, keys_path, :recursive, :data_store_exceptions)
+ rescue DataStore::DataNotFoundError
+ end
end
end
end
diff --git a/lib/chef_zero/endpoints/organization_user_endpoint.rb b/lib/chef_zero/endpoints/organization_user_endpoint.rb
index d0c5b3c..db1fb3d 100644
--- a/lib/chef_zero/endpoints/organization_user_endpoint.rb
+++ b/lib/chef_zero/endpoints/organization_user_endpoint.rb
@@ -5,39 +5,43 @@ module ChefZero
module Endpoints
# /organizations/ORG/users/NAME
class OrganizationUserEndpoint < RestBase
- DEFAULT_PUBLIC_KEY_NAME = "default"
-
def get(request)
username = request.rest_path[3]
get_data(request) # 404 if user is not in org
- user = get_data(request, [ 'users', username ])
- user = FFI_Yajl::Parser.parse(user, :create_additions => false)
-
- user["public_key"] = get_user_default_public_key(request, username)
-
- json_response(200, ChefData::DataNormalizer.normalize_user(user, username, ['username'], server.options[:osc_compat], request.method))
+ user_data = get_data(request, [ 'users', username ])
+ user = FFI_Yajl::Parser.parse(user_data, :create_additions => false)
+
+ json_response(200,
+ ChefData::DataNormalizer.normalize_user(
+ data_store,
+ user,
+ username,
+ ['username'],
+ server.options[:osc_compat],
+ request.method
+ )
+ )
end
def delete(request)
- user = get_data(request)
+ user_data = get_data(request)
delete_data(request)
- user = FFI_Yajl::Parser.parse(user, :create_additions => false)
- json_response(200, ChefData::DataNormalizer.normalize_user(user, request.rest_path[3], ['username'], server.options[:osc_compat]))
+
+ user = FFI_Yajl::Parser.parse(user_data, :create_additions => false)
+
+ json_response(200,
+ ChefData::DataNormalizer.normalize_user(
+ data_store,
+ user,
+ request.rest_path[3],
+ ['username'],
+ server.options[:osc_compat]
+ )
+ )
end
# Note: post to a named org user is not permitted, allow invalid method handling (405)
-
- private
- # Returns the user's default public_key from user_keys store
- def get_user_default_public_key(request, username)
- path = [ "user_keys", username, "keys", DEFAULT_PUBLIC_KEY_NAME ]
- key_json = get_data(request, path, :nil)
- return unless key_json
-
- key_data = FFI_Yajl::Parser.parse(key_json, create_additions: false)
- key_data && key_data["public_key"]
- end
end
end
end
diff --git a/lib/chef_zero/endpoints/organizations_endpoint.rb b/lib/chef_zero/endpoints/organizations_endpoint.rb
index 41bf03b..9464ae7 100644
--- a/lib/chef_zero/endpoints/organizations_endpoint.rb
+++ b/lib/chef_zero/endpoints/organizations_endpoint.rb
@@ -1,11 +1,14 @@
require 'ffi_yajl'
require 'chef_zero/rest_base'
+require 'chef_zero/chef_data/data_normalizer'
require 'uuidtools'
module ChefZero
module Endpoints
# /organizations
class OrganizationsEndpoint < RestBase
+ DEFAULT_PUBLIC_KEY_NAME = "default"
+
def get(request)
result = {}
data_store.list(request.rest_path).each do |name|
@@ -31,32 +34,60 @@ module ChefZero
"guid" => UUIDTools::UUID.random_create.to_s.gsub('-', ''),
"assigned_at" => Time.now.to_s
}.merge(contents)
+
org_path = request.rest_path + [ name ]
set_data(request, org_path + [ 'org' ], FFI_Yajl::Encoder.encode(org, :pretty => true))
if server.generate_real_keys?
- # Create the validator client
- validator_name = "#{name}-validator"
- validator_path = org_path + [ 'clients', validator_name ]
- private_key, public_key = server.gen_key_pair
- validator = FFI_Yajl::Encoder.encode({
- 'validator' => true,
- 'public_key' => public_key
- }, :pretty => true)
- set_data(request, validator_path, validator)
+ private_key = create_validator_client!(request, org_path)
end
-
json_response(201, {
- "uri" => "#{build_uri(request.base_uri, org_path)}",
+ "uri" => build_uri(request.base_uri, org_path),
"name" => name,
"org_type" => org["org_type"],
"full_name" => full_name,
- "clientname" => validator_name,
+ "clientname" => validator_name(name),
"private_key" => private_key
})
end
end
+
+ private
+
+ def validator_name(org_name)
+ "#{org_name}-validator"
+ end
+
+ def create_validator_client!(request, org_path)
+ name = validator_name(org_path.last)
+ validator_path = [ *org_path, 'clients', name ]
+
+ private_key, public_key = server.gen_key_pair
+
+ validator = FFI_Yajl::Encoder.encode({
+ 'validator' => true,
+ }, :pretty => true)
+
+ set_data(request, validator_path, validator)
+
+ store_default_public_key!(request, name, public_key)
+
+ private_key
+ end
+
+ # Store the validator client's public key in client_keys
+ def store_default_public_key!(request, client_name, public_key)
+ path = [ "client_keys", client_name, "keys" ]
+
+ data = FFI_Yajl::Encoder.encode(
+ "name" => DEFAULT_PUBLIC_KEY_NAME,
+ "public_key" => public_key,
+ "expiration_date" => "infinity"
+ )
+
+ create_data(request, path, DEFAULT_PUBLIC_KEY_NAME, data, :create_dir)
+ end
end
end
end
diff --git a/lib/chef_zero/endpoints/search_endpoint.rb b/lib/chef_zero/endpoints/search_endpoint.rb
index a9ad2bf..200a1ad 100644
--- a/lib/chef_zero/endpoints/search_endpoint.rb
+++ b/lib/chef_zero/endpoints/search_endpoint.rb
@@ -48,22 +48,21 @@ module ChefZero
private
def search_container(request, index, orgname)
- relative_parts, normalize_proc = case index
- when 'client'
- [ ['clients'], Proc.new { |client, name| ChefData::DataNormalizer.normalize_client(client, name, orgname) } ]
- when 'node'
- [ ['nodes'], Proc.new { |node, name| ChefData::DataNormalizer.normalize_node(node, name) } ]
- when 'environment'
- [ ['environments'], Proc.new { |environment, name| ChefData::DataNormalizer.normalize_environment(environment, name) } ]
- when 'role'
- [ ['roles'], Proc.new { |role, name| ChefData::DataNormalizer.normalize_role(role, name) } ]
- else
- [ ['data', index], Proc.new { |data_bag_item, id| ChefData::DataNormalizer.normalize_data_bag_item(data_bag_item, index, id, 'DELETE') } ]
- end
- [
- request.rest_path[0..1] + relative_parts,
- normalize_proc
- ]
+ *relative_parts, normalize_proc =
+ case index
+ when 'client'
+ [ 'clients', method(:normalize_client).to_proc.curry[orgname] ]
+ when 'node'
+ [ 'nodes', ChefData::DataNormalizer.method(:normalize_node) ]
+ when 'environment'
+ [ 'environments', ChefData::DataNormalizer.method(:normalize_environment) ]
+ when 'role'
+ [ 'roles', ChefData::DataNormalizer.method(:normalize_role) ]
+ else
+ [ 'data', index, method(:normalize_data_bag_item).to_proc.curry[index] ]
+ end
+
+ [ request.rest_path[0..1] + relative_parts, normalize_proc ]
end
def expand_for_indexing(value, index, id)
@@ -189,6 +188,14 @@ module ChefZero
dest
end # deep_merge!
+ def normalize_client(orgname, client, name)
+ ChefData::DataNormalizer.normalize_client(data_store, client, name, orgname)
+ end
+
+ def normalize_data_bag_item(index, data_bag_item, id)
+ ChefData::DataNormalizer
+ .normalize_data_bag_item(data_bag_item, index, id, 'DELETE')
+ end
end
end
end
diff --git a/lib/chef_zero/endpoints/system_recovery_endpoint.rb b/lib/chef_zero/endpoints/system_recovery_endpoint.rb
index be438f8..fa3589e 100644
--- a/lib/chef_zero/endpoints/system_recovery_endpoint.rb
+++ b/lib/chef_zero/endpoints/system_recovery_endpoint.rb
@@ -15,7 +15,7 @@ module ChefZero
end
user = FFI_Yajl::Parser.parse(user, :create_additions => false)
- user = ChefData::DataNormalizer.normalize_user(user, name, [ 'username' ], server.options[:osc_compat])
+ user = ChefData::DataNormalizer.normalize_user(data_store, user, name, [ 'username' ], server.options[:osc_compat])
if !user['recovery_authentication_enabled']
raise RestErrorResponse.new(403, "Only users with recovery_authentication_enabled=true may use /system_recovery to log in")
end
diff --git a/lib/chef_zero/rest_base.rb b/lib/chef_zero/rest_base.rb
index f276426..6a9bd2e 100644
--- a/lib/chef_zero/rest_base.rb
+++ b/lib/chef_zero/rest_base.rb
@@ -114,7 +114,7 @@ module ChefZero
if options.include?(:data_store_exceptions)
raise
else
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
end
end
@@ -133,7 +133,7 @@ module ChefZero
if options.include?(:data_store_exceptions)
raise
else
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
end
end
@@ -152,7 +152,7 @@ module ChefZero
if options.include?(:data_store_exceptions)
raise
else
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
end
end
end
@@ -165,13 +165,13 @@ module ChefZero
if options.include?(:data_store_exceptions)
raise
else
- raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
+ raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, rest_path)}")
end
rescue DataStore::DataAlreadyExistsError
if options.include?(:data_store_exceptions)
raise
else
- raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
+ raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, rest_path + [name])}")
end
end
end
@@ -184,13 +184,13 @@ module ChefZero
if options.include?(:data_store_exceptions)
raise
else
- raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
+ raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, rest_path)}")
end
rescue DataStore::DataAlreadyExistsError
if options.include?(:data_store_exceptions)
raise
else
- raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
+ raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, rest_path + [name])}")
end
end
end
diff --git a/lib/chef_zero/rest_router.rb b/lib/chef_zero/rest_router.rb
index f2770d3..889c810 100644
--- a/lib/chef_zero/rest_router.rb
+++ b/lib/chef_zero/rest_router.rb
@@ -1,3 +1,5 @@
+require 'pp'
+
module ChefZero
class RestRouter
def initialize(routes)
@@ -15,24 +17,18 @@ module ChefZero
attr_accessor :not_found
def call(request)
- begin
- ChefZero::Log.debug(request)
- ChefZero::Log.debug(request.body) if request.body
-
- clean_path = "/" + request.rest_path.join("/")
-
- response = find_endpoint(clean_path).call(request)
- ChefZero::Log.debug([
- "",
- "--- RESPONSE (#{response[0]}) ---",
- response[2],
- "--- END RESPONSE ---",
- ].join("\n"))
- return response
- rescue
- ChefZero::Log.error("#{$!.inspect}\n#{$!.backtrace.join("\n")}")
- [500, {"Content-Type" => "text/plain"}, "Exception raised! #{$!.inspect}\n#{$!.backtrace.join("\n")}"]
+ log_request(request)
+
+ clean_path = "/" + request.rest_path.join("/")
+
+ find_endpoint(clean_path).call(request).tap do |response|
+ log_response(response)
end
+ rescue => ex
+ exception = "#{ex.inspect}\n#{ex.backtrace.join("\n")}"
+
+ ChefZero::Log.error(exception)
+ [ 500, { "Content-Type" => "text/plain" }, "Exception raised! #{exception}" ]
end
private
@@ -41,5 +37,36 @@ module ChefZero
_, endpoint = routes.find { |route, endpoint| route.match(clean_path) }
endpoint || not_found
end
+
+ def log_request(request)
+ ChefZero::Log.info do
+ "#{request.method} /#{request.rest_path.join("/")}".tap do |msg|
+ next unless request.method =~ /^(POST|PUT)$/
+
+ if request.body.nil? || request.body.empty?
+ msg << " (no body)"
+ else
+ msg << [
+ "",
+ "--- #{request.method} BODY ---",
+ request.body.chomp,
+ "--- END #{request.method} BODY ---"
+ ].join("\n")
+ end
+ end
+ end
+
+ ChefZero::Log.debug { request.pretty_inspect }
+ end
+
+ def log_response(response)
+ ChefZero::Log.info {
+ [ "",
+ "--- RESPONSE (#{response[0]}) ---",
+ response[2].chomp,
+ "--- END RESPONSE ---",
+ ].join("\n")
+ }
+ end
end
end
diff --git a/lib/chef_zero/server.rb b/lib/chef_zero/server.rb
index 45d36c3..da277b6 100644
--- a/lib/chef_zero/server.rb
+++ b/lib/chef_zero/server.rb
@@ -109,7 +109,7 @@ module ChefZero
DEFAULT_OPTIONS = {
:host => '127.0.0.1',
:port => 8889,
- :log_level => :info,
+ :log_level => :warn,
:generate_real_keys => true,
:single_org => 'chef',
:ssl => false
diff --git a/spec/run_oc_pedant.rb b/spec/run_oc_pedant.rb
index 25672fb..e4e8475 100644
--- a/spec/run_oc_pedant.rb
+++ b/spec/run_oc_pedant.rb
@@ -5,6 +5,42 @@ require 'bundler/setup'
require 'chef_zero/server'
require 'rspec/core'
+# This file runs oc-chef-pedant specs and is invoked by `rake pedant`
+# and other Rake tasks. Run `rake -T` to list tasks.
+#
+# Options for oc-chef-pedant and rspec can be specified via
+# ENV['PEDANT_OPTS'] and ENV['RSPEC_OPTS'], respectively.
+#
+# The log level can be specified via ENV['LOG_LEVEL'].
+#
+# Example:
+#
+# $ PEDANT_OPTS="--focus-users --skip-keys" \
+# > RSPEC_OPTS="--fail-fast --profile 5" \
+# > LOG_LEVEL=debug \
+# > rake pedant
+#
+
+DEFAULT_SERVER_OPTIONS = {
+ port: 8889,
+ single_org: false,
+}.freeze
+
+DEFAULT_LOG_LEVEL = :warn
+
+def log_level
+ return ENV['LOG_LEVEL'].downcase.to_sym if ENV['LOG_LEVEL']
+ return :debug if ENV['DEBUG']
+ DEFAULT_LOG_LEVEL
+end
+
+def start_chef_server(opts={})
+ opts = DEFAULT_SERVER_OPTIONS.merge(opts)
+ opts[:log_level] = log_level
+
+ ChefZero::Server.new(opts).tap {|server| server.start_background }
+end
+
def start_cheffs_server(chef_repo_path)
require 'chef/version'
require 'chef/config'
@@ -34,37 +70,42 @@ def start_cheffs_server(chef_repo_path)
data_store.set(%w(organizations pedant-testorg groups admins), '{ "users": [ "pivotal" ] }')
data_store.set(%w(organizations pedant-testorg groups users), '{ "users": [ "pivotal" ] }')
- server = ChefZero::Server.new(
- port: 8889,
- data_store: data_store,
- single_org: false,
- #log_level: :debug
- )
- server.start_background
- server
+ start_chef_server(data_store: data_store)
+end
+
+def pedant_args_from_env
+ args_from_env('PEDANT_OPTS')
+end
+
+def rspec_args_from_env
+ args_from_env('RSPEC_OPTS')
end
-tmpdir = nil
+def args_from_env(key)
+ return [] unless ENV[key]
+ ENV[key].split
+end
begin
- if ENV['FILE_STORE']
- require 'tmpdir'
- require 'chef_zero/data_store/raw_file_store'
- tmpdir = Dir.mktmpdir
- data_store = ChefZero::DataStore::RawFileStore.new(tmpdir, true)
- data_store = ChefZero::DataStore::DefaultFacade.new(data_store, false, false)
- server = ChefZero::Server.new(:port => 8889, :single_org => false, :data_store => data_store)
- server.start_background
-
- elsif ENV['CHEF_FS']
- require 'tmpdir'
- tmpdir = Dir.mktmpdir
- server = start_cheffs_server(tmpdir)
+ tmpdir = nil
+ server =
+ if ENV['FILE_STORE']
+ require 'tmpdir'
+ require 'chef_zero/data_store/raw_file_store'
+ tmpdir = Dir.mktmpdir
+ data_store = ChefZero::DataStore::RawFileStore.new(tmpdir, true)
+ data_store = ChefZero::DataStore::DefaultFacade.new(data_store, false, false)
+
+ start_chef_server(data_store: data_store)
+
+ elsif ENV['CHEF_FS']
+ require 'tmpdir'
+ tmpdir = Dir.mktmpdir
+ start_cheffs_server(tmpdir)
- else
- server = ChefZero::Server.new(:port => 8889, :single_org => false)#, :log_level => :debug)
- server.start_background
- end
+ else
+ start_chef_server
+ end
require 'rspec/core'
require 'pedant'
@@ -104,7 +145,6 @@ begin
# are turned off" - @jkeiser
#
# ...but we're not there yet
- '--skip-client-keys',
'--skip-controls',
'--skip-acl',
@@ -145,14 +185,10 @@ begin
default_skips + chef_fs_skips + %w{ --skip-knife }
end
- pedant_args << "--focus-client-keys"
-
- Pedant.setup(pedant_args)
-
- # fail_fast = []
- fail_fast = ["--fail-fast"]
+ Pedant.setup(pedant_args + pedant_args_from_env)
- result = RSpec::Core::Runner.run(Pedant.config.rspec_args + fail_fast)
+ rspec_args = Pedant.config.rspec_args + rspec_args_from_env
+ result = RSpec::Core::Runner.run(rspec_args)
server.stop if server.running?
ensure