chef-zero 2.2.1 → 3.0.0.rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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