chef-zero 4.5.0 → 4.6.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6cc5716f0bde147efc79fb02be61275ea01aa654
4
- data.tar.gz: d1a2c69275d9a2bc901f5024f47be5b821320e98
3
+ metadata.gz: ca7530fffb7dc24422a41d298d2411f8661d5e7d
4
+ data.tar.gz: a18a46c9da1936c3d89ec33e83d7e97ed0b82bb6
5
5
  SHA512:
6
- metadata.gz: e0c7757da8314dad7ff5f58fe4423c7ee816b32138f59b16fcf9073e8b8fffc045b819781e81e119f85c553d44b6336e678c37d8aed0d729aae3f54ebbc48f3f
7
- data.tar.gz: a606ffcd42a0001e1f1a43854d9f373e15f6000a29eb52129a0b5a0298eeff28675bb6d8d4e6991c179fd4b24e0a241623f9388b0d1e733f1e1a254cb9c13272
6
+ metadata.gz: 9e5a78f306534fc4849f8f40c1ba435d3efa9c8cebbd182e26b68e34c92a08aed491c5259780847c0cf05ab19480cc485b61b12b01992b27ddad4a776be81897
7
+ data.tar.gz: 4add88aed368a2044f817a5f7caa2429a27c2d6f23e81c3054ba4a68270250c404f926abaf571c354069fcbe61dcbc4163ec9dc31e7255e77d0dd75e5302d553
data/Gemfile CHANGED
@@ -3,7 +3,11 @@ gemspec
3
3
 
4
4
  # gem 'rest-client', :github => 'chef/rest-client'
5
5
 
6
- gem 'oc-chef-pedant', :github => 'chef/chef-server', :branch => "jk/authorization-tags"
6
+ gem 'oc-chef-pedant', :github => 'chef/chef-server'
7
+
8
+ group :changelog do
9
+ gem "github_changelog_generator"
10
+ end
7
11
 
8
12
  # bundler resolve failure on "rspec_junit_formatter"
9
13
  # gem 'chef-pedant', :github => 'opscode/chef-pedant', :ref => "server-cli-option"
data/Rakefile CHANGED
@@ -3,33 +3,43 @@ require 'bundler/gem_tasks'
3
3
 
4
4
  require 'chef_zero/version'
5
5
 
6
+ def run_oc_pedant(env={})
7
+ ENV.update(env)
8
+ require File.expand_path('spec/run_oc_pedant')
9
+ end
10
+
11
+ ENV_DOCS = <<END
12
+ Environment:
13
+ - RSPEC_OPTS Options to pass to RSpec
14
+ e.g. RSPEC_OPTS="--fail-fast --profile 5"
15
+ - PEDANT_OPTS Options to pass to oc-chef-pedant
16
+ e.g. PEDANT_OPTS="--focus-keys --skip-users"
17
+ - LOG_LEVEL Set the log level (default: warn)
18
+ e.g. LOG_LEVEL=debug
19
+ END
20
+
6
21
  task :default => :pedant
7
22
 
8
- desc "run specs"
23
+ desc "Run specs"
9
24
  task :spec do
10
25
  system('rspec spec/*_spec.rb')
11
26
  end
12
27
 
13
- desc "run oc pedant"
14
- task :pedant do
15
- require File.expand_path('spec/run_oc_pedant')
16
- end
28
+ desc "Run oc-chef-pedant\n\n#{ENV_DOCS}"
29
+ task :pedant => :oc_pedant
17
30
 
18
- desc "run pedant with CHEF_FS set"
31
+ desc "Run oc-chef-pedant with CHEF_FS set\n\n#{ENV_DOCS}"
19
32
  task :cheffs do
20
- ENV['CHEF_FS'] = "yes"
21
- require File.expand_path('spec/run_oc_pedant')
33
+ run_oc_pedant('CHEF_FS' => 'yes')
22
34
  end
