chef-zero 2.2.1 → 3.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/Rakefile +5 -1
  4. data/bin/chef-zero +17 -0
  5. data/lib/chef_zero/chef_data/acl_path.rb +139 -0
  6. data/lib/chef_zero/chef_data/cookbook_data.rb +240 -0
  7. data/lib/chef_zero/chef_data/data_normalizer.rb +207 -0
  8. data/lib/chef_zero/chef_data/default_creator.rb +446 -0
  9. data/lib/chef_zero/data_store/default_facade.rb +149 -0
  10. data/lib/chef_zero/data_store/interface_v1.rb +18 -0
  11. data/lib/chef_zero/data_store/memory_store.rb +2 -1
  12. data/lib/chef_zero/data_store/memory_store_v2.rb +3 -36
  13. data/lib/chef_zero/data_store/raw_file_store.rb +147 -0
  14. data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +39 -103
  15. data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +1 -1
  16. data/lib/chef_zero/endpoints/acl_endpoint.rb +38 -0
  17. data/lib/chef_zero/endpoints/acls_endpoint.rb +29 -0
  18. data/lib/chef_zero/endpoints/actor_endpoint.rb +36 -10
  19. data/lib/chef_zero/endpoints/actors_endpoint.rb +38 -6
  20. data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +15 -9
  21. data/lib/chef_zero/endpoints/container_endpoint.rb +22 -0
  22. data/lib/chef_zero/endpoints/containers_endpoint.rb +13 -0
  23. data/lib/chef_zero/endpoints/cookbook_endpoint.rb +1 -1
  24. data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +15 -14
  25. data/lib/chef_zero/endpoints/cookbooks_base.rb +2 -2
  26. data/lib/chef_zero/endpoints/data_bag_endpoint.rb +4 -4
  27. data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +5 -5
  28. data/lib/chef_zero/endpoints/data_bags_endpoint.rb +5 -4
  29. data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +2 -2
  30. data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +6 -6
  31. data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +2 -2
  32. data/lib/chef_zero/endpoints/environment_endpoint.rb +5 -5
  33. data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +2 -2
  34. data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +3 -3
  35. data/lib/chef_zero/endpoints/environment_role_endpoint.rb +2 -2
  36. data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +1 -1
  37. data/lib/chef_zero/endpoints/group_endpoint.rb +20 -0
  38. data/lib/chef_zero/endpoints/groups_endpoint.rb +13 -0
  39. data/lib/chef_zero/endpoints/license_endpoint.rb +25 -0
  40. data/lib/chef_zero/endpoints/node_endpoint.rb +5 -5
  41. data/lib/chef_zero/endpoints/not_found_endpoint.rb +2 -2
  42. data/lib/chef_zero/endpoints/organization_association_request_endpoint.rb +22 -0
  43. data/lib/chef_zero/endpoints/organization_association_requests_endpoint.rb +29 -0
  44. data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -0
  45. data/lib/chef_zero/endpoints/organization_endpoint.rb +41 -0
  46. data/lib/chef_zero/endpoints/organization_user_endpoint.rb +48 -0
  47. data/lib/chef_zero/endpoints/organization_users_endpoint.rb +14 -0
  48. data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -0
  49. data/lib/chef_zero/endpoints/organizations_endpoint.rb +55 -0
  50. data/lib/chef_zero/endpoints/principal_endpoint.rb +15 -3
  51. data/lib/chef_zero/endpoints/rest_list_endpoint.rb +8 -6
  52. data/lib/chef_zero/endpoints/rest_object_endpoint.rb +12 -10
  53. data/lib/chef_zero/endpoints/role_endpoint.rb +5 -5
  54. data/lib/chef_zero/endpoints/role_environments_endpoint.rb +2 -2
  55. data/lib/chef_zero/endpoints/sandbox_endpoint.rb +2 -2
  56. data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +4 -4
  57. data/lib/chef_zero/endpoints/search_endpoint.rb +10 -10
  58. data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -0
  59. data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +40 -0
  60. data/lib/chef_zero/endpoints/user_association_requests_count_endpoint.rb +19 -0
  61. data/lib/chef_zero/endpoints/user_association_requests_endpoint.rb +19 -0
  62. data/lib/chef_zero/endpoints/user_organizations_endpoint.rb +22 -0
  63. data/lib/chef_zero/rest_base.rb +79 -13
  64. data/lib/chef_zero/rest_error_response.rb +1 -1
  65. data/lib/chef_zero/rest_request.rb +4 -0
  66. data/lib/chef_zero/rest_router.rb +1 -0
  67. data/lib/chef_zero/rspec.rb +55 -8
  68. data/lib/chef_zero/server.rb +87 -21
  69. data/lib/chef_zero/version.rb +1 -1
  70. data/spec/run_oc_pedant.rb +53 -0
  71. data/spec/{run.rb → run_pedant.rb} +13 -4
  72. data/spec/server_spec.rb +54 -0
  73. data/spec/support/oc_pedant.rb +134 -0
  74. data/spec/support/pedant.rb +1 -1
  75. metadata +54 -13
  76. data/lib/chef_zero/cookbook_data.rb +0 -236
  77. data/lib/chef_zero/data_normalizer.rb +0 -146
