chef-dk 0.3.0 → 0.3.5

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -0
  3. data/lib/chef-dk/cli.rb +7 -5
  4. data/lib/chef-dk/command/generate.rb +2 -0
  5. data/lib/chef-dk/command/generator_commands.rb +8 -0
  6. data/lib/chef-dk/command/generator_commands/base.rb +4 -1
  7. data/lib/chef-dk/command/generator_commands/policyfile.rb +83 -0
  8. data/lib/chef-dk/command/install.rb +4 -5
  9. data/lib/chef-dk/command/push.rb +4 -5
  10. data/lib/chef-dk/command/verify.rb +3 -2
  11. data/lib/chef-dk/component_test.rb +7 -2
  12. data/lib/chef-dk/exceptions.rb +3 -34
  13. data/lib/chef-dk/helpers.rb +20 -2
  14. data/lib/chef-dk/policyfile/cookbook_locks.rb +19 -1
  15. data/lib/chef-dk/policyfile/read_cookbook_for_compat_mode_upload.rb +11 -1
  16. data/lib/chef-dk/policyfile/storage_config.rb +23 -0
  17. data/lib/chef-dk/policyfile/uploader.rb +1 -1
  18. data/lib/chef-dk/policyfile_services/install.rb +19 -32
  19. data/lib/chef-dk/policyfile_services/push.rb +17 -27
  20. data/lib/chef-dk/service_exception_inspectors.rb +25 -0
  21. data/lib/chef-dk/service_exception_inspectors/base.rb +40 -0
  22. data/lib/chef-dk/service_exception_inspectors/http.rb +121 -0
  23. data/lib/chef-dk/service_exceptions.rb +77 -0
  24. data/lib/chef-dk/skeletons/code_generator/recipes/policyfile.rb +8 -0
  25. data/lib/chef-dk/skeletons/code_generator/templates/default/Policyfile.rb.erb +16 -0
  26. data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen.yml.erb +1 -1
  27. data/lib/chef-dk/version.rb +1 -1
  28. data/spec/unit/cli_spec.rb +126 -65
  29. data/spec/unit/command/exec_spec.rb +7 -2
  30. data/spec/unit/command/generator_commands/cookbook_spec.rb +27 -1
  31. data/spec/unit/command/generator_commands/policyfile_spec.rb +125 -0
  32. data/spec/unit/command/install_spec.rb +3 -4
  33. data/spec/unit/command/push_spec.rb +6 -7
  34. data/spec/unit/command/shell_init_spec.rb +5 -1
  35. data/spec/unit/cookbook_profiler/git_spec.rb +2 -2
  36. data/spec/unit/policyfile/cookbook_locks_spec.rb +58 -0
  37. data/spec/unit/policyfile/read_cookbook_for_compat_mode_upload_spec.rb +8 -1
  38. data/spec/unit/policyfile/storage_config_spec.rb +75 -1
  39. data/spec/unit/policyfile/uploader_spec.rb +31 -0
  40. data/spec/unit/policyfile_lock_validation_spec.rb +13 -12
  41. data/spec/unit/policyfile_services/install_spec.rb +5 -3
  42. data/spec/unit/policyfile_services/push_spec.rb +7 -5
  43. data/spec/unit/service_exception_inspectors/base_spec.rb +43 -0
  44. data/spec/unit/service_exception_inspectors/http_spec.rb +140 -0
  45. metadata +41 -2
@@ -16,6 +16,7 @@
16
16
  #
17
17
 
18
18
  require 'chef-dk/cookbook_omnifetch'
19
+ require 'chef-dk/exceptions'
19
20
 
20
21
  module ChefDK
21
22
  module Policyfile
@@ -37,23 +38,37 @@ module ChefDK
37
38
  end
38
39
 
39
40
  def use_policyfile(policyfile_filename)
41
+ unless policyfile_filename.end_with?(".rb")
42
+ raise InvalidPolicyfileFilename, "Policyfile filenames must end with `.rb' extension (you gave: `#{policyfile_filename}')"
43
+ end
40
44
  @policyfile_filename = policyfile_filename
45
+ @policyfile_lock_filename = policyfile_filename.sub(/\.rb\Z/, '.lock.json')
41
46
  @relative_paths_root = File.dirname(policyfile_filename)
42
47
  self
43
48
  end
44
49
 
45
50
  def use_policyfile_lock(policyfile_lock_filename)
46
51
  @policyfile_lock_filename = policyfile_lock_filename