23
35
 
24
- desc "run pedant with FILE_STORE set"
36
+ desc "Run oc-chef-pedant with FILE_STORE set\n\n#{ENV_DOCS}"
25
37
  task :filestore do
26
- ENV['FILE_STORE'] = "yes"
27
- require File.expand_path('spec/run_oc_pedant')
38
+ run_oc_pedant('FILE_STORE' => 'yes')
28
39
  end
29
40
 
30
- desc "run oc pedant"
31
41
  task :oc_pedant do
32
- require File.expand_path('spec/run_oc_pedant')
42
+ run_oc_pedant
33
43
  end
34
44
 
35
45
  task :chef_spec do
@@ -42,11 +52,15 @@ task :berkshelf_spec do
42
52
  system("cd #{gem_path} && thor spec:ci")
43
53
  end
44
54
 
45
- require 'github_changelog_generator/task'
55
+ begin
56
+ require "github_changelog_generator/task"
46
57
 
47
- GitHubChangelogGenerator::RakeTask.new :changelog do |config|
48
- # config.future_release = ChefZero::VERSION
49
- config.enhancement_labels = "enhancement,Enhancement,New Feature".split(',')
50
- config.bug_labels = "bug,Bug,Improvement,Upstream Bug".split(',')
51
- config.exclude_labels = "duplicate,question,invalid,wontfix,no_changelog".split(',')
58
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
59
+ config.future_release = ChefZero::VERSION
60
+ config.enhancement_labels = "enhancement,Enhancement,New Feature,Feature".split(",")
61
+ config.bug_labels = "bug,Bug,Improvement,Upstream Bug".split(",")
62
+ config.exclude_labels = "duplicate,question,invalid,wontfix,no_changelog,Exclude From Changelog,Question,Discussion".split(",")
63
+ end
64
+ rescue LoadError
65
+ puts "github_changelog_generator is not available. gem install github_changelog_generator to generate changelogs"
52
66
  end
@@ -31,7 +31,8 @@ OptionParser.new do |opts|
31
31
  opts.banner = "Usage: chef-zero [ARGS]"
32
32
 
33
33
  opts.on("-H", "--host HOST", "Host to bind to (default: 127.0.0.1)") do |value|
34
- options[:host] = value
34
+ options[:host] ||= []
35
+ options[:host] << value
35
36
  end
36
37
 
37
38
  opts.on("-p", "--port PORT", "Port to listen on (e.g. 8889, or 8500-8600 or 8885,8888)") do |value|
@@ -12,6 +12,8 @@ Gem::Specification.new do |s|
12
12
  s.homepage = 'http://www.opscode.com'
13
13
  s.license = 'Apache 2.0'
14
14
 
15
+ s.required_ruby_version = ">= 2.1.0"
16
+
15
17
  s.add_dependency 'mixlib-log', '~> 1.3'
16
18
  s.add_dependency 'hashie', '>= 2.0', '< 4.0'
17
19
  s.add_dependency 'uuidtools', '~> 2.1'
@@ -23,7 +25,6 @@ Gem::Specification.new do |s|
23
25
  s.add_development_dependency 'pry-stack_explorer'
24
26
  s.add_development_dependency 'rake'
25
27
  s.add_development_dependency 'rspec'
26
- s.add_development_dependency 'github_changelog_generator'
27
28
  s.add_development_dependency 'chef'
28
29
 
29
30
  s.bindir = 'bin'
@@ -108,6 +108,11 @@ module ChefZero
108
108
  cookbook_arg(:replacing, cookbook, version_constraints)
109
109
  end
110
110
 
111
+ def gem(*opts)
112
+ self[:gems] ||= []
113
+ self[:gems] << opts
114
+ end
115
+
111
116
  def recipe(recipe, description)
112
117
  self[:recipes][recipe] = description
113
118
  end