@@ -0,0 +1,19 @@
1
+ require 'json'
2
+ require 'chef_zero/rest_base'
3
+
4
+ module ChefZero
5
+ module Endpoints
6
+ # /users/USER/association_requests
7
+ class UserAssociationRequestsEndpoint < RestBase
8
+ def get(request)
9
+ get_data(request, request.rest_path[0..-2])
10
+ username = request.rest_path[1]
11
+ result = list_data(request, [ 'organizations' ]).select do |org|
12
+ exists_data?(request, [ 'organizations', org, 'association_requests', username ])
13
+ end
14
+ result = result.map { |org| { "id" => "#{username}-#{org}", "orgname" => org } }
15
+ json_response(200, result)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ require 'json'
2
+ require 'chef_zero/rest_base'
3
+
4
+ module ChefZero
5
+ module Endpoints
6
+ # /users/USER/organizations
7
+ class UserOrganizationsEndpoint < RestBase
8
+ def get(request)
9
+ username = request.rest_path[1]
10
+ result = list_data(request, [ 'organizations' ]).select do |orgname|
11
+ exists_data?(request, [ 'organizations', orgname, 'users', username ])
12
+ end
13
+ result = result.map do |orgname|
14
+ org = get_data(request, [ 'organizations', orgname, 'org' ])
15
+ org = JSON.parse(org, :create_additions => false)
16
+ ChefData::DataNormalizer.normalize_organization(org, orgname)
17
+ end
18
+ json_response(200, result)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,6 +1,7 @@
1
1
  require 'chef_zero/rest_request'
2
2
  require 'chef_zero/rest_error_response'
3
3
  require 'chef_zero/data_store/data_not_found_error'
4
+ require 'chef_zero/chef_data/acl_path'
4
5
 
5
6
  module ChefZero
6
7
  class RestBase
@@ -21,7 +22,7 @@ module ChefZero
21
22
  accept_methods_str = accept_methods.map { |m| m.to_s.upcase }.join(', ')
22
23
  return [405, {"Content-Type" => "text/plain", "Allow" => accept_methods_str}, "Bad request method for '#{request.env['REQUEST_PATH']}': #{request.env['REQUEST_METHOD']}"]
23
24
  end
24
- if json_only && request.env['HTTP_ACCEPT'] && !request.env['HTTP_ACCEPT'].split(';').include?('application/json')
25
+ if json_only && !accepts?(request, 'application', 'json')
25
26
  return [406, {"Content-Type" => "text/plain"}, "Must accept application/json"]
26
27
  end
27
28
  # Dispatch to get()/post()/put()/delete()
@@ -37,6 +38,14 @@ module ChefZero
37
38
  true
38
39
  end
39
40
 