52
+ @policyfile_filename = policyfile_lock_filename.sub(/\.lock\.json\Z/, '.rb')
47
53
  @relative_paths_root = File.dirname(policyfile_lock_filename)
48
54
  self
49
55
  end
50
56
 
57
+ def policyfile_expanded_path
58
+ File.expand_path(policyfile_filename, relative_paths_root)
59
+ end
60
+
61
+ def policyfile_lock_expanded_path
62
+ File.expand_path(policyfile_lock_filename, relative_paths_root)
63
+ end
64
+
51
65
  private
52
66
 
53
67
  def handle_options(options)
54
68
  @cache_path = options[:cache_path] if options[:cache_path]
55
69
  @relative_paths_root = options[:relative_paths_root] if options.key?(:relative_paths_root)
56
70
  end
71
+
57
72
  end
58
73
 
59
74
  module StorageConfigDelegation
@@ -70,6 +85,14 @@ module ChefDK
70
85
  storage_config.policyfile_filename
71
86
  end
72
87
 
88
+ def policyfile_expanded_path
89
+ storage_config.policyfile_expanded_path
90
+ end
91
+
92
+ def policyfile_lock_expanded_path
93
+ storage_config.policyfile_lock_expanded_path
94
+ end
95
+
73
96
  end
74
97
 
75
98
  end
@@ -119,7 +119,7 @@ module ChefDK
119
119
  def upload_cookbooks
120
120
  ui.msg("WARN: Uploading cookbooks using semver compat mode")
121
121
 
122
- uploader.upload_cookbooks
122
+ uploader.upload_cookbooks unless cookbook_versions_to_upload.empty?
123
123
 
124
124
  reused_cbs, uploaded_cbs = cookbook_versions_for_policy.partition do |cb_with_lock|
125
125
  remote_already_has_cookbook?(cb_with_lock.cookbook)
@@ -15,7 +15,9 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
- require 'chef-dk/exceptions'
18
+ require 'ffi_yajl'
19
+
20
+ require 'chef-dk/service_exceptions'
19
21
  require 'chef-dk/policyfile_compiler'
20
22
  require 'chef-dk/policyfile/storage_config'
21
23
  require 'chef-dk/policyfile_lock'
@@ -25,54 +27,43 @@ module ChefDK
25
27
 
26
28
  class Install
27
29
 
28
- attr_reader :root_dir
30
+ include Policyfile::StorageConfigDelegation
31
+ include ChefDK::Helpers
32
+
29
33
  attr_reader :ui
34
+ attr_reader :storage_config
30
35
 
31
36
  def initialize(policyfile: nil, ui: nil, root_dir: nil)
32
- @policyfile_relative_path = policyfile
33
37
  @ui = ui
34
- @root_dir = root_dir
38
+
39
+ policyfile_rel_path = policyfile || "Policyfile.rb"
40
+ policyfile_full_path = File.expand_path(policyfile_rel_path, root_dir)
41
+ @storage_config = Policyfile::StorageConfig.new.use_policyfile(policyfile_full_path)
35
42
 
36
43
  @policyfile_content = nil
37
44
  @policyfile_compiler = nil
38
45
  end
39
46
 
40
47
  def run
41
- unless File.exist?(policyfile_path)
48
+ unless File.exist?(policyfile_expanded_path)
42
49
  # TODO: suggest next step. Add a generator/init command? Specify path to Policyfile.rb?
43
50
  # See card CC-232
44
- raise PolicyfileNotFound, "Policyfile not found at path #{policyfile_path}"
51
+ raise PolicyfileNotFound, "Policyfile not found at path #{policyfile_expanded_path}"
45
52
  end
46
53
 
47
- if File.exist?(lockfile_path)
54
+ if File.exist?(policyfile_lock_expanded_path)
48
55
  install_from_lock
49
56
  else
50
57
  generate_lock_and_install
51
58
  end
52
59
  end
53
60
 
54
- def policyfile_relative_path
55
- @policyfile_relative_path || "Policyfile.rb"
56
- end
57
-
58
- def policyfile_path
59
- File.expand_path(policyfile_relative_path, root_dir)
60
- end
61
-
62
- def lockfile_relative_path
63
- policyfile_relative_path.gsub(/\.rb\Z/, '') + ".lock.json"
64
- end
65
-
66
- def lockfile_path
67
- File.expand_path(lockfile_relative_path, root_dir)
68
- end
69
-
70
61
  def policyfile_content
71
- @policyfile_content ||= IO.read(policyfile_path)
62
+ @policyfile_content ||= IO.read(policyfile_expanded_path)
72
63
  end
73
64
 
74
65
  def policyfile_compiler