@@ -17,8 +17,8 @@ module ChefZero
17
17
  def self.normalize_client(client, name, orgname = nil)
18
18
  client['name'] ||= name
19
19
  client['clientname'] ||= name
20
- client['admin'] = !!client['admin'] if client.has_key?('admin')
21
- client['public_key'] ||= PUBLIC_KEY
20
+ client['admin'] = !!client['admin'] if client.key?('admin')
21
+ client['public_key'] = PUBLIC_KEY unless client.key?('public_key')
22
22
  client['orgname'] ||= orgname
23
23
  client['validator'] ||= false
24
24
  client['validator'] = !!client['validator']
@@ -36,7 +36,7 @@ module ChefZero
36
36
 
37
37
  def self.normalize_user(user, name, identity_keys, osc_compat, method=nil)
38
38
  user[identity_keys.first] ||= name
39
- user['public_key'] ||= PUBLIC_KEY
39
+ user['public_key'] = PUBLIC_KEY unless user.key?('public_key')
40
40
  user['admin'] ||= false
41
41
  user['admin'] = !!user['admin']
42
42
  user['openid'] ||= nil
@@ -19,13 +19,14 @@
19
19
  module ChefZero
20
20
  module DataStore
21
21
  class DataError < StandardError
22
+ attr_reader :path, :cause
23
+
22
24
  def initialize(path, cause = nil)
23
25
  @path = path
24
26
  @cause = cause
27
+ path_for_msg = path.nil? ? "nil" : "/#{path.join('/')}"
28
+ super "Data path: #{path_for_msg}"
25
29
  end
26
-
27
- attr_reader :path
28
- attr_reader :cause
29
30
  end
30
31
  end
31
32
  end
@@ -0,0 +1,77 @@
1
+ require 'chef_zero/rest_base'
2
+
3
+ module ChefZero
4
+ module Endpoints
5
+ # ActorDefaultKeyEndpoint
6
+ #
7
+ # This class handles DELETE/GET/PUT requests for client/user default public
8
+ # keys, i.e. requests with identity key "default". All others are handled
9
+ # by ActorKeyEndpoint.
10
+ #
11
+ # Default public keys are stored with the actor (client or user) instead of
12
+ # under user/client_keys. Handling those in a separate endpoint offloads
13
+ # the branching logic onto the router rather than branching in every
14
+ # endpoint method (`if request.rest_path[-1] == "default" ...`).
15
+ #
16
+ # /users/USER/keys/default
17
+ # /organizations/ORG/clients/CLIENT/keys/default
18
+ class ActorDefaultKeyEndpoint < RestBase
19
+ DEFAULT_PUBLIC_KEY_NAME = "default".freeze
20
+
21
+ def get(request)
22
+ # 404 if actor doesn't exist
23
+ actor_data = get_actor_data(request)
24
+ key_data = default_public_key_from_actor(actor_data)
25
+
26
+ # 404 if the actor doesn't have a default key
27
+ if key_data["public_key"].nil?
28
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
29
+ end
30
+
31
+ json_response(200, default_public_key_from_actor(actor_data))
32
+ end
33
+
34
+ def delete(request)
35
+ path = actor_path(request)
36
+ actor_data = get_actor_data(request) # 404 if actor doesn't exist
37
+
38
+ default_public_key = delete_actor_default_public_key!(request, path, actor_data)
39
+ json_response(200, default_public_key)
40
+ end
41
+
42
+ def put(request)
43
+ # 404 if actor doesn't exist
44
+ actor_data = get_actor_data(request)
45
+
46
+ new_public_key = parse_json(request.body)["public_key"]
47
+ actor_data["public_key"] = new_public_key
48
+
49
+ set_data(request, actor_path(request), to_json(actor_data))
50
+ end
51
+
52
+ private
53
+
54
+ def actor_path(request)
55
+ return request.rest_path[0..3] if request.rest_path[2] == "clients"
56
+ request.rest_path[0..1]
57
+ end
58
+
59
+ def get_actor_data(request)
60
+ path = actor_path(request)
61
+ parse_json(get_data(request, path))
62
+ end
63
+
64
+ def default_public_key_from_actor(actor_data)
65
+ { "name" => DEFAULT_PUBLIC_KEY_NAME,
66
+ "public_key" => actor_data["public_key"],
67
+ "expiration_date" => "infinity" }
68
+ end
69
+
70
+ def delete_actor_default_public_key!(request, path, actor_data)
71
+ new_actor_data = actor_data.merge("public_key" => nil)
72
+ set_data(request, path, to_json(new_actor_data))
73
+ default_public_key_from_actor(actor_data)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -8,8 +8,19 @@ module ChefZero
8
8
  # /organizations/ORG/users/NAME