41
+ def accepts?(request, category, type)
42
+ # If HTTP_ACCEPT is not sent at all, assume it accepts anything
43
+ # This parses as per http://tools.ietf.org/html/rfc7231#section-5.3
44
+ return true if !request.env['HTTP_ACCEPT']
45
+ accepts = request.env['HTTP_ACCEPT'].split(/,\s*/).map { |x| x.split(';',2)[0].strip }
46
+ return accepts.include?("#{category}/#{type}") || accepts.include?("#{category}/*") || accepts.include?('*/*')
47
+ end
48
+
40
49
  def get_data(request, rest_path=nil, *options)
41
50
  rest_path ||= request.rest_path
42
51
  begin
@@ -44,27 +53,43 @@ module ChefZero
44
53
  rescue DataStore::DataNotFoundError
45
54
  if options.include?(:nil)
46
55
  nil
56
+ elsif options.include?(:data_store_exceptions)
57
+ raise
47
58
  else
48
59
  raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
49
60
  end
50
61
  end
51
62
  end
52
63
 
53
- def list_data(request, rest_path=nil)
64
+ def list_data(request, rest_path=nil, *options)
54
65
  rest_path ||= request.rest_path
55
66
  begin
56
67
  data_store.list(rest_path)
57
68
  rescue DataStore::DataNotFoundError
58
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
69
+ if options.include?(:data_store_exceptions)
70
+ raise
71
+ else
72
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, rest_path)}")
73
+ end
59
74
  end
60
75
  end
61
76
 
62
- def delete_data(request, rest_path=nil)
77
+ def delete_data(request, rest_path=nil, *options)
63
78
  rest_path ||= request.rest_path
64
79
  begin
65
- data_store.delete(rest_path)
80
+ data_store.delete(rest_path, *options)
81
+ rescue DataStore::DataNotFoundError
82
+ if options.include?(:data_store_exceptions)
83
+ raise
84
+ else
85
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
86
+ end
87
+ end
88
+
89
+ begin
90
+ acl_path = ChefData::AclPath.get_acl_data_path(rest_path)
91
+ data_store.delete(acl_path) if acl_path
66
92
  rescue DataStore::DataNotFoundError
67
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
68
93
  end
69
94
  end
70
95
 
@@ -73,27 +98,68 @@ module ChefZero
73
98
  begin
74
99
  data_store.delete_dir(rest_path, *options)
75
100
  rescue DataStore::DataNotFoundError
76
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
101
+ if options.include?(:data_store_exceptions)
102
+ raise
103
+ else
104
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
105
+ end
106
+ end
107
+
108
+ begin
109
+ acl_path = ChefData::AclPath.get_acl_data_path(rest_path)
110
+ data_store.delete(acl_path) if acl_path
111
+ rescue DataStore::DataNotFoundError
77
112
  end
78
113
  end
79
114
 
80
115
  def set_data(request, rest_path, data, *options)
81
116
  rest_path ||= request.rest_path
82
117
  begin
83
- data_store.set(rest_path, request.body, *options)
118
+ data_store.set(rest_path, data, *options, :requestor => request.requestor)
84
119
  rescue DataStore::DataNotFoundError
85
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
120
+ if options.include?(:data_store_exceptions)
121
+ raise
122
+ else
123
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
124
+ end
125
+ end
126
+ end
127
+
128
+ def create_data_dir(request, rest_path, name, *options)
129
+ rest_path ||= request.rest_path
130
+ begin
131
+ data_store.create_dir(rest_path, name, *options, :requestor => request.requestor)
132
+ rescue DataStore::DataNotFoundError
133
+ if options.include?(:data_store_exceptions)
134
+ raise
135
+ else
136
+ raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
137
+ end
138
+ rescue DataStore::DataAlreadyExistsError
139
+ if options.include?(:data_store_exceptions)
140
+ raise
141
+ else
142
+ raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
143
+ end
86
144
  end
87
145
  end
88
146
 
89
147
  def create_data(request, rest_path, name, data, *options)
90
148
  rest_path ||= request.rest_path
91
149
  begin
92
- data_store.create(rest_path, name, data, *options)
150
+ data_store.create(rest_path, name, data, *options, :requestor => request.requestor)
93
151
  rescue DataStore::DataNotFoundError