75
- @policyfile_compiler ||= ChefDK::PolicyfileCompiler.evaluate(policyfile_content, policyfile_path, ui: ui)
66
+ @policyfile_compiler ||= ChefDK::PolicyfileCompiler.evaluate(policyfile_content, policyfile_expanded_path, ui: ui)
76
67
  end
77
68
 
78
69
  def expanded_run_list
@@ -80,7 +71,7 @@ module ChefDK
80
71
  end
81
72
 
82
73
  def policyfile_lock_content
83
- @policyfile_lock_content ||= IO.read(lockfile_path) if File.exist?(lockfile_path)
74
+ @policyfile_lock_content ||= IO.read(policyfile_lock_expanded_path) if File.exist?(policyfile_lock_expanded_path)
84
75
  end
85
76
 
86
77
  def policyfile_lock
@@ -91,10 +82,6 @@ module ChefDK
91
82
  end
92
83
  end
93
84
 
94
- def storage_config
95
- @storage_config ||= Policyfile::StorageConfig.new(relative_paths_root: root_dir)
96
- end
97
-
98
85
  def generate_lock_and_install
99
86
  policyfile_compiler.error!
100
87
 
@@ -107,13 +94,13 @@ module ChefDK
107
94
 
108
95
  lock_data = policyfile_compiler.lock.to_lock
109
96
 
110
- File.open(lockfile_path, "w+") do |f|
97
+ with_file(policyfile_lock_expanded_path) do |f|
111
98
  f.print(FFI_Yajl::Encoder.encode(lock_data, pretty: true ))
112
99
  end
113
100
 
114
101
  ui.msg ""
115
102
 
116
- ui.msg "Lockfile written to #{lockfile_path}"
103
+ ui.msg "Lockfile written to #{policyfile_lock_expanded_path}"
117
104
  rescue => error
118
105
  raise PolicyfileInstallError.new("Failed to generate Policyfile.lock", error)
119
106
  end
@@ -15,47 +15,41 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
+ require 'ffi_yajl'
19
+
20
+ require 'chef-dk/service_exceptions'
18
21
  require 'chef-dk/authenticated_http'
19
22
  require 'chef-dk/policyfile_compiler'
20
23
  require 'chef-dk/policyfile/uploader'
24
+ require 'chef-dk/policyfile/storage_config'
21
25
 
22
26
  module ChefDK
23
27
  module PolicyfileServices
24
28
  class Push
25
29
 
30
+ include Policyfile::StorageConfigDelegation
31
+ include ChefDK::Helpers
32
+
26
33
  attr_reader :root_dir
27
34
  attr_reader :config
28
35
  attr_reader :policy_group
29
36
  attr_reader :ui
37
+ attr_reader :storage_config
30
38
 
31
39
  def initialize(policyfile: nil, ui: nil, policy_group: nil, config: nil, root_dir: nil)
32
40
  @root_dir = root_dir
33
- @policyfile_relative_path = policyfile
34
41
  @ui = ui
35
42
  @config = config
36
43
  @policy_group = policy_group
37
44
 
45
+ policyfile_rel_path = policyfile || "Policyfile.rb"
46
+ policyfile_full_path = File.expand_path(policyfile_rel_path, root_dir)
47
+ @storage_config = Policyfile::StorageConfig.new.use_policyfile(policyfile_full_path)
48
+
38
49
  @http_client = nil
39
- @storage_config = nil
40
50
  @policy_data = nil
41
51
  end
42
52
 
43
- def policyfile_relative_path
44
- @policyfile_relative_path || "Policyfile.rb"
45
- end
46
-
47
- def policyfile_path
48
- File.expand_path(policyfile_relative_path, root_dir)
49
- end
50
-
51
- def lockfile_relative_path
52
- policyfile_relative_path.gsub(/\.rb\Z/, '') + ".lock.json"
53
- end
54
-
55
- def lockfile_path
56
- File.expand_path(lockfile_relative_path, root_dir)
57
- end
58
-
59
53
  def http_client