9
9
  # /users/NAME
10
10
  class ActorEndpoint < RestObjectEndpoint
11
+
12
+ def get(request)
13
+ result = super
14
+ user_data = parse_json(result[2])
15
+
16
+ user_data.delete("public_key") unless request.api_v0?
17
+
18
+ json_response(200, user_data)
19
+ end
20
+
11
21
  def delete(request)
12
22
  result = super
23
+
13
24
  if request.rest_path[0] == 'users'
14
25
  list_data(request, [ 'organizations' ]).each do |org|
15
26
  begin
@@ -18,12 +29,15 @@ module ChefZero
18
29
  end
19
30
  end
20
31
  end
32
+
33
+ delete_actor_keys!(request)
21
34
  result
22
35
  end
23
36
 
24
37
  def put(request)
25
38
  # Find out if we're updating the public key.
26
39
  request_body = FFI_Yajl::Parser.parse(request.body, :create_additions => false)
40
+
27
41
  if request_body['public_key'].nil?
28
42
  # If public_key is null, then don't overwrite it. Weird patchiness.
29
43
  body_modified = true
@@ -33,18 +47,18 @@ module ChefZero
33
47
  end
34
48
 
35
49
  # Generate private_key if requested.
36
- if request_body.has_key?('private_key')
50
+ if request_body.key?('private_key')
37
51
  body_modified = true
38
- if request_body['private_key']
52
+
53
+ if request_body.delete('private_key')
39
54
  private_key, public_key = server.gen_key_pair
40
55
  updating_public_key = true
41
56
  request_body['public_key'] = public_key
42
57
  end
43
- request_body.delete('private_key')
44
58
  end
45
59
 
46
- # Save request
47
- request.body = FFI_Yajl::Encoder.encode(request_body, :pretty => true) if body_modified
60
+ # Put modified body back in `request.body`
61
+ request.body = to_json(request_body) if body_modified
48
62
 
49
63
  # PUT /clients is patchy
50
64
  request.body = patch_request_body(request)
@@ -53,27 +67,29 @@ module ChefZero
53
67
 
54
68
  # Inject private_key into response, delete public_key/password if applicable
55
69
  if result[0] == 200 || result[0] == 201
70
+ client_or_user_name = identity_key_value(request) || request.rest_path[-1]
71
+
72
+ if is_rename?(request)
73
+ rename_keys!(request, client_or_user_name)
74
+ end
75
+
56
76
  if request.rest_path[0] == 'users'
57
- key = nil
58
- identity_keys.each do |identity_key|
59
- key ||= request_body[identity_key]
60
- end
61
- key ||= request.rest_path[-1]
62
77
  response = {
63
- 'uri' => build_uri(request.base_uri, [ 'users', key ])
78
+ 'uri' => build_uri(request.base_uri, [ 'users', client_or_user_name ])
64
79
  }
65
80
  else
66
- response = FFI_Yajl::Parser.parse(result[2], :create_additions => false)
81
+ response = parse_json(result[2])
67
82
  end
68
83
 