94
- raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
152
+ if options.include?(:data_store_exceptions)
153
+ raise
154
+ else
155
+ raise RestErrorResponse.new(404, "Parent not found: #{build_uri(request.base_uri, request.rest_path)}")
156
+ end
95
157
  rescue DataStore::DataAlreadyExistsError
96
- raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
158
+ if options.include?(:data_store_exceptions)
159
+ raise
160
+ else
161
+ raise RestErrorResponse.new(409, "Object already exists: #{build_uri(request.base_uri, request.rest_path + [name])}")
162
+ end
97
163
  end
98
164
  end
99
165
 
@@ -112,7 +178,7 @@ module ChefZero
112
178
  end
113
179
 
114
180
  def json_response(response_code, json)
115
- already_json_response(response_code, FFI_Yajl::Encoder.encode(json, :pretty => true))
181
+ already_json_response(response_code, JSON.pretty_generate(json))
116
182
  end
117
183
 
118
184
  def already_json_response(response_code, json_text)
@@ -1,5 +1,5 @@
1
1
  module ChefZero
2
- class RestErrorResponse < Exception
2
+ class RestErrorResponse < StandardError
3
3
  def initialize(response_code, error)
4
4
  @response_code = response_code
5
5
  @error = error
@@ -14,6 +14,10 @@ module ChefZero
14
14
  @base_uri ||= "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}#{env['SCRIPT_NAME']}"
15
15
  end
16
16
 
17
+ def requestor
18
+ @env['HTTP_X_OPS_USERID']
19
+ end
20
+
17
21
  def method
18
22
  @env['REQUEST_METHOD']
19
23
  end
@@ -17,6 +17,7 @@ module ChefZero
17
17
  def call(request)
18
18
  begin
19
19
  ChefZero::Log.debug(request)
20
+ ChefZero::Log.debug(request.body) if request.body
20
21
 
21
22
  clean_path = "/" + request.rest_path.join("/")
22
23
 
@@ -34,7 +34,7 @@ module ChefZero
34
34
  default_opts
35
35
  end
36
36
 
37
- if ChefZero::RSpec.server && server_opts.any? { |opt, value| ChefZero::RSpec.server.options[opt] != value }
37
+ if ChefZero::RSpec.server && server_opts != ChefZero::RSpec.server.options
38
38
  ChefZero::RSpec.server.stop
39
39
  ChefZero::RSpec.server = nil
40
40
  end
@@ -77,32 +77,79 @@ module ChefZero
77
77
  end
78
78
  end
79
79
 
80
+ def self.organization(name, org = '{}')
81
+ before(:each) do
82
+ ChefZero::RSpec.server.data_store.set([ 'organizations', name, 'org' ], dejsonize(org), :create_dir, :create)
83
+ @current_org = name
84
+ end
85
+ end
86
+
87
+ def self.acl(path, acl)
88
+ before(:each) do
89
+ path = [ 'organizations', @current_org || 'chef' ] + path.split('/')
90
+ ChefZero::RSpec.server.data_store.set(ChefData::AclPath.get_acl_data_path(path), acl)
91
+ end
92
+ end
93
+
94
+ def self.group(name, group)
95
+ before(:each) do
96
+ path = [ 'organizations', @current_org || 'chef' ] + path.split('/')
97
+ ChefZero::RSpec.server.data_store.set([ 'organizations', @current_org || 'chef', 'groups', name ], dejsonize(group), :create)
98
+ end
99
+ end
100
+
101
+ def self.org_invite(username)
102
+ before(:each) do
103
+ ChefZero::RSpec.server.data_store.set([ 'organizations', @current_org || 'chef', 'users', username ], '{}', :create)
104
+ end
105
+ end
106
+
107
+ def self.org_members(name, *members)
108
+ before(:each) do
109
+ members.each do |member|
110
+ ChefZero::RSpec.server.set([ 'organizations', @current_org || 'chef', 'users', member], '{}')
111
+ end
112
+ end
113
+ end
114
+
80
115
  def self.client(name, client)