60
54
  @http_client ||= ChefDK::AuthenticatedHTTP.new(config.chef_server_url,
61
55
  signing_key_filename: config.client_key,
@@ -63,13 +57,9 @@ module ChefDK
63
57
  end
64
58
 
65
59
  def policy_data
66
- @policy_data ||= FFI_Yajl::Parser.parse(IO.read(lockfile_path))
60
+ @policy_data ||= FFI_Yajl::Parser.parse(IO.read(policyfile_lock_expanded_path))
67
61
  rescue => error
68
- raise PolicyfilePushError.new("Error reading lockfile #{lockfile_path}", error)
69
- end
70
-
71
- def storage_config
72
- @storage_config ||= ChefDK::Policyfile::StorageConfig.new.use_policyfile_lock(lockfile_path)
62
+ raise PolicyfilePushError.new("Error reading lockfile #{policyfile_lock_expanded_path}", error)
73
63
  end
74
64
 
75
65
  def uploader
@@ -77,8 +67,8 @@ module ChefDK
77
67
  end
78
68
 
79
69
  def run
80
- unless File.exist?(lockfile_path)
81
- raise LockfileNotFound, "No lockfile at #{lockfile_path} - you need to run `install` before `push`"
70
+ unless File.exist?(policyfile_lock_expanded_path)
71
+ raise LockfileNotFound, "No lockfile at #{policyfile_lock_expanded_path} - you need to run `install` before `push`"
82
72
  end
83
73
 
84
74
  validate_lockfile
@@ -100,7 +90,7 @@ module ChefDK
100
90
  end
101
91
 
102
92
  def write_updated_lockfile
103
- File.open(lockfile_path, "w+") do |f|
93
+ with_file(policyfile_lock_expanded_path) do |f|
104
94
  f.print(FFI_Yajl::Encoder.encode(policyfile_lock.to_lock, pretty: true ))
105
95
  end
106
96
  end
@@ -0,0 +1,25 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2014 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef-dk/service_exception_inspectors/base'
19
+ require 'chef-dk/service_exception_inspectors/http'
20
+
21
+ module ChefDK
22
+ module ServiceExceptionInspectors
23
+ end
24
+ end
25
+
@@ -0,0 +1,40 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2014 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ module ChefDK
19
+ module ServiceExceptionInspectors
20
+
21
+ class Base
22
+
23
+ attr_reader :exception
24
+
25
+ def initialize(exception)
26
+ @exception = exception
27
+ end
28
+
29
+ def message
30
+ exception.message
31
+ end
32
+
33
+ def extended_error_info
34
+ ""
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+
@@ -0,0 +1,121 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2014 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'ffi_yajl'
19
+
20
+ module ChefDK
21
+ module ServiceExceptionInspectors
22
+ class HTTP
23
+
24
+ attr_reader :exception
25
+
26
+ def initialize(exception)
27
+ @exception = exception
28
+ end
29
+
30
+ def message
31
+ "HTTP #{code} #{response_message}: " + parsed_response_body
32
+ end
33
+
34
+ def extended_error_info
35
+ <<-END
36
+ --- REQUEST DATA ----
37
+ #{http_method} #{uri}
38
+ #{request_headers}
39
+ #{req_body}
40
+
41
+ --- RESPONSE DATA ---
42
+ #{code} #{response_message}
43
+ #{response_headers}
44
+
45
+ #{response_body}
46
+
47
+ END
48
+ end
49
+
50
+ def response
51
+ exception.response
52
+ end
53
+
54
+ def code
55
+ response.code
56
+ end
57
+
58
+ def response_message
59
+ response.message
60
+ end
61
+
62
+ def response_body
63
+ response.body
64
+ end
65
+
66
+ def parsed_response_body
67
+ if response_body && !response_body.empty?
68
+ attempt_error_message_extract
69
+ else
70
+ "(No explanation provided by server)"
71
+ end
72
+ end
73
+
74
+ def attempt_error_message_extract
75
+ error_body = FFI_Yajl::Parser.parse(response_body)
76
+ if error_body.respond_to?(:key?) && error_body.key?("error")
77
+ Array(error_body["error"]).join(", ")
78
+ else
79
+ error_body.to_s
80
+ end
81
+ rescue
82
+ response_body
83
+ end
84
+
85
+ def response_headers
86
+ headers_s = ""
87
+ response.each_header do |key, value|
88
+ headers_s << key << ": " << value << "\n"
89
+ end
90
+ headers_s
91
+ end
92
+
93
+ def request
94
+ exception.chef_rest_request
95
+ end
96
+
97
+ def uri
98
+ request.uri.to_s + request.path.to_s
99
+ end
100
+
101
+ def http_method
102
+ request.method
103
+ end
104
+
105
+ def request_headers
106
+ headers_s = ""
107
+ request.each_header do |key, value|
108
+ headers_s << key << ": " << value << "\n"
109
+ end
110
+ headers_s
111
+ end
112
+
113
+ def req_body
114
+ request.body
115
+ end
116
+
117
+ end
118
+ end
119
+ end
120
+
121
+