69
- if request.rest_path[2] == 'clients'
84
+ if client?(request)
70
85
  response['private_key'] = private_key ? private_key : false
71
86
  else
72
87
  response['private_key'] = private_key if private_key
88
+ response.delete('public_key') unless updating_public_key
73
89
  end
74
90
 
75
- response.delete('public_key') if !updating_public_key && request.rest_path[2] == 'users'
76
91
  response.delete('password')
92
+
77
93
  json_response(result[0], response)
78
94
  else
79
95
  result
@@ -81,13 +97,86 @@ module ChefZero
81
97
  end
82
98
 
83
99
  def populate_defaults(request, response_json)
84
- response = FFI_Yajl::Parser.parse(response_json, :create_additions => false)
85
- if request.rest_path[2] == 'clients'
86
- response = ChefData::DataNormalizer.normalize_client(response,request.rest_path[3], request.rest_path[1])
100
+ response = parse_json(response_json)
101
+
102
+ populated_response =
103
+ if client?(request)
104
+ ChefData::DataNormalizer.normalize_client(
105
+ response,
106
+ response["name"] || request.rest_path[-1],
107
+ request.rest_path[1]
108
+ )
109
+ else
110
+ ChefData::DataNormalizer.normalize_user(
111
+ response,
112
+ response["username"] || request.rest_path[-1],
113
+ identity_keys,
114
+ server.options[:osc_compat],
115
+ request.method
116
+ )
117
+ end
118
+
119
+ to_json(populated_response)
120
+ end
121
+
122
+ private
123
+
124
+ # Move key data to new path
125
+ def rename_keys!(request, new_client_or_user_name)
126
+ orig_keys_path = keys_path_base(request)
127
+ new_keys_path = orig_keys_path.dup
128
+ .tap {|path| path[-2] = new_client_or_user_name }
129
+
130
+ key_names = list_data_or_else(request, orig_keys_path, nil)
131
+ return unless key_names # No keys to move
132
+
133
+ key_names.each do |key_name|
134
+ # Get old data
135
+ orig_path = [ *orig_keys_path, key_name ]
136
+ data = get_data(request, orig_path, :data_store_exceptions)
137
+
138
+ # Copy data to new path
139
+ create_data(
140
+ request,
141
+ new_keys_path, key_name,
142
+ data,
143
+ :create_dir
144
+ )
145
+ end
146
+
147
+ # Delete original data
148
+ delete_data_dir(request, orig_keys_path, :recursive, :data_store_exceptions)
149
+ end
150
+
151
+ def delete_actor_keys!(request)
152
+ path = keys_path_base(request)[0..-2]
153
+ delete_data_dir(request, path, :recursive, :data_store_exceptions)
154
+ rescue DataStore::DataNotFoundError
155
+ end
156
+
157
+ def client?(request, rest_path=nil)
158
+ rest_path ||= request.rest_path
159
+ request.rest_path[2] == "clients"
160
+ end
161
+
162
+ # Return the data store keys path for the request client or user, e.g.
163
+ #
164
+ # [ "organizations", <org>, "client_keys", <client>, "keys" ]
165
+ #
166
+ # Or:
167
+ #
168
+ # [ "user_keys", <user>, "keys" ]
169
+ #
170
+ def keys_path_base(request, client_or_user_name=nil)
171
+ rest_path = (rest_path || request.rest_path).dup
172
+ rest_path[-1] = client_or_user_name if client_or_user_name
173
+
174
+ if client?(request, rest_path)
175
+ [ *rest_path[0..1], "client_keys" ]
87
176
  else
88
- response = ChefData::DataNormalizer.normalize_user(response, request.rest_path[3], identity_keys, server.options[:osc_compat], request.method)
177
+ [ "user_keys" ]
89
178
  end
90
- FFI_Yajl::Encoder.encode(response, :pretty => true)
179
+ .push(rest_path.last, "keys")
91
180
  end
92
181
  end
93
182
  end