81
- before(:each) { ChefZero::RSpec.server.load_data({ 'clients' => { name => client }}) }
116
+ before(:each) { ChefZero::RSpec.server.load_data({ 'clients' => { name => client }}, @current_org) }
82
117
  end
83
118
 
84
119
  def self.cookbook(name, version, cookbook, options = {})
85
- before(:each) { ChefZero::RSpec.server.load_data({ 'cookbooks' => { "#{name}-#{version}" => cookbook.merge(options) }}) }
120
+ before(:each) { ChefZero::RSpec.server.load_data({ 'cookbooks' => { "#{name}-#{version}" => cookbook.merge(options) }}, @current_org) }
86
121
  end
87
122
 
88
123
  def self.data_bag(name, data_bag)
89
- before(:each) { ChefZero::RSpec.server.load_data({ 'data' => { name => data_bag }}) }
124
+ before(:each) { ChefZero::RSpec.server.load_data({ 'data' => { name => data_bag }}, @current_org) }
90
125
  end
91
126
 
92
127
  def self.environment(name, environment)
93
- before(:each) { ChefZero::RSpec.server.load_data({ 'environments' => { name => environment }}) }
128
+ before(:each) { ChefZero::RSpec.server.load_data({ 'environments' => { name => environment }}, @current_org) }
94
129
  end
95
130
 
96
131
  def self.node(name, node)
97
- before(:each) { ChefZero::RSpec.server.load_data({ 'nodes' => { name => node }}) }
132
+ before(:each) { ChefZero::RSpec.server.load_data({ 'nodes' => { name => node }}, @current_org) }
98
133
  end
99
134
 
100
135
  def self.role(name, role)
101
- before(:each) { ChefZero::RSpec.server.load_data({ 'roles' => { name => role }}) }
136
+ before(:each) { ChefZero::RSpec.server.load_data({ 'roles' => { name => role }}, @current_org) }
102
137
  end
103
138
 
104
139
  def self.user(name, user)
105
- before(:each) { ChefZero::RSpec.server.load_data({ 'users' => { name => user }}) }
140
+ if ChefZero::RSpec.server.options[:osc_compat]
141
+ before(:each) { ChefZero::RSpec.server.load_data({ 'users' => { name => user }}, @current_org) }
142
+ else
143
+ before(:each) { ChefZero::RSpec.server.set([ 'users', name ], dejsonize(user)) }
144
+ end
145
+ end
146
+
147
+ def self.dejsonize(data)
148
+ if data.is_a?(String)
149
+ data
150
+ else
151
+ JSON.pretty_generate(value)
152
+ end
106
153
  end
107
154
 
108
155
  # after :each do
@@ -24,24 +24,32 @@ require 'stringio'
24
24
 
25
25
  require 'rack'
26
26
  require 'webrick'
27
+ require 'webrick/https'
27
28
 
28
29
  require 'chef_zero'
29
- require 'chef_zero/cookbook_data'
30
+ require 'chef_zero/chef_data/cookbook_data'
30
31
  require 'chef_zero/rest_router'
31
32
  require 'chef_zero/data_store/memory_store_v2'
32
33
  require 'chef_zero/data_store/v1_to_v2_adapter'
34
+ require 'chef_zero/data_store/default_facade'
33
35
  require 'chef_zero/version'
34
36
 
37
+ require 'chef_zero/endpoints/rest_list_endpoint'
35
38
  require 'chef_zero/endpoints/authenticate_user_endpoint'
39
+ require 'chef_zero/endpoints/acls_endpoint'
40
+ require 'chef_zero/endpoints/acl_endpoint'
36
41
  require 'chef_zero/endpoints/actors_endpoint'
37
42
  require 'chef_zero/endpoints/actor_endpoint'
38
43
  require 'chef_zero/endpoints/cookbooks_endpoint'
39
44
  require 'chef_zero/endpoints/cookbook_endpoint'
40
45
  require 'chef_zero/endpoints/cookbook_version_endpoint'
46
+ require 'chef_zero/endpoints/containers_endpoint'
47
+ require 'chef_zero/endpoints/container_endpoint'
41
48
  require 'chef_zero/endpoints/data_bags_endpoint'
42
49
  require 'chef_zero/endpoints/data_bag_endpoint'
43
50
  require 'chef_zero/endpoints/data_bag_item_endpoint'
44
- require 'chef_zero/endpoints/rest_list_endpoint'
51
+ require 'chef_zero/endpoints/groups_endpoint'
52
+ require 'chef_zero/endpoints/group_endpoint'
45
53
  require 'chef_zero/endpoints/environment_endpoint'
46
54
  require 'chef_zero/endpoints/environment_cookbooks_endpoint'
47
55
  require 'chef_zero/endpoints/environment_cookbook_endpoint'
@@ -49,7 +57,16 @@ require 'chef_zero/endpoints/environment_cookbook_versions_endpoint'
49
57
  require 'chef_zero/endpoints/environment_nodes_endpoint'
50
58
  require 'chef_zero/endpoints/environment_recipes_endpoint'
51
59
  require 'chef_zero/endpoints/environment_role_endpoint'
60
+ require 'chef_zero/endpoints/license_endpoint'
52
61
  require 'chef_zero/endpoints/node_endpoint'
62
+ require 'chef_zero/endpoints/organizations_endpoint'
63
+ require 'chef_zero/endpoints/organization_endpoint'
64
+ require 'chef_zero/endpoints/organization_association_requests_endpoint'
65
+ require 'chef_zero/endpoints/organization_association_request_endpoint'
66
+ require 'chef_zero/endpoints/organization_authenticate_user_endpoint'
67
+ require 'chef_zero/endpoints/organization_users_endpoint'
68
+ require 'chef_zero/endpoints/organization_user_endpoint'
69
+ require 'chef_zero/endpoints/organization_validator_key_endpoint'
53
70
  require 'chef_zero/endpoints/principal_endpoint'
54
71
  require 'chef_zero/endpoints/role_endpoint'
55
72
  require 'chef_zero/endpoints/role_environments_endpoint'
@@ -57,6 +74,11 @@ require 'chef_zero/endpoints/sandboxes_endpoint'
57
74
  require 'chef_zero/endpoints/sandbox_endpoint'
58
75
  require 'chef_zero/endpoints/searches_endpoint'
59
76
  require 'chef_zero/endpoints/search_endpoint'
77
+ require 'chef_zero/endpoints/system_recovery_endpoint'
78
+ require 'chef_zero/endpoints/user_association_requests_endpoint'
79
+ require 'chef_zero/endpoints/user_association_requests_count_endpoint'
80
+ require 'chef_zero/endpoints/user_association_request_endpoint'
81
+ require 'chef_zero/endpoints/user_organizations_endpoint'
60
82
  require 'chef_zero/endpoints/file_store_file_endpoint'
61
83
  require 'chef_zero/endpoints/not_found_endpoint'
62
84
 
@@ -67,11 +89,15 @@ module ChefZero
67
89
  :port => 8889,
68
90
  :log_level => :info,
69
91
  :generate_real_keys => true,
70
- :single_org => 'chef'
92
+ :single_org => 'chef',
93
+ :ssl => false
71
94
  }.freeze
72
95
 
73
96
  def initialize(options = {})
74
97
  @options = DEFAULT_OPTIONS.merge(options)
98
+ if @options[:single_org] && !@options.has_key?(:osc_compat)
99
+ @options[:osc_compat] = true
100
+ end
75
101
  @options.freeze
76
102
 
77
103
  ChefZero::Log.level = @options[:log_level].to_sym
@@ -105,10 +131,11 @@ module ChefZero
105
131
  # @return [String]
106
132
  #
107
133
  def url
134
+ sch = @options[:ssl] ? 'https' : 'http'
108
135
  @url ||= if @options[:host].include?(':')
109
- URI("http://[#{@options[:host]}]:#{port}").to_s
136
+ URI("#{sch}://[#{@options[:host]}]:#{port}").to_s
110
137
  else
111
- URI("http://#{@options[:host]}:#{port}").to_s
138
+ URI("#{sch}://#{@options[:host]}:#{port}").to_s
112
139
  end
113
140
  end
114
141
 
@@ -119,15 +146,16 @@ module ChefZero
119
146
  #
120
147
  def data_store
121
148
  @data_store ||= begin
122
- result = @options[:data_store] || DataStore::MemoryStoreV2.new
149
+ result = @options[:data_store] || DataStore::DefaultFacade.new(DataStore::MemoryStoreV2.new, options[:single_org], options[:osc_compat])
123
150
  if options[:single_org]
124
- if result.respond_to?(:interface_version) && result.interface_version >= 2 && result.interface_version < 3
125
- result.create_dir([ 'organizations' ], options[:single_org])
126
- else
151
+
152
+ if !result.respond_to?(:interface_version) || result.interface_version == 1
127
153
  result = ChefZero::DataStore::V1ToV2Adapter.new(result, options[:single_org])
154
+ result = ChefZero::DataStore::DefaultFacade.new(result, options[:single_org], options[:osc_compat])
128
155
  end
156
+
129
157
  else
130
- if !(result.respond_to?(:interface_version) && result.interface_version >= 2 && result.interface_version < 3)
158
+ if !result.respond_to?(:interface_version) || result.interface_version == 1
131
159
  raise "Multi-org not supported by data store #{result}!"
132
160
  end
133
161
  end
@@ -205,6 +233,8 @@ module ChefZero
205
233
  :DoNotListen => true,
206
234
  :AccessLog => [],
207
235
  :Logger => WEBrick::Log.new(StringIO.new, 7),
236
+ :SSLEnable => options[:ssl],
237
+ :SSLCertName => [ [ 'CN', WEBrick::Utils::getservername ] ],
208
238
  :StartCallback => proc {
209
239
  @running = true
210
240
  }
@@ -345,13 +375,13 @@ module ChefZero
345
375
  if contents['cookbooks']
346
376
  contents['cookbooks'].each_pair do |name_version, cookbook|
347
377
  if name_version =~ /(.+)-(\d+\.\d+\.\d+)$/
348
- cookbook_data = CookbookData.to_hash(cookbook, $1, $2)
378
+ cookbook_data = ChefData::CookbookData.to_hash(cookbook, $1, $2)
349
379
  else
350
- cookbook_data = CookbookData.to_hash(cookbook, name_version)
380
+ cookbook_data = ChefData::CookbookData.to_hash(cookbook, name_version)
351
381
  end
352
382
  raise "No version specified" if !cookbook_data[:version]
353
383
  data_store.create_dir(['organizations', org_name, 'cookbooks'], cookbook_data[:cookbook_name], :recursive)
354
- data_store.set(['organizations', org_name, 'cookbooks', cookbook_data[:cookbook_name], cookbook_data[:version]], FFI_Yajl::Encoder.encode(cookbook_data, :pretty => true), :create)
384
+ data_store.set(['organizations', org_name, 'cookbooks', cookbook_data[:cookbook_name], cookbook_data[:version]], JSON.pretty_generate(cookbook_data), :create)
355
385
  cookbook_data.values.each do |files|
356
386
  next unless files.is_a? Array
357
387
  files.each do |file|
@@ -364,9 +394,6 @@ module ChefZero
364
394
 
365
395
  def clear_data
366
396
  data_store.clear
367
- if options[:single_org]
368
- data_store.create_dir([ 'organizations' ], options[:single_org])
369
- end
370
397
  end
371
398
 
372
399
  def request_handler(&block)
@@ -384,8 +411,48 @@ module ChefZero
384
411
  private
385
412
 
386
413
  def open_source_endpoints
414
+ result = if options[:osc_compat]
415
+ # OSC-only
416
+ [
417
+ [ "/organizations/*/users", ActorsEndpoint.new(self) ],
418
+ [ "/organizations/*/users/*", ActorEndpoint.new(self) ],
419
+ [ "/organizations/*/authenticate_user", OrganizationAuthenticateUserEndpoint.new(self) ],
420
+ ]
421
+ else
422
+ # EC-only
423
+ [
424
+ [ "/organizations/*/users", OrganizationUsersEndpoint.new(self) ],
425
+ [ "/organizations/*/users/*", OrganizationUserEndpoint.new(self) ],
426
+ [ "/users", ActorsEndpoint.new(self, 'username') ],
427
+ [ "/users/*", ActorEndpoint.new(self, 'username') ],
428
+ [ "/users/_acl", AclsEndpoint.new(self) ],
429
+ [ "/users/_acl/*", AclEndpoint.new(self) ],
430
+ [ "/users/*/association_requests", UserAssociationRequestsEndpoint.new(self) ],
431
+ [ "/users/*/association_requests/count", UserAssociationRequestsCountEndpoint.new(self) ],
432
+ [ "/users/*/association_requests/*", UserAssociationRequestEndpoint.new(self) ],
433
+ [ "/users/*/organizations", UserOrganizationsEndpoint.new(self) ],
434
+ [ "/authenticate_user", AuthenticateUserEndpoint.new(self) ],
435
+ [ "/system_recovery", SystemRecoveryEndpoint.new(self) ],
436
+ [ "/license", LicenseEndpoint.new(self) ],
437
+
438
+ [ "/organizations", OrganizationsEndpoint.new(self) ],
439
+ [ "/organizations/*", OrganizationEndpoint.new(self) ],
440
+ [ "/organizations/*/_validator_key", OrganizationValidatorKeyEndpoint.new(self) ],
441
+ [ "/organizations/*/association_requests", OrganizationAssociationRequestsEndpoint.new(self) ],
442
+ [ "/organizations/*/association_requests/*", OrganizationAssociationRequestEndpoint.new(self) ],
443
+ [ "/organizations/*/containers", ContainersEndpoint.new(self) ],
444
+ [ "/organizations/*/containers/*", ContainerEndpoint.new(self) ],
445
+ [ "/organizations/*/groups", GroupsEndpoint.new(self) ],
446
+ [ "/organizations/*/groups/*", GroupEndpoint.new(self) ],
447
+ [ "/organizations/*/organizations/_acl", AclsEndpoint.new(self) ],
448
+ [ "/organizations/*/*/*/_acl", AclsEndpoint.new(self) ],
449
+ [ "/organizations/*/organizations/_acl/*", AclEndpoint.new(self) ],
450
+ [ "/organizations/*/*/*/_acl/*", AclEndpoint.new(self) ]
451
+ ]
452
+ end
453
+ result +
387
454
  [
388
- [ "/organizations/*/authenticate_user", AuthenticateUserEndpoint.new(self) ],
455
+ # Both
389
456
  [ "/organizations/*/clients", ActorsEndpoint.new(self) ],
390
457
  [ "/organizations/*/clients/*", ActorEndpoint.new(self) ],
391
458
  [ "/organizations/*/cookbooks", CookbooksEndpoint.new(self) ],
@@ -413,10 +480,9 @@ module ChefZero
413
480
  [ "/organizations/*/sandboxes/*", SandboxEndpoint.new(self) ],
414
481
  [ "/organizations/*/search", SearchesEndpoint.new(self) ],
415
482
  [ "/organizations/*/search/*", SearchEndpoint.new(self) ],
416
- [ "/organizations/*/users", ActorsEndpoint.new(self) ],
417
- [ "/organizations/*/users/*", ActorEndpoint.new(self) ],
418
483
 
419
- [ "/organizations/*/file_store/**", FileStoreFileEndpoint.new(self) ],
484
+ # Internal
485
+ [ "/organizations/*/file_store/**", FileStoreFileEndpoint.new(self) ]
420
486
  ]
421
487
  end
422
488
 
@@ -467,7 +533,7 @@ module ChefZero
467
533
  def dejsonize_children(hash)
468
534
  result = {}
469
535
  hash.each_pair do |key, value|
470
- result[key] = value.is_a?(Hash) ? FFI_Yajl::Encoder.encode(value, :pretty => true) : value
536
+ result[key] = value.is_a?(Hash) ? JSON.pretty_generate(value) : value
471
537
  end
472
538
  result
473
539
